diff --git a/.gitmodules b/.gitmodules index e22d576279042..c60a0dd2c7c43 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,7 +34,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/13.0-2021-08-08 + branch = rustc/13.0-2021-09-30 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/Cargo.lock b/Cargo.lock index 6b3a714920bb4..39de549c7bd15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -360,7 +360,7 @@ version = "0.1.0" dependencies = [ "directories", "rustc-workspace-hack", - "rustc_version", + "rustc_version 0.3.3", "serde", "serde_json", "vergen", @@ -1092,19 +1092,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "env_logger" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd" -dependencies = [ - "atty", - "humantime 2.0.1", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.9.0" @@ -1660,7 +1647,7 @@ checksum = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f" dependencies = [ "bitmaps", "rand_core 0.5.1", - "rand_xoshiro", + "rand_xoshiro 0.4.0", "sized-chunks", "typenum", "version_check", @@ -1892,9 +1879,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.99" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" dependencies = [ "rustc-std-workspace-core", ] @@ -2250,15 +2237,15 @@ version = "0.1.0" dependencies = [ "colored", "compiletest_rs", - "env_logger 0.8.1", + "env_logger 0.9.0", "getrandom 0.2.0", "hex 0.4.2", "libc", "log", "measureme", - "rand 0.8.3", + "rand 0.8.4", "rustc-workspace-hack", - "rustc_version", + "rustc_version 0.4.0", "shell-escape", "smallvec", ] @@ -2852,9 +2839,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha 0.3.0", @@ -2945,6 +2932,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.2", +] + [[package]] name = "rayon" version = "1.3.1" @@ -3675,6 +3671,7 @@ dependencies = [ "rustc_llvm", "rustc_metadata", "rustc_middle", + "rustc_query_system", "rustc_serialize", "rustc_session", "rustc_span", @@ -3706,7 +3703,9 @@ dependencies = [ "rustc_incremental", "rustc_index", "rustc_macros", + "rustc_metadata", "rustc_middle", + "rustc_query_system", "rustc_serialize", "rustc_session", "rustc_span", @@ -3734,6 +3733,7 @@ dependencies = [ "rustc_macros", "rustc_middle", "rustc_mir_dataflow", + "rustc_query_system", "rustc_session", "rustc_span", "rustc_target", @@ -4086,6 +4086,8 @@ dependencies = [ "either", "gsgdt", "polonius-engine", + "rand 0.8.4", + "rand_xoshiro 0.6.0", "rustc-rayon-core", "rustc_apfloat", "rustc_arena", @@ -4166,6 +4168,7 @@ dependencies = [ "rustc_index", "rustc_middle", "rustc_mir_dataflow", + "rustc_query_system", "rustc_serialize", "rustc_session", "rustc_span", @@ -4296,13 +4299,17 @@ dependencies = [ "parking_lot", "rustc-rayon-core", "rustc_arena", + "rustc_ast", "rustc_data_structures", "rustc_errors", + "rustc_feature", + "rustc_hir", "rustc_index", "rustc_macros", "rustc_serialize", "rustc_session", "rustc_span", + "rustc_target", "smallvec", "tracing", ] @@ -4370,6 +4377,7 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_fs_util", + "rustc_hir", "rustc_lint_defs", "rustc_macros", "rustc_serialize", @@ -4405,6 +4413,7 @@ dependencies = [ "rustc_data_structures", "rustc_hir", "rustc_middle", + "rustc_query_system", "rustc_session", "rustc_span", "rustc_target", @@ -4445,9 +4454,11 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", + "rustc_lint_defs", "rustc_macros", "rustc_middle", "rustc_parse_format", + "rustc_query_system", "rustc_session", "rustc_span", "rustc_target", @@ -4536,6 +4547,15 @@ dependencies = [ "semver 0.11.0", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.3", +] + [[package]] name = "rustdoc" version = "0.0.0" @@ -4896,9 +4916,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "snap" @@ -5096,7 +5116,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.3", + "rand 0.8.4", "redox_syscall", "remove_dir_all", "winapi", @@ -5345,9 +5365,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.25" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -5357,9 +5377,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.13" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a9bd1db7706f2373a190b0d067146caa39350c486f3d455b0e33b431f94c07" +checksum = "c4f915eb6abf914599c200260efced9203504c4c37380af10cdf3b7d36970650" dependencies = [ "proc-macro2", "quote", @@ -5368,9 +5388,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" dependencies = [ "lazy_static", ] diff --git a/Cargo.toml b/Cargo.toml index 3822da2ccd5e4..ce7073886c20e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ members = [ exclude = [ "build", "compiler/rustc_codegen_cranelift", + "compiler/rustc_codegen_gcc", "src/test/rustdoc-gui", # HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`. "obj", diff --git a/RELEASES.md b/RELEASES.md index c0851a1506e13..ef1377a4a32df 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,188 @@ +Rust 1.56.0 (2021-10-21) +======================== + +Language +-------- + +- [The 2021 Edition is now stable.][rust#88100] + See [the edition guide][rust-2021-edition-guide] for more details. +- [You can now specify explicit discriminant values on any Rust enum.][rust#86860] +- [The pattern in `binding @ pattern` can now also introduce new bindings.][rust#85305] +- [Union field access is permitted in `const fn`.][rust#85769] + +[rust-2021-edition-guide]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/index.html + +Compiler +-------- + +- [Upgrade to LLVM 13.][rust#87570] +- [Support memory, address, and thread sanitizers on aarch64-unknown-freebsd.][rust#88023] +- [Allow specifying a deployment target version for all iOS targets][rust#87699] +- [Warnings can be forced on with `--force-warn`.][rust#87472] + This feature is primarily intended for usage by `cargo fix`, rather than end users. +- [Promote `aarch64-apple-ios-sim` to Tier 2\*.][rust#87760] +- [Add `powerpc-unknown-freebsd` at Tier 3\*.][rust#87370] + +\* Refer to Rust's [platform support page][platform-support-doc] for more +information on Rust's tiered platform support. + +Libraries +--------- + +- [Allow writing of incomplete UTF-8 sequences via stdout/stderr on Windows.][rust#83342] + The Windows console still requires valid Unicode, but this change allows + splitting a UTF-8 character across multiple write calls. This allows, for + instance, programs that just read and write data buffers (e.g. copying a file + to stdout) without regard for Unicode or character boundaries. +- [Prefer `AtomicU{64,128}` over Mutex for Instant backsliding protection.][rust#83093] + For this use case, atomics scale much better under contention. +- [Implement `Extend<(A, B)>` for `(Extend, Extend)`][rust#85835] +- [impl Default, Copy, Clone for std::io::Sink and std::io::Empty][rust#86744] +- [`impl From<[(K, V); N]>` for all collections.][rust#84111] +- [Remove `P: Unpin` bound on impl Future for Pin.][rust#81363] +- [Treat invalid environment variable names as non-existent.][rust#86183] + Previously, the environment functions would panic if given a variable name + with an internal null character or equal sign (`=`). Now, these functions will + just treat such names as non-existent variables, since the OS cannot represent + the existence of a variable with such a name. + +Stabilised APIs +--------------- + +- [`std::os::unix::fs::chroot`] +- [`Iterator::intersperse`] +- [`Iterator::intersperse_with`] +- [`UnsafeCell::raw_get`] +- [`BufWriter::into_parts`] +- [`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`] + These APIs were previously stable in `std`, but are now also available in `core`. +- [`Vec::shrink_to`] +- [`String::shrink_to`] +- [`OsString::shrink_to`] +- [`PathBuf::shrink_to`] +- [`BinaryHeap::shrink_to`] +- [`VecDeque::shrink_to`] +- [`HashMap::shrink_to`] +- [`HashSet::shrink_to`] +- [`task::ready!`] + +These APIs are now usable in const contexts: + +- [`std::mem::transmute`] +- [`[T]::first`][`slice::first`] +- [`[T]::split_first`][`slice::split_first`] +- [`[T]::last`][`slice::last`] +- [`[T]::split_last`][`slice::split_last`] + +Cargo +----- + +- [Cargo supports specifying a minimum supported Rust version in Cargo.toml.][`rust-version`] + This has no effect at present on dependency version selection. + We encourage crates to specify their minimum supported Rust version, and we encourage CI systems + that support Rust code to include a crate's specified minimum version in the text matrix for that + crate by default. + +Compatibility notes +------------------- + +- [Update to new argument parsing rules on Windows.][rust#87580] + This adjusts Rust's standard library to match the behavior of the standard + libraries for C/C++. The rules have changed slightly over time, and this PR + brings us to the latest set of rules (changed in 2008). +- [Disallow the aapcs calling convention on aarch64][rust#88399] + This was already not supported by LLVM; this change surfaces this lack of + support with a better error message. +- [Make `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` warn by default][rust#87385] +- [Warn when an escaped newline skips multiple lines.][rust#87671] +- [Calls to `libc::getpid` / `std::process::id` from `Command::pre_exec` + may return different values on glibc <= 2.24.][rust#81825] + Rust now invokes the `clone3` system call directly, when available, to use new functionality + available via that system call. Older versions of glibc cache the result of `getpid`, and only + update that cache when calling glibc's clone/fork functions, so a direct system call bypasses + that cache update. glibc 2.25 and newer no longer cache `getpid` for exactly this reason. + +Internal changes +---------------- +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc +and related tools. + +- [LLVM is compiled with PGO in published x86_64-unknown-linux-gnu artifacts.][rust#88069] + This improves the performance of most Rust builds. +- [Unify representation of macros in internal data structures.][rust#88019] + This change fixes a host of bugs with the handling of macros by the compiler, + as well as rustdoc. + +[`std::os::unix::fs::chroot`]: https://doc.rust-lang.org/stable/std/os/unix/fs/fn.chroot.html +[`Iterator::intersperse`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse +[`Iterator::intersperse_with`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse +[`UnsafeCell::raw_get`]: https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.raw_get +[`BufWriter::into_parts`]: https://doc.rust-lang.org/stable/std/io/struct.BufWriter.html#method.into_parts +[`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`]: https://github.com/rust-lang/rust/pull/84662 +[`Vec::shrink_to`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.shrink_to +[`String::shrink_to`]: https://doc.rust-lang.org/stable/std/string/struct.String.html#method.shrink_to +[`OsString::shrink_to`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.shrink_to +[`PathBuf::shrink_to`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.shrink_to +[`BinaryHeap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.shrink_to +[`VecDeque::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.shrink_to +[`HashMap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.shrink_to +[`HashSet::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_set/struct.HashSet.html#method.shrink_to +[`task::ready!`]: https://doc.rust-lang.org/stable/std/task/macro.ready.html +[`std::mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html +[`slice::first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first +[`slice::split_first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first +[`slice::last`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.last +[`slice::split_last`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_last +[`rust-version`]: https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-rust-version-field +[rust#87671]: https://github.com/rust-lang/rust/pull/87671 +[rust#86183]: https://github.com/rust-lang/rust/pull/86183 +[rust#87385]: https://github.com/rust-lang/rust/pull/87385 +[rust#88100]: https://github.com/rust-lang/rust/pull/88100 +[rust#86860]: https://github.com/rust-lang/rust/pull/86860 +[rust#84039]: https://github.com/rust-lang/rust/pull/84039 +[rust#86492]: https://github.com/rust-lang/rust/pull/86492 +[rust#88363]: https://github.com/rust-lang/rust/pull/88363 +[rust#85305]: https://github.com/rust-lang/rust/pull/85305 +[rust#87832]: https://github.com/rust-lang/rust/pull/87832 +[rust#88069]: https://github.com/rust-lang/rust/pull/88069 +[rust#87472]: https://github.com/rust-lang/rust/pull/87472 +[rust#87699]: https://github.com/rust-lang/rust/pull/87699 +[rust#87570]: https://github.com/rust-lang/rust/pull/87570 +[rust#88023]: https://github.com/rust-lang/rust/pull/88023 +[rust#87760]: https://github.com/rust-lang/rust/pull/87760 +[rust#87370]: https://github.com/rust-lang/rust/pull/87370 +[rust#87580]: https://github.com/rust-lang/rust/pull/87580 +[rust#83342]: https://github.com/rust-lang/rust/pull/83342 +[rust#83093]: https://github.com/rust-lang/rust/pull/83093 +[rust#88177]: https://github.com/rust-lang/rust/pull/88177 +[rust#88548]: https://github.com/rust-lang/rust/pull/88548 +[rust#88551]: https://github.com/rust-lang/rust/pull/88551 +[rust#88299]: https://github.com/rust-lang/rust/pull/88299 +[rust#88220]: https://github.com/rust-lang/rust/pull/88220 +[rust#85835]: https://github.com/rust-lang/rust/pull/85835 +[rust#86879]: https://github.com/rust-lang/rust/pull/86879 +[rust#86744]: https://github.com/rust-lang/rust/pull/86744 +[rust#84662]: https://github.com/rust-lang/rust/pull/84662 +[rust#86593]: https://github.com/rust-lang/rust/pull/86593 +[rust#81050]: https://github.com/rust-lang/rust/pull/81050 +[rust#81363]: https://github.com/rust-lang/rust/pull/81363 +[rust#84111]: https://github.com/rust-lang/rust/pull/84111 +[rust#85769]: https://github.com/rust-lang/rust/pull/85769#issuecomment-854363720 +[rust#88490]: https://github.com/rust-lang/rust/pull/88490 +[rust#88269]: https://github.com/rust-lang/rust/pull/88269 +[rust#84176]: https://github.com/rust-lang/rust/pull/84176 +[rust#88399]: https://github.com/rust-lang/rust/pull/88399 +[rust#88227]: https://github.com/rust-lang/rust/pull/88227 +[rust#88200]: https://github.com/rust-lang/rust/pull/88200 +[rust#82776]: https://github.com/rust-lang/rust/pull/82776 +[rust#88077]: https://github.com/rust-lang/rust/pull/88077 +[rust#87728]: https://github.com/rust-lang/rust/pull/87728 +[rust#87050]: https://github.com/rust-lang/rust/pull/87050 +[rust#87619]: https://github.com/rust-lang/rust/pull/87619 +[rust#81825]: https://github.com/rust-lang/rust/pull/81825#issuecomment-808406918 +[rust#88019]: https://github.com/rust-lang/rust/pull/88019 + Version 1.55.0 (2021-09-09) ============================ @@ -4985,7 +5170,7 @@ Libraries - [Upgrade to Unicode 10.0.0][42999] - [Reimplemented `{f32, f64}::{min, max}` in Rust instead of using CMath.][42430] - [Skip the main thread's manual stack guard on Linux][43072] -- [Iterator::nth for `ops::{Range, RangeFrom}` is now done in O(1) time][43077] +- [Iterator::nth for `ops::{Range, RangeFrom}` is now done in *O*(1) time][43077] - [`#[repr(align(N))]` attribute max number is now 2^31 - 1.][43097] This was previously 2^15. - [`{OsStr, Path}::Display` now avoids allocations where possible][42613] @@ -8288,7 +8473,7 @@ Libraries algorithm][s]. * [`std::io::copy` allows `?Sized` arguments][cc]. * The `Windows`, `Chunks`, and `ChunksMut` iterators over slices all - [override `count`, `nth` and `last` with an O(1) + [override `count`, `nth` and `last` with an *O*(1) implementation][it]. * [`Default` is implemented for arrays up to `[T; 32]`][d]. * [`IntoRawFd` has been added to the Unix-specific prelude, @@ -8810,7 +8995,7 @@ Libraries * The `Default` implementation for `Arc` [no longer requires `Sync + Send`][arc]. * [The `Iterator` methods `count`, `nth`, and `last` have been - overridden for slices to have O(1) performance instead of O(n)][si]. + overridden for slices to have *O*(1) performance instead of *O*(*n*)][si]. * Incorrect handling of paths on Windows has been improved in both the compiler and the standard library. * [`AtomicPtr` gained a `Default` implementation][ap]. diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index c27ab810a4c60..e2424e7d7ad90 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1211,6 +1211,8 @@ impl Expr { } } + ExprKind::Underscore => TyKind::Infer, + // This expression doesn't look like a type syntactically. _ => return None, }; diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 3a65ffe41ae87..db066d7c6a519 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -295,6 +295,7 @@ impl TokenKind { match *self { Comma => Some(vec![Dot, Lt, Semi]), Semi => Some(vec![Colon, Comma]), + FatArrow => Some(vec![Eq, RArrow]), _ => None, } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a6ea4aa8923cf..6027027428eee 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -100,10 +100,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::If(ref cond, ref then, ref else_opt) => { self.lower_expr_if(cond, then, else_opt.as_deref()) } - ExprKind::While(ref cond, ref body, opt_label) => self - .with_loop_scope(e.id, |this| { - this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label) - }), + ExprKind::While(ref cond, ref body, opt_label) => { + self.with_loop_scope(e.id, |this| { + let span = + this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None); + this.lower_expr_while_in_loop_scope(span, cond, body, opt_label) + }) + } ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| { hir::ExprKind::Loop( this.lower_block(body, false), diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9f879494d7374..ea9eb0cf2742b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1328,32 +1328,45 @@ impl<'hir> LoweringContext<'_, 'hir> { // keep track of the Span info. Now, `add_implicitly_sized` in `AstConv` checks both param bounds and // where clauses for `?Sized`. for pred in &generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(ref bound_pred) = *pred { - 'next_bound: for bound in &bound_pred.bounds { - if let GenericBound::Trait(_, TraitBoundModifier::Maybe) = *bound { - // Check if the where clause type is a plain type parameter. - match self - .resolver - .get_partial_res(bound_pred.bounded_ty.id) - .map(|d| (d.base_res(), d.unresolved_segments())) - { - Some((Res::Def(DefKind::TyParam, def_id), 0)) - if bound_pred.bound_generic_params.is_empty() => - { - for param in &generics.params { - if def_id == self.resolver.local_def_id(param.id).to_def_id() { - continue 'next_bound; - } - } - } - _ => {} - } - self.diagnostic().span_err( - bound_pred.bounded_ty.span, - "`?Trait` bounds are only permitted at the \ - point where a type parameter is declared", - ); + let bound_pred = match *pred { + WherePredicate::BoundPredicate(ref bound_pred) => bound_pred, + _ => continue, + }; + let compute_is_param = || { + // Check if the where clause type is a plain type parameter. + match self + .resolver + .get_partial_res(bound_pred.bounded_ty.id) + .map(|d| (d.base_res(), d.unresolved_segments())) + { + Some((Res::Def(DefKind::TyParam, def_id), 0)) + if bound_pred.bound_generic_params.is_empty() => + { + generics + .params + .iter() + .find(|p| def_id == self.resolver.local_def_id(p.id).to_def_id()) + .is_some() } + // Either the `bounded_ty` is not a plain type parameter, or + // it's not found in the generic type parameters list. + _ => false, + } + }; + // We only need to compute this once per `WherePredicate`, but don't + // need to compute this at all unless there is a Maybe bound. + let mut is_param: Option = None; + for bound in &bound_pred.bounds { + if !matches!(*bound, GenericBound::Trait(_, TraitBoundModifier::Maybe)) { + continue; + } + let is_param = *is_param.get_or_insert_with(compute_is_param); + if !is_param { + self.diagnostic().span_err( + bound.span(), + "`?Trait` bounds are only permitted at the \ + point where a type parameter is declared", + ); } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3c75089a760f3..245199e375113 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -166,7 +166,7 @@ pub trait ResolverAstLowering { fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option>; /// Obtains resolution for a `NodeId` with a single resolution. - fn get_partial_res(&mut self, id: NodeId) -> Option; + fn get_partial_res(&self, id: NodeId) -> Option; /// Obtains per-namespace resolutions for `use` statement with the given `NodeId`. fn get_import_res(&mut self, id: NodeId) -> PerNS>>; diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 24108f779c818..968e9fa3e2480 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -590,7 +590,7 @@ impl<'a> AstValidator<'a> { ) .span_label(self.current_extern_span(), "in this `extern` block") .note(&format!( - "This limitation may be lifted in the future; see issue #{} for more information", + "this limitation may be lifted in the future; see issue #{} for more information", n, n, )) .emit(); @@ -683,31 +683,53 @@ impl<'a> AstValidator<'a> { } } + fn emit_e0568(&self, span: Span, ident_span: Span) { + struct_span_err!( + self.session, + span, + E0568, + "auto traits cannot have super traits or lifetime bounds" + ) + .span_label(ident_span, "auto trait cannot have super traits or lifetime bounds") + .span_suggestion( + span, + "remove the super traits or lifetime bounds", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) { - if let [first @ last] | [first, .., last] = &bounds[..] { - let span = first.span().to(last.span()); - struct_span_err!(self.session, span, E0568, "auto traits cannot have super traits") - .span_label(ident_span, "auto trait cannot have super traits") - .span_suggestion( - span, - "remove the super traits", - String::new(), - Applicability::MachineApplicable, - ) - .emit(); + if let [.., last] = &bounds[..] { + let span = ident_span.shrink_to_hi().to(last.span()); + self.emit_e0568(span, ident_span); + } + } + + fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) { + if !where_clause.predicates.is_empty() { + self.emit_e0568(where_clause.span, ident_span); } } fn deny_items(&self, trait_items: &[P], ident_span: Span) { if !trait_items.is_empty() { let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect(); + let total_span = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span); struct_span_err!( self.session, spans, E0380, - "auto traits cannot have methods or associated items" + "auto traits cannot have associated items" + ) + .span_suggestion( + total_span, + "remove these associated items", + String::new(), + Applicability::MachineApplicable, ) - .span_label(ident_span, "auto trait cannot have items") + .span_label(ident_span, "auto trait cannot have associated items") .emit(); } } @@ -1184,6 +1206,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Auto traits cannot have generics, super traits nor contain items. self.deny_generic_params(generics, item.ident.span); self.deny_super_traits(bounds, item.ident.span); + self.deny_where_clause(&generics.where_clause, item.ident.span); self.deny_items(trait_items, item.ident.span); } self.no_questions_in_bounds(bounds, "supertraits", true); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 06e9d9ed32933..bce5cd8174d08 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -279,6 +279,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_doc!( cfg => doc_cfg + cfg_hide => doc_cfg_hide masked => doc_masked notable_trait => doc_notable_trait keyword => doc_keyword diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 0ab452fb42dc6..8d7f2b65c5a82 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -66,7 +66,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { } } -#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)] +#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum InlineAttr { None, Hint, @@ -74,13 +74,13 @@ pub enum InlineAttr { Never, } -#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)] pub enum InstructionSetAttr { ArmA32, ArmT32, } -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub enum OptimizeAttr { None, Speed, diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 4333038a6f936..97daad201d959 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -31,7 +31,7 @@ pub fn get_body_with_borrowck_facts<'tcx>( def: ty::WithOptConstParam, ) -> BodyWithBorrowckFacts<'tcx> { let (input_body, promoted) = tcx.mir_promoted(def); - tcx.infer_ctxt().enter(|infcx| { + tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| { let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexVec<_, _> = &promoted.borrow(); *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap() diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 76e779bfec608..15309ccd8df27 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op; use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _}; -use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span}; +use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; use std::fmt; use std::rc::Rc; @@ -45,13 +45,12 @@ impl UniverseInfo<'tcx> { mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, placeholder: ty::PlaceholderRegion, error_element: RegionElement, - span: Span, + cause: ObligationCause<'tcx>, ) { match self.0 { UniverseInfoInner::RelateTys { expected, found } => { - let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id()); let err = mbcx.infcx.report_mismatched_types( - &ObligationCause::misc(span, body_id), + &cause, expected, found, TypeError::RegionsPlaceholderMismatch, @@ -59,7 +58,7 @@ impl UniverseInfo<'tcx> { err.buffer(&mut mbcx.errors_buffer); } UniverseInfoInner::TypeOp(ref type_op_info) => { - type_op_info.report_error(mbcx, placeholder, error_element, span); + type_op_info.report_error(mbcx, placeholder, error_element, cause); } UniverseInfoInner::Other => { // FIXME: This error message isn't great, but it doesn't show @@ -68,7 +67,7 @@ impl UniverseInfo<'tcx> { mbcx.infcx .tcx .sess - .struct_span_err(span, "higher-ranked subtype error") + .struct_span_err(cause.span, "higher-ranked subtype error") .buffer(&mut mbcx.errors_buffer); } } @@ -130,7 +129,7 @@ trait TypeOpInfo<'tcx> { fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option>; @@ -140,7 +139,7 @@ trait TypeOpInfo<'tcx> { mbcx: &mut MirBorrowckCtxt<'_, 'tcx>, placeholder: ty::PlaceholderRegion, error_element: RegionElement, - span: Span, + cause: ObligationCause<'tcx>, ) { let tcx = mbcx.infcx.tcx; let base_universe = self.base_universe(); @@ -150,7 +149,7 @@ trait TypeOpInfo<'tcx> { { adjusted } else { - self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer); + self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer); return; }; @@ -175,7 +174,8 @@ trait TypeOpInfo<'tcx> { debug!(?placeholder_region); - let nice_error = self.nice_error(tcx, span, placeholder_region, error_region); + let span = cause.span; + let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region); if let Some(nice_error) = nice_error { nice_error.buffer(&mut mbcx.errors_buffer); @@ -205,15 +205,24 @@ impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> { fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span)); - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause); + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) } } @@ -239,32 +248,41 @@ where fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - - let mut selcx = SelectionContext::new(infcx); - - // FIXME(lqd): Unify and de-duplicate the following with the actual - // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the - // `ObligationCause`. The normalization results are currently different between - // `AtExt::normalize` used in the query and `normalize` called below: the former fails - // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check - // after #85499 lands to see if its fixes have erased this difference. - let (param_env, value) = key.into_parts(); - let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( - &mut selcx, - param_env, - ObligationCause::dummy_with_span(span), - value.value, - ); - fulfill_cx.register_predicate_obligations(infcx, obligations); - - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + + let mut selcx = SelectionContext::new(infcx); + + // FIXME(lqd): Unify and de-duplicate the following with the actual + // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the + // `ObligationCause`. The normalization results are currently different between + // `AtExt::normalize` used in the query and `normalize` called below: the former fails + // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check + // after #85499 lands to see if its fixes have erased this difference. + let (param_env, value) = key.into_parts(); + let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize( + &mut selcx, + param_env, + cause, + value.value, + ); + fulfill_cx.register_predicate_obligations(infcx, obligations); + + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) } } @@ -287,18 +305,29 @@ impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> { fn nice_error( &self, tcx: TyCtxt<'tcx>, - span: Span, + cause: ObligationCause<'tcx>, placeholder_region: ty::Region<'tcx>, error_region: Option>, ) -> Option> { - tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| { - let mut fulfill_cx = >::new(tcx); - type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?; - try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region) - }) + tcx.infer_ctxt().enter_with_canonical( + cause.span, + &self.canonical_query, + |ref infcx, key, _| { + let mut fulfill_cx = >::new(tcx); + type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)) + .ok()?; + try_extract_error_from_fulfill_cx( + fulfill_cx, + infcx, + placeholder_region, + error_region, + ) + }, + ) } } +#[instrument(skip(fulfill_cx, infcx), level = "debug")] fn try_extract_error_from_fulfill_cx<'tcx>( mut fulfill_cx: Box + 'tcx>, infcx: &InferCtxt<'_, 'tcx>, @@ -313,7 +342,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new); let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| { - debug!(?region_constraints); + debug!("{:#?}", region_constraints); region_constraints.constraints.iter().find_map(|(constraint, cause)| { match *constraint { Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => { @@ -328,7 +357,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( }) })?; - debug!(?sub_region, ?cause); + debug!(?sub_region, "cause = {:#?}", cause); let nice_error = match (error_region, sub_region) { (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new( infcx, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f4cbbb60b053a..37398894a202b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -10,8 +10,7 @@ use rustc_middle::mir::{ ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; -use rustc_mir_dataflow::drop_flag_effects; -use rustc_mir_dataflow::move_paths::{MoveOutIndex, MovePathIndex}; +use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::sym; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; @@ -1531,25 +1530,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } + let mut mpis = vec![mpi]; + let move_paths = &self.move_data.move_paths; + mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi)); + let mut stack = Vec::new(); - stack.extend(predecessor_locations(self.body, location).map(|predecessor| { - let is_back_edge = location.dominates(predecessor, &self.dominators); - (predecessor, is_back_edge) - })); + let mut back_edge_stack = Vec::new(); + + predecessor_locations(self.body, location).for_each(|predecessor| { + if location.dominates(predecessor, &self.dominators) { + back_edge_stack.push(predecessor) + } else { + stack.push(predecessor); + } + }); + + let mut reached_start = false; + + /* Check if the mpi is initialized as an argument */ + let mut is_argument = false; + for arg in self.body.args_iter() { + let path = self.move_data.rev_lookup.find_local(arg); + if mpis.contains(&path) { + is_argument = true; + } + } let mut visited = FxHashSet::default(); let mut move_locations = FxHashSet::default(); let mut reinits = vec![]; let mut result = vec![]; - 'dfs: while let Some((location, is_back_edge)) = stack.pop() { + let mut dfs_iter = |result: &mut Vec, location: Location, is_back_edge: bool| { debug!( "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})", location, is_back_edge ); if !visited.insert(location) { - continue; + return true; } // check for moves @@ -1568,10 +1587,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // worry about the other case: that is, if there is a move of a.b.c, it is already // marked as a move of a.b and a as well, so we will generate the correct errors // there. - let mut mpis = vec![mpi]; - let move_paths = &self.move_data.move_paths; - mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi)); - for moi in &self.move_data.loc_map[location] { debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); let path = self.move_data.moves[*moi].path; @@ -1599,33 +1614,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Because we stop the DFS here, we only highlight `let c = a`, // and not `let b = a`. We will of course also report an error at // `let c = a` which highlights `let b = a` as the move. - continue 'dfs; + return true; } } } // check for inits let mut any_match = false; - drop_flag_effects::for_location_inits( - self.infcx.tcx, - &self.body, - self.move_data, - location, - |m| { - if m == mpi { - any_match = true; + for ii in &self.move_data.init_loc_map[location] { + let init = self.move_data.inits[*ii]; + match init.kind { + InitKind::Deep | InitKind::NonPanicPathOnly => { + if mpis.contains(&init.path) { + any_match = true; + } } - }, - ); + InitKind::Shallow => { + if mpi == init.path { + any_match = true; + } + } + } + } if any_match { reinits.push(location); - continue 'dfs; + return true; } + return false; + }; - stack.extend(predecessor_locations(self.body, location).map(|predecessor| { - let back_edge = location.dominates(predecessor, &self.dominators); - (predecessor, is_back_edge || back_edge) - })); + while let Some(location) = stack.pop() { + if dfs_iter(&mut result, location, false) { + continue; + } + + let mut has_predecessor = false; + predecessor_locations(self.body, location).for_each(|predecessor| { + if location.dominates(predecessor, &self.dominators) { + back_edge_stack.push(predecessor) + } else { + stack.push(predecessor); + } + has_predecessor = true; + }); + + if !has_predecessor { + reached_start = true; + } + } + if (is_argument || !reached_start) && result.is_empty() { + /* Process back edges (moves in future loop iterations) only if + the move path is definitely initialized upon loop entry, + to avoid spurious "in previous iteration" errors. + During DFS, if there's a path from the error back to the start + of the function with no intervening init or move, then the + move path may be uninitialized at loop entry. + */ + while let Some(location) = back_edge_stack.pop() { + if dfs_iter(&mut result, location, true) { + continue; + } + + predecessor_locations(self.body, location) + .for_each(|predecessor| back_edge_stack.push(predecessor)); + } } // Check if we can reach these reinits from a move location. diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 2d12a682e7ae6..d5de0801ac443 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -300,7 +300,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_region: RegionVid, outlived_region: RegionVid, ) -> (ConstraintCategory, bool, Span, Option) { - let BlameConstraint { category, from_closure, span, variance_info: _ } = + let BlameConstraint { category, from_closure, cause, variance_info: _ } = self.regioncx.best_blame_constraint( &self.body, borrow_region, @@ -310,7 +310,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let outlived_fr_name = self.give_region_a_name(outlived_region); - (category, from_closure, span, outlived_fr_name) + (category, from_closure, cause.span, outlived_fr_name) } /// Returns structured explanation for *why* the borrow contains the diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 50130dc2a27ed..a4df277a7b084 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -966,8 +966,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { _ => None, }); let is_option_or_result = parent_self_ty.map_or(false, |def_id| { - tcx.is_diagnostic_item(sym::option_type, def_id) - || tcx.is_diagnostic_item(sym::result_type, def_id) + tcx.is_diagnostic_item(sym::Option, def_id) + || tcx.is_diagnostic_item(sym::Result, def_id) }); FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result } }); diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index b23ce281bef24..855e6850b2efa 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -400,8 +400,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { | ty::Opaque(def_id, _) => def_id, _ => return err, }; - let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id); - let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id); + let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id); + let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id); if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) { err.span_suggestion_verbose( span.shrink_to_hi(), diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index 9de0c62f186c0..b15e55cd6675e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -171,9 +171,7 @@ impl OutlivesSuggestionBuilder { let outlived_fr_name = self.region_vid_to_name(mbcx, errci.outlived_fr); if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name) { - if let RegionNameSource::Static = outlived_fr_name.source { - diag.help(&format!("consider replacing `{}` with `'static`", fr_name)); - } else { + if !matches!(outlived_fr_name.source, RegionNameSource::Static) { diag.help(&format!( "consider adding the following bound: `{}: {}`", fr_name, outlived_fr_name diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 0761d63c66540..11cdbe84accb7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -13,6 +13,7 @@ use rustc_span::{BytePos, Span}; use crate::borrowck_errors; +use super::{OutlivesSuggestionBuilder, RegionName}; use crate::region_infer::BlameConstraint; use crate::{ nll::ConstraintDescription, @@ -21,8 +22,6 @@ use crate::{ MirBorrowckCtxt, }; -use super::{OutlivesSuggestionBuilder, RegionName}; - impl ConstraintDescription for ConstraintCategory { fn description(&self) -> &'static str { // Must end with a space. Allows for empty names to be provided. @@ -41,7 +40,8 @@ impl ConstraintDescription for ConstraintCategory { ConstraintCategory::OpaqueType => "opaque type ", ConstraintCategory::ClosureUpvar(_) => "closure capture ", ConstraintCategory::Usage => "this usage ", - ConstraintCategory::Boring + ConstraintCategory::Predicate(_) + | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation | ConstraintCategory::Internal => "", } @@ -217,7 +217,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let error_vid = self.regioncx.region_from_element(longer_fr, &error_element); // Find the code to blame for the fact that `longer_fr` outlives `error_fr`. - let (_, span) = self.regioncx.find_outlives_blame_span( + let (_, cause) = self.regioncx.find_outlives_blame_span( &self.body, longer_fr, NllRegionVariableOrigin::Placeholder(placeholder), @@ -227,7 +227,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let universe = placeholder.universe; let universe_info = self.regioncx.universe_info(universe); - universe_info.report_error(self, placeholder, error_element, span); + universe_info.report_error(self, placeholder, error_element, cause); } RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { @@ -275,15 +275,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) { debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr); - let BlameConstraint { category, span, variance_info, from_closure: _ } = + let BlameConstraint { category, cause, variance_info, from_closure: _ } = self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| { self.regioncx.provides_universal_region(r, fr, outlived_fr) }); - debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info); + debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info); // Check if we can use one of the "nice region errors". if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - let nice = NiceRegionError::new_from_span(self.infcx, span, o, f); + let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f); if let Some(diag) = nice.try_report_from_nll() { diag.buffer(&mut self.errors_buffer); return; @@ -306,7 +306,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fr_is_local, outlived_fr_is_local, category, - span, + span: cause.span, }; let mut diag = match (category, fr_is_local, outlived_fr_is_local) { @@ -498,6 +498,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { diag.span_label(*span, format!("`{}` escapes the {} body here", fr_name, escapes_from)); } + // Only show an extra note if we can find an 'error region' for both of the region + // variables. This avoids showing a noisy note that just mentions 'synthetic' regions + // that don't help the user understand the error. + if self.to_error_region(errci.fr).is_some() + && self.to_error_region(errci.outlived_fr).is_some() + { + let fr_region_name = self.give_region_a_name(errci.fr).unwrap(); + fr_region_name.highlight_region_name(&mut diag); + let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap(); + outlived_fr_region_name.highlight_region_name(&mut diag); + + diag.span_label( + *span, + format!( + "{}requires that `{}` must outlive `{}`", + category.description(), + fr_region_name, + outlived_fr_region_name, + ), + ); + } diag } diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 016fe0bb6dedf..efd34f4e0a58e 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -316,7 +316,8 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) - | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { + | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) + | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { self.consume_operand(location, operand) } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index b3b7d7e02ccef..e6260157d11a7 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,7 +2,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] -#![feature(const_panic)] +#![cfg_attr(bootstrap, feature(const_panic))] #![feature(crate_visibility_modifier)] #![feature(format_args_capture)] #![feature(in_band_lifetimes)] @@ -144,6 +144,7 @@ fn mir_borrowck<'tcx>( /// If `return_body_with_facts` is true, then return the body with non-erased /// region ids on which the borrow checking was performed together with Polonius /// facts. +#[instrument(skip(infcx, input_body, input_promoted), level = "debug")] fn do_mir_borrowck<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, input_body: &Body<'tcx>, @@ -152,7 +153,7 @@ fn do_mir_borrowck<'a, 'tcx>( ) -> (BorrowCheckResult<'tcx>, Option>>) { let def = input_body.source.with_opt_param().as_local().unwrap(); - debug!("do_mir_borrowck(def = {:?})", def); + debug!(?def); let tcx = infcx.tcx; let param_env = tcx.param_env(def.did); @@ -276,26 +277,26 @@ fn do_mir_borrowck<'a, 'tcx>( let regioncx = Rc::new(regioncx); - let flow_borrows = Borrows::new(tcx, &body, ®ioncx, &borrow_set) - .into_engine(tcx, &body) + let flow_borrows = Borrows::new(tcx, body, ®ioncx, &borrow_set) + .into_engine(tcx, body) .pass_name("borrowck") .iterate_to_fixpoint(); - let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe) - .into_engine(tcx, &body) + let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe) + .into_engine(tcx, body) .pass_name("borrowck") .iterate_to_fixpoint(); - let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe) - .into_engine(tcx, &body) + let flow_ever_inits = EverInitializedPlaces::new(tcx, body, &mdpe) + .into_engine(tcx, body) .pass_name("borrowck") .iterate_to_fixpoint(); - let movable_generator = match tcx.hir().get(id) { + let movable_generator = !matches!( + tcx.hir().get(id), Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., Some(hir::Movability::Static)), .. - }) => false, - _ => true, - }; + }) + ); for (idx, move_data_results) in promoted_errors { let promoted_body = &promoted[idx]; @@ -373,8 +374,8 @@ fn do_mir_borrowck<'a, 'tcx>( mbcx.report_move_errors(move_errors); rustc_mir_dataflow::visit_results( - &body, - traversal::reverse_postorder(&body).map(|(bb, _)| bb), + body, + traversal::reverse_postorder(body).map(|(bb, _)| bb), &results, &mut mbcx, ); @@ -1361,7 +1362,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | Rvalue::UnaryOp(_ /*un_op*/, ref operand) - | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => { + | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) + | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => { self.consume_operand(location, (operand, span), flow_state) } diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs index 2e2578df01146..f22d355e61344 100644 --- a/compiler/rustc_borrowck/src/member_constraints.rs +++ b/compiler/rustc_borrowck/src/member_constraints.rs @@ -144,7 +144,7 @@ impl MemberConstraintSet<'tcx, R> where R: Copy + Hash + Eq, { - crate fn all_indices(&self) -> impl Iterator { + crate fn all_indices(&self) -> impl Iterator + '_ { self.constraints.indices() } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 477b049b07596..e5924f9d08478 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -54,6 +54,7 @@ crate struct NllOutput<'tcx> { /// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal /// regions (e.g., region parameters) declared on the function. That set will need to be given to /// `compute_regions`. +#[instrument(skip(infcx, param_env, body, promoted), level = "debug")] pub(crate) fn replace_regions_in_mir<'cx, 'tcx>( infcx: &InferCtxt<'cx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -62,7 +63,7 @@ pub(crate) fn replace_regions_in_mir<'cx, 'tcx>( ) -> UniversalRegions<'tcx> { let def = body.source.with_opt_param().as_local().unwrap(); - debug!("replace_regions_in_mir(def={:?})", def); + debug!(?def); // Compute named region information. This also renumbers the inputs/outputs. let universal_regions = UniversalRegions::new(infcx, def, param_env); diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 128faab8d722e..734a5b4972bcc 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -5,7 +5,8 @@ use rustc_data_structures::binary_search_util; use rustc_data_structures::frozen::Frozen; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::scc::Sccs; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; +use rustc_hir::CRATE_HIR_ID; use rustc_index::vec::IndexVec; use rustc_infer::infer::canonical::QueryOutlivesConstraint; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound}; @@ -14,6 +15,8 @@ use rustc_middle::mir::{ Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint, }; +use rustc_middle::traits::ObligationCause; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; @@ -494,7 +497,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Returns an iterator over all the region indices. - pub fn regions(&self) -> impl Iterator { + pub fn regions(&self) -> impl Iterator + '_ { self.definitions.indices() } @@ -549,6 +552,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Performs region inference and report errors if we see any /// unsatisfiable constraints. If this is a closure, returns the /// region requirements to propagate to our creator, if any. + #[instrument(skip(self, infcx, body, polonius_output), level = "debug")] pub(super) fn solve( &mut self, infcx: &InferCtxt<'_, 'tcx>, @@ -604,10 +608,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// for each region variable until all the constraints are /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. + #[instrument(skip(self, _body), level = "debug")] fn propagate_constraints(&mut self, _body: &Body<'tcx>) { - debug!("propagate_constraints()"); - - debug!("propagate_constraints: constraints={:#?}", { + debug!("constraints={:#?}", { let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); constraints.sort(); constraints @@ -634,12 +637,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// computed, by unioning the values of its successors. /// Assumes that all successors have been computed already /// (which is assured by iterating over SCCs in dependency order). + #[instrument(skip(self), level = "debug")] fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex) { let constraint_sccs = self.constraint_sccs.clone(); // Walk each SCC `B` such that `A: B`... for &scc_b in constraint_sccs.successors(scc_a) { - debug!("propagate_constraint_sccs: scc_a = {:?} scc_b = {:?}", scc_a, scc_b); + debug!(?scc_b); // ...and add elements from `B` into `A`. One complication // arises because of universes: If `B` contains something @@ -660,11 +664,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i)); } - debug!( - "propagate_constraint_sccs: scc_a = {:?} has value {:?}", - scc_a, - self.scc_values.region_value_str(scc_a), - ); + debug!(value = ?self.scc_values.region_value_str(scc_a)); } /// Invoked for each `R0 member of [R1..Rn]` constraint. @@ -678,14 +678,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// is considered a *lower bound*. If possible, we will modify /// the constraint to set it equal to one of the option regions. /// If we make any changes, returns true, else false. + #[instrument(skip(self, member_constraint_index), level = "debug")] fn apply_member_constraint( &mut self, scc: ConstraintSccIndex, member_constraint_index: NllMemberConstraintIndex, choice_regions: &[ty::RegionVid], ) -> bool { - debug!("apply_member_constraint(scc={:?}, choice_regions={:#?})", scc, choice_regions,); - // Create a mutable vector of the options. We'll try to winnow // them down. let mut choice_regions: Vec = choice_regions.to_vec(); @@ -711,7 +710,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .universal_regions_outlived_by(scc) .all(|lb| self.universal_region_relations.outlives(o_r, lb)) }); - debug!("apply_member_constraint: after lb, choice_regions={:?}", choice_regions); + debug!(?choice_regions, "after lb"); // Now find all the *upper bounds* -- that is, each UB is a // free region that must outlive the member region `R0` (`UB: @@ -720,10 +719,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { let rev_scc_graph = self.reverse_scc_graph(); let universal_region_relations = &self.universal_region_relations; for ub in rev_scc_graph.upper_bounds(scc) { - debug!("apply_member_constraint: ub={:?}", ub); + debug!(?ub); choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r)); } - debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions); + debug!(?choice_regions, "after ub"); // If we ruled everything out, we're done. if choice_regions.is_empty() { @@ -732,7 +731,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // Otherwise, we need to find the minimum remaining choice, if // any, and take that. - debug!("apply_member_constraint: choice_regions remaining are {:#?}", choice_regions); + debug!("choice_regions remaining are {:#?}", choice_regions); let min = |r1: ty::RegionVid, r2: ty::RegionVid| -> Option { let r1_outlives_r2 = self.universal_region_relations.outlives(r1, r2); let r2_outlives_r1 = self.universal_region_relations.outlives(r2, r1); @@ -745,27 +744,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { }; let mut min_choice = choice_regions[0]; for &other_option in &choice_regions[1..] { - debug!( - "apply_member_constraint: min_choice={:?} other_option={:?}", - min_choice, other_option, - ); + debug!(?min_choice, ?other_option,); match min(min_choice, other_option) { Some(m) => min_choice = m, None => { - debug!( - "apply_member_constraint: {:?} and {:?} are incomparable; no min choice", - min_choice, other_option, - ); + debug!(?min_choice, ?other_option, "incomparable; no min choice",); return false; } } } let min_choice_scc = self.constraint_sccs.scc(min_choice); - debug!( - "apply_member_constraint: min_choice={:?} best_choice_scc={:?}", - min_choice, min_choice_scc, - ); + debug!(?min_choice, ?min_choice_scc); if self.scc_values.add_region(scc, min_choice_scc) { self.member_constraints_applied.push(AppliedMemberConstraint { member_region_scc: scc, @@ -1088,8 +1078,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// include the CFG anyhow. /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. + #[instrument(skip(self), level = "debug")] pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { - debug!("universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); + debug!(r = %self.region_value_str(r)); // Find the smallest universal region that contains all other // universal regions within `region`. @@ -1099,7 +1090,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { lub = self.universal_region_relations.postdom_upper_bound(lub, ur); } - debug!("universal_upper_bound: r={:?} lub={:?}", r, lub); + debug!(?lub); lub } @@ -1259,9 +1250,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Evaluate whether `sup_region: sub_region`. + #[instrument(skip(self), level = "debug")] fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { - debug!("eval_outlives({:?}: {:?})", sup_region, sub_region); - debug!( "eval_outlives: sup_region's value = {:?} universal={:?}", self.region_value_str(sup_region), @@ -1464,6 +1454,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// Things that are to be propagated are accumulated into the /// `outlives_requirements` vector. + #[instrument( + skip(self, body, propagated_outlives_requirements, errors_buffer), + level = "debug" + )] fn check_universal_region( &self, body: &Body<'tcx>, @@ -1471,8 +1465,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements: &mut Option<&mut Vec>>, errors_buffer: &mut RegionErrors<'tcx>, ) { - debug!("check_universal_region(fr={:?})", longer_fr); - let longer_fr_scc = self.constraint_sccs.scc(longer_fr); // Because this free region must be in the ROOT universe, we @@ -1596,7 +1588,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { propagated_outlives_requirements.push(ClosureOutlivesRequirement { subject: ClosureOutlivesSubject::Region(fr_minus), outlived_free_region: fr, - blame_span: blame_span_category.1, + blame_span: blame_span_category.1.span, category: blame_span_category.0, }); } @@ -1738,7 +1730,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { return BlameConstraint { category: constraint.category, from_closure: false, - span, + cause: ObligationCause::dummy_with_span(span), variance_info: constraint.variance_info, }; } @@ -1751,30 +1743,30 @@ impl<'tcx> RegionInferenceContext<'tcx> { .map(|&(category, span)| BlameConstraint { category, from_closure: true, - span: span, + cause: ObligationCause::dummy_with_span(span), variance_info: constraint.variance_info, }) .unwrap_or(BlameConstraint { category: constraint.category, from_closure: false, - span: body.source_info(loc).span, + cause: ObligationCause::dummy_with_span(body.source_info(loc).span), variance_info: constraint.variance_info, }) } - /// Finds a good span to blame for the fact that `fr1` outlives `fr2`. + /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`. crate fn find_outlives_blame_span( &self, body: &Body<'tcx>, fr1: RegionVid, fr1_origin: NllRegionVariableOrigin, fr2: RegionVid, - ) -> (ConstraintCategory, Span) { - let BlameConstraint { category, span, .. } = + ) -> (ConstraintCategory, ObligationCause<'tcx>) { + let BlameConstraint { category, cause, .. } = self.best_blame_constraint(body, fr1, fr1_origin, |r| { self.provides_universal_region(r, fr1, fr2) }); - (category, span) + (category, cause) } /// Walks the graph of constraints (where `'a: 'b` is considered @@ -1877,21 +1869,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Finds some region R such that `fr1: R` and `R` is live at `elem`. + #[instrument(skip(self), level = "trace")] crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { - debug!("find_sub_region_live_at(fr1={:?}, elem={:?})", fr1, elem); - debug!("find_sub_region_live_at: {:?} is in scc {:?}", fr1, self.constraint_sccs.scc(fr1)); - debug!( - "find_sub_region_live_at: {:?} is in universe {:?}", - fr1, - self.scc_universes[self.constraint_sccs.scc(fr1)] - ); + trace!(scc = ?self.constraint_sccs.scc(fr1)); + trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); self.find_constraint_paths_between_regions(fr1, |r| { // First look for some `r` such that `fr1: r` and `r` is live at `elem` - debug!( - "find_sub_region_live_at: liveness_constraints for {:?} are {:?}", - r, - self.liveness_constraints.region_value_str(r), - ); + trace!(?r, liveness_constraints=?self.liveness_constraints.region_value_str(r)); self.liveness_constraints.contains(r, elem) }) .or_else(|| { @@ -1990,6 +1974,27 @@ impl<'tcx> RegionInferenceContext<'tcx> { .collect::>() ); + // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint. + // Instead, we use it to produce an improved `ObligationCauseCode`. + // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate` + // constraints. Currently, we just pick the first one. + let cause_code = path + .iter() + .find_map(|constraint| { + if let ConstraintCategory::Predicate(predicate_span) = constraint.category { + // We currentl'y doesn't store the `DefId` in the `ConstraintCategory` + // for perforamnce reasons. The error reporting code used by NLL only + // uses the span, so this doesn't cause any problems at the moment. + Some(ObligationCauseCode::BindingObligation( + CRATE_DEF_ID.to_def_id(), + predicate_span, + )) + } else { + None + } + }) + .unwrap_or_else(|| ObligationCauseCode::MiscObligation); + // Classify each of the constraints along the path. let mut categorized_path: Vec> = path .iter() @@ -2000,7 +2005,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { BlameConstraint { category: constraint.category, from_closure: false, - span: constraint.locations.span(body), + cause: ObligationCause::new( + constraint.locations.span(body), + CRATE_HIR_ID, + cause_code.clone(), + ), variance_info: constraint.variance_info, } } @@ -2083,7 +2092,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => false, + | ConstraintCategory::Internal + | ConstraintCategory::Predicate(_) => false, ConstraintCategory::TypeAnnotation | ConstraintCategory::Return(_) | ConstraintCategory::Yield => true, @@ -2094,7 +2104,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { ConstraintCategory::OpaqueType | ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation - | ConstraintCategory::Internal => false, + | ConstraintCategory::Internal + | ConstraintCategory::Predicate(_) => false, _ => true, } } @@ -2249,6 +2260,6 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx pub struct BlameConstraint<'tcx> { pub category: ConstraintCategory, pub from_closure: bool, - pub span: Span, + pub cause: ObligationCause<'tcx>, pub variance_info: ty::VarianceDiagInfo<'tcx>, } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d790e31105c8a..4eb7be542e7a1 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,5 +1,9 @@ +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; +use rustc_hir::OpaqueTyOrigin; +use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::InferCtxt; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::opaque_types::InferCtxtExt; @@ -50,13 +54,14 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'_, 'tcx>, - opaque_ty_decls: VecMap, Ty<'tcx>>, + opaque_ty_decls: VecMap, OpaqueTypeDecl<'tcx>>, span: Span, ) -> VecMap, Ty<'tcx>> { opaque_ty_decls .into_iter() - .map(|(opaque_type_key, concrete_type)| { + .filter_map(|(opaque_type_key, decl)| { let substs = opaque_type_key.substs; + let concrete_type = decl.concrete_ty; debug!(?concrete_type, ?substs); let mut subst_regions = vec![self.universal_regions.fr_static]; @@ -94,7 +99,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { universal_concrete_type, span, ); - (opaque_type_key, remapped_type) + + check_opaque_type_parameter_valid( + infcx.tcx, + opaque_type_key, + OpaqueTypeDecl { concrete_ty: remapped_type, ..decl }, + ) + .then_some((opaque_type_key, remapped_type)) }) .collect() } @@ -113,9 +124,116 @@ impl<'tcx> RegionInferenceContext<'tcx> { ty::ReVar(vid) => { // Find something that we can name let upper_bound = self.approx_universal_upper_bound(vid); - self.definitions[upper_bound].external_name.unwrap_or(region) + let upper_bound = &self.definitions[upper_bound]; + match upper_bound.external_name { + Some(reg) => reg, + None => { + // Nothing exact found, so we pick the first one that we find. + let scc = self.constraint_sccs.scc(vid); + for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) { + match self.definitions[vid].external_name { + None => {} + Some(&ty::ReStatic) => {} + Some(region) => return region, + } + } + region + } + } } _ => region, }) } } + +fn check_opaque_type_parameter_valid( + tcx: TyCtxt<'_>, + opaque_type_key: OpaqueTypeKey<'_>, + decl: OpaqueTypeDecl<'_>, +) -> bool { + match decl.origin { + // No need to check return position impl trait (RPIT) + // because for type and const parameters they are correct + // by construction: we convert + // + // fn foo() -> impl Trait + // + // into + // + // type Foo + // fn foo() -> Foo. + // + // For lifetime parameters we convert + // + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> + // + // into + // + // type foo::<'p0..'pn>::Foo<'q0..'qm> + // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. + // + // which would error here on all of the `'static` args. + OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true, + // Check these + OpaqueTyOrigin::TyAlias => {} + } + let span = decl.definition_span; + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); + 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(ty::ReStatic) => { + 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(_)) + } + GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), + }; + + if arg_is_param { + seen_params.entry(arg).or_default().push(i); + } else { + // Prevent `fn foo() -> Foo` from being defining. + let opaque_param = opaque_generics.param_at(i, tcx); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note( + tcx.def_span(opaque_param.def_id), + &format!( + "used non-generic {} `{}` for generic parameter", + opaque_param.kind.descr(), + arg, + ), + ) + .emit(); + return false; + } + } + + for (_, indices) in seen_params { + if indices.len() > 1 { + let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); + let spans: Vec<_> = indices + .into_iter() + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .collect(); + tcx.sess + .struct_span_err(span, "non-defining opaque type use in defining scope") + .span_note(spans, &format!("{} used multiple times", descr)) + .emit(); + return false; + } + } + true +} diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index 9377473befe32..20567610f6557 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -7,13 +7,13 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; /// Replaces all free regions appearing in the MIR with fresh /// inference variables, returning the number of variables created. +#[instrument(skip(infcx, body, promoted), level = "debug")] pub fn renumber_mir<'tcx>( infcx: &InferCtxt<'_, 'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexVec>, ) { - debug!("renumber_mir()"); - debug!("renumber_mir: body.arg_count={:?}", body.arg_count); + debug!(?body.arg_count); let mut visitor = NllVisitor { infcx }; @@ -26,12 +26,11 @@ pub fn renumber_mir<'tcx>( /// Replaces all regions appearing in `value` with fresh inference /// variables. +#[instrument(skip(infcx), level = "debug")] pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, { - debug!("renumber_regions(value={:?})", value); - infcx.tcx.fold_regions(value, &mut false, |_region, _depth| { let origin = NllRegionVariableOrigin::Existential { from_forall: false }; infcx.next_nll_region_var(origin) @@ -56,12 +55,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { self.infcx.tcx } + #[instrument(skip(self), level = "debug")] fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { - debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context); - *ty = self.renumber_regions(ty); - debug!("visit_ty: ty={:?}", ty); + debug!(?ty); } fn process_projection_elem( @@ -80,21 +78,19 @@ impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> { None } + #[instrument(skip(self), level = "debug")] fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) { - debug!("visit_substs(substs={:?}, location={:?})", substs, location); - *substs = self.renumber_regions(*substs); - debug!("visit_substs: substs={:?}", substs); + debug!(?substs); } + #[instrument(skip(self), level = "debug")] fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) { - debug!("visit_region(region={:?}, location={:?})", region, location); - let old_region = *region; *region = self.renumber_regions(&old_region); - debug!("visit_region: region={:?}", region); + debug!(?region); } fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) { diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 18070164e8219..7d4df59902aed 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -4,6 +4,7 @@ use rustc_infer::infer::canonical::Canonical; use rustc_infer::traits::query::NoSolution; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::{self, ToPredicate, TypeFoldable}; +use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; use rustc_trait_selection::traits::query::Fallible; @@ -23,6 +24,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// **Any `rustc_infer::infer` operations that might generate region /// constraints should occur within this method so that those /// constraints can be properly localized!** + #[instrument(skip(self, category, op), level = "trace")] pub(super) fn fully_perform_op( &mut self, locations: Locations, @@ -89,10 +91,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory, ) { self.prove_predicates( - Some(ty::PredicateKind::Trait(ty::TraitPredicate { + Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: ty::BoundConstness::NotConst, - })), + }))), locations, category, ); @@ -100,12 +102,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn normalize_and_prove_instantiated_predicates( &mut self, + // Keep this parameter for now, in case we start using + // it in `ConstraintCategory` at some point. + _def_id: DefId, instantiated_predicates: ty::InstantiatedPredicates<'tcx>, locations: Locations, ) { - for predicate in instantiated_predicates.predicates { + for (predicate, span) in instantiated_predicates + .predicates + .into_iter() + .zip(instantiated_predicates.spans.into_iter()) + { let predicate = self.normalize(predicate, locations); - self.prove_predicate(predicate, locations, ConstraintCategory::Boring); + self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span)); } } @@ -123,14 +132,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] pub(super) fn prove_predicate( &mut self, predicate: ty::Predicate<'tcx>, locations: Locations, category: ConstraintCategory, ) { - debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,); - let param_env = self.param_env; self.fully_perform_op( locations, @@ -142,11 +150,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }) } + #[instrument(skip(self), level = "debug")] pub(super) fn normalize(&mut self, value: T, location: impl NormalizeLocation) -> T where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, { - debug!("normalize(value={:?}, location={:?})", value, location); let param_env = self.param_env; self.fully_perform_op( location.to_locations(), diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index b020746848535..ab1a7461b4b9b 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -53,9 +53,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { - debug!("convert_all(query_constraints={:#?})", query_constraints); - let QueryRegionConstraints { outlives, member_constraints } = query_constraints; // Annoying: to invoke `self.to_region_vid`, we need access to diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 46d30a188edb9..24332690bec31 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -20,6 +20,7 @@ use crate::universal_regions::UniversalRegions; use super::{Locations, TypeChecker}; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + #[instrument(skip(self, body, universal_regions), level = "debug")] pub(super) fn equate_inputs_and_outputs( &mut self, body: &Body<'tcx>, @@ -64,10 +65,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - debug!( - "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}", - normalized_input_tys, body.local_decls - ); + debug!(?normalized_input_tys, ?body.local_decls); // Equate expected input tys with those in the MIR. for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { @@ -160,9 +158,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(skip(self, span), level = "debug")] fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) { - debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b); - if let Err(_) = self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 5ccf380602554..55790bd2daa9b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -14,6 +14,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::infer::opaque_types::OpaqueTypeDecl; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{ @@ -31,6 +32,7 @@ use rustc_middle::ty::{ self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness, }; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_trait_selection::infer::InferCtxtExt as _; @@ -193,16 +195,22 @@ pub(crate) fn type_check<'mir, 'tcx>( opaque_type_values .into_iter() - .filter_map(|(opaque_type_key, decl)| { - let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); - if revealed_ty.has_infer_types_or_consts() { + .filter_map(|(opaque_type_key, mut decl)| { + decl.concrete_ty = infcx.resolve_vars_if_possible(decl.concrete_ty); + trace!( + "finalized opaque type {:?} to {:#?}", + opaque_type_key, + decl.concrete_ty.kind() + ); + if decl.concrete_ty.has_infer_types_or_consts() { infcx.tcx.sess.delay_span_bug( body.span, - &format!("could not resolve {:#?}", revealed_ty.kind()), + &format!("could not resolve {:#?}", decl.concrete_ty.kind()), ); - revealed_ty = infcx.tcx.ty_error(); + decl.concrete_ty = infcx.tcx.ty_error(); } - let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() { + let concrete_is_opaque = if let ty::Opaque(def_id, _) = decl.concrete_ty.kind() + { *def_id == opaque_type_key.def_id } else { false @@ -234,7 +242,7 @@ pub(crate) fn type_check<'mir, 'tcx>( ); None } else { - Some((opaque_type_key, revealed_ty)) + Some((opaque_type_key, decl)) } }) .collect() @@ -244,6 +252,18 @@ pub(crate) fn type_check<'mir, 'tcx>( MirTypeckResults { constraints, universal_region_relations, opaque_type_values } } +#[instrument( + skip( + infcx, + body, + promoted, + region_bound_pairs, + borrowck_context, + universal_region_relations, + extra + ), + level = "debug" +)] fn type_check_internal<'a, 'tcx, R>( infcx: &'a InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -447,6 +467,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() { let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); self.cx.normalize_and_prove_instantiated_predicates( + def_id, instantiated_predicates, location.to_locations(), ); @@ -890,7 +911,7 @@ struct BorrowCheckContext<'a, 'tcx> { crate struct MirTypeckResults<'tcx> { crate constraints: MirTypeckRegionConstraints<'tcx>, crate universal_region_relations: Frozen>, - crate opaque_type_values: VecMap, Ty<'tcx>>, + crate opaque_type_values: VecMap, OpaqueTypeDecl<'tcx>>, } /// A collection of region constraints that must be satisfied for the @@ -1078,7 +1099,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.prove_predicate( - ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into())) + .to_predicate(self.tcx()), Locations::All(span), ConstraintCategory::TypeAnnotation, ); @@ -1109,13 +1131,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(skip(self, data), level = "debug")] fn push_region_constraints( &mut self, locations: Locations, category: ConstraintCategory, data: &QueryRegionConstraints<'tcx>, ) { - debug!("push_region_constraints: constraints generated at {:?} are {:#?}", locations, data); + debug!("constraints generated: {:#?}", data); constraint_conversion::ConstraintConversion::new( self.infcx, @@ -1175,6 +1198,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.relate_types(expected, ty::Variance::Invariant, found, locations, category) } + #[instrument(skip(self), level = "debug")] fn relate_type_and_user_type( &mut self, a: Ty<'tcx>, @@ -1183,11 +1207,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - debug!( - "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})", - a, v, user_ty, locations, - ); - let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); @@ -1245,6 +1264,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// generics of `foo`). Note that `anon_ty` is not just the opaque type, /// but the entire return type (which may contain opaque types within it). /// * `revealed_ty` would be `Box<(T, u32)>` + #[instrument(skip(self), level = "debug")] fn eq_opaque_type_and_type( &mut self, revealed_ty: Ty<'tcx>, @@ -1252,13 +1272,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - debug!( - "eq_opaque_type_and_type( \ - revealed_ty={:?}, \ - anon_ty={:?})", - revealed_ty, anon_ty - ); - // Fast path for the common case. if !anon_ty.has_opaque_types() { if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) { @@ -1278,7 +1291,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let body = self.body; let mir_def_id = body.source.def_id().expect_local(); - debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id); + debug!(?mir_def_id); self.fully_perform_op( locations, category, @@ -1300,12 +1313,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { anon_ty, locations.span(body), )); - debug!( - "eq_opaque_type_and_type: \ - instantiated output_ty={:?} \ - revealed_ty={:?}", - output_ty, revealed_ty - ); + debug!(?output_ty, ?revealed_ty); // Make sure that the inferred types are well-formed. I'm // not entirely sure this is needed (the HIR type check @@ -1314,7 +1322,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { obligations.obligations.push(traits::Obligation::new( ObligationCause::dummy(), param_env, - ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into())) + .to_predicate(infcx.tcx), )); obligations.add( infcx @@ -1322,7 +1331,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { .eq(output_ty, revealed_ty)?, ); - debug!("eq_opaque_type_and_type: equated"); + debug!("equated"); Ok(InferOk { value: (), obligations: obligations.into_vec() }) }, @@ -1362,8 +1371,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.infcx.tcx } + #[instrument(skip(self, body, location), level = "debug")] fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { - debug!("check_stmt: {:?}", stmt); let tcx = self.tcx(); match stmt.kind { StatementKind::Assign(box (ref place, ref rv)) => { @@ -1516,13 +1525,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } + #[instrument(skip(self, body, term_location), level = "debug")] fn check_terminator( &mut self, body: &Body<'tcx>, term: &Terminator<'tcx>, term_location: Location, ) { - debug!("check_terminator: {:?}", term); let tcx = self.tcx(); match term.kind { TerminatorKind::Goto { .. } @@ -1597,7 +1606,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_call_dest(body, term, &sig, destination, term_location); self.prove_predicates( - sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())), + sig.inputs_and_output + .iter() + .map(|ty| ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))), term_location.to_locations(), ConstraintCategory::Boring, ); @@ -2018,13 +2029,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - Rvalue::NullaryOp(_, ty) => { - // Even with unsized locals cannot box an unsized value. - if self.unsized_feature_enabled() { - let span = body.source_info(location).span; - self.ensure_place_sized(ty, span); - } - + Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => { let trait_ref = ty::TraitRef { def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), substs: tcx.mk_substs_trait(ty, &[]), @@ -2357,6 +2362,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::AddressOf(..) | Rvalue::Len(..) | Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) | Rvalue::BinaryOp(..) | Rvalue::CheckedBinaryOp(..) | Rvalue::NullaryOp(..) @@ -2571,9 +2577,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { aggregate_kind, location ); - let instantiated_predicates = match aggregate_kind { + let (def_id, instantiated_predicates) = match aggregate_kind { AggregateKind::Adt(def, _, substs, _, _) => { - tcx.predicates_of(def.did).instantiate(tcx, substs) + (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs)) } // For closures, we have some **extra requirements** we @@ -2598,13 +2604,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // clauses on the struct. AggregateKind::Closure(def_id, substs) | AggregateKind::Generator(def_id, substs, _) => { - self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location) + (*def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location)) } - AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(), + AggregateKind::Array(_) | AggregateKind::Tuple => { + (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) + } }; self.normalize_and_prove_instantiated_predicates( + def_id, instantiated_predicates, location.to_locations(), ); @@ -2679,9 +2688,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx.predicates_of(def_id).instantiate(tcx, substs) } + #[instrument(skip(self, body), level = "debug")] fn typeck_mir(&mut self, body: &Body<'tcx>) { self.last_span = body.span; - debug!("run_on_mir: {:?}", body.span); + debug!(?body.span); for (local, local_decl) in body.local_decls.iter_enumerated() { self.check_local(&body, local, local_decl); diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index de86d39cc3722..b788529dc1cd4 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -17,6 +17,7 @@ use crate::type_check::{BorrowCheckContext, Locations}; /// /// N.B., the type `a` is permitted to have unresolved inference /// variables, but not the type `b`. +#[instrument(skip(infcx, param_env, borrowck_context), level = "debug")] pub(super) fn relate_types<'tcx>( infcx: &InferCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -27,7 +28,6 @@ pub(super) fn relate_types<'tcx>( category: ConstraintCategory, borrowck_context: &mut BorrowCheckContext<'_, 'tcx>, ) -> Fallible<()> { - debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations); TypeRelating::new( infcx, NllTypeRelatingDelegate::new( diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index d7b46f282151f..307730f7f5f14 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -2,6 +2,7 @@ use crate::util::check_builtin_macro_attribute; use rustc_ast as ast; use rustc_ast::mut_visit::MutVisitor; +use rustc_ast::ptr::P; use rustc_ast::tokenstream::CanSynthesizeMissingTokens; use rustc_ast::visit::Visitor; use rustc_ast::{mut_visit, visit}; @@ -9,10 +10,10 @@ use rustc_ast::{AstLike, Attribute}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_expand::config::StripUnconfigured; use rustc_expand::configure; +use rustc_feature::Features; use rustc_parse::parser::ForceCollect; use rustc_session::utils::FlattenNonterminals; - -use rustc_ast::ptr::P; +use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use smallvec::SmallVec; @@ -24,21 +25,19 @@ crate fn expand( annotatable: Annotatable, ) -> Vec { check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval); - vec![cfg_eval(ecx, annotatable)] + vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)] } -crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable { - CfgEval { - cfg: &mut StripUnconfigured { - sess: ecx.sess, - features: ecx.ecfg.features, - config_tokens: true, - }, - } - .configure_annotatable(annotatable) - // Since the item itself has already been configured by the `InvocationCollector`, - // we know that fold result vector will contain exactly one element. - .unwrap() +crate fn cfg_eval( + sess: &Session, + features: Option<&Features>, + annotatable: Annotatable, +) -> Annotatable { + CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } } + .configure_annotatable(annotatable) + // Since the item itself has already been configured by the `InvocationCollector`, + // we know that fold result vector will contain exactly one element. + .unwrap() } struct CfgEval<'a, 'b> { diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 209158ce39206..53a456b69acfd 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -12,7 +12,7 @@ pub fn expand_concat_idents<'cx>( tts: TokenStream, ) -> Box { if tts.is_empty() { - cx.span_err(sp, "concat_idents! takes 1 or more arguments."); + cx.span_err(sp, "concat_idents! takes 1 or more arguments"); return DummyResult::any(sp); } @@ -22,7 +22,7 @@ pub fn expand_concat_idents<'cx>( match e { TokenTree::Token(Token { kind: token::Comma, .. }) => {} _ => { - cx.span_err(sp, "concat_idents! expecting comma."); + cx.span_err(sp, "concat_idents! expecting comma"); return DummyResult::any(sp); } } @@ -34,7 +34,7 @@ pub fn expand_concat_idents<'cx>( } } - cx.span_err(sp, "concat_idents! requires ident args."); + cx.span_err(sp, "concat_idents! requires ident args"); return DummyResult::any(sp); } } diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index e0389f448ebf2..241c90c157125 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,12 +1,13 @@ use crate::cfg_eval::cfg_eval; -use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; +use rustc_ast as ast; +use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; use rustc_errors::{struct_span_err, Applicability}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; use rustc_parse::validate_attr; use rustc_session::Session; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; crate struct Expander; @@ -26,8 +27,7 @@ impl MultiItemModifier for Expander { return ExpandResult::Ready(vec![item]); } - let item = cfg_eval(ecx, item); - + let (sess, features) = (ecx.sess, ecx.ecfg.features); let result = ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| { let template = @@ -40,7 +40,8 @@ impl MultiItemModifier for Expander { template, ); - attr.meta_item_list() + let mut resolutions: Vec<_> = attr + .meta_item_list() .unwrap_or_default() .into_iter() .filter_map(|nested_meta| match nested_meta { @@ -56,8 +57,21 @@ impl MultiItemModifier for Expander { report_path_args(sess, &meta); meta.path }) - .map(|path| (path, item.clone(), None)) - .collect() + .map(|path| (path, dummy_annotatable(), None)) + .collect(); + + // Do not configure or clone items unless necessary. + match &mut resolutions[..] { + [] => {} + [(_, first_item, _), others @ ..] => { + *first_item = cfg_eval(sess, features, item.clone()); + for (_, item, _) in others { + *item = first_item.clone(); + } + } + } + + resolutions }); match result { @@ -67,6 +81,18 @@ impl MultiItemModifier for Expander { } } +// The cheapest `Annotatable` to construct. +fn dummy_annotatable() -> Annotatable { + Annotatable::GenericParam(ast::GenericParam { + id: ast::DUMMY_NODE_ID, + ident: Ident::invalid(), + attrs: Default::default(), + bounds: Default::default(), + is_placeholder: false, + kind: GenericParamKind::Lifetime, + }) +} + fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool { let item_kind = match item { Annotatable::Item(item) => Some(&item.kind), diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 59f933d422d01..0f88995846cc1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -332,20 +332,27 @@ pub fn combine_substructure( RefCell::new(f) } +struct TypeParameter { + bound_generic_params: Vec, + ty: P, +} + /// This method helps to extract all the type parameters referenced from a /// type. For a type parameter ``, it looks for either a `TyPath` that /// is not global and starts with `T`, or a `TyQPath`. +/// Also include bound generic params from the input type. fn find_type_parameters( ty: &ast::Ty, ty_param_names: &[Symbol], cx: &ExtCtxt<'_>, -) -> Vec> { +) -> Vec { use rustc_ast::visit; struct Visitor<'a, 'b> { cx: &'a ExtCtxt<'b>, ty_param_names: &'a [Symbol], - types: Vec>, + bound_generic_params_stack: Vec, + type_params: Vec, } impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { @@ -353,7 +360,10 @@ fn find_type_parameters( if let ast::TyKind::Path(_, ref path) = ty.kind { if let Some(segment) = path.segments.first() { if self.ty_param_names.contains(&segment.ident.name) { - self.types.push(P(ty.clone())); + self.type_params.push(TypeParameter { + bound_generic_params: self.bound_generic_params_stack.clone(), + ty: P(ty.clone()), + }); } } } @@ -361,15 +371,35 @@ fn find_type_parameters( visit::walk_ty(self, ty) } + // Place bound generic params on a stack, to extract them when a type is encountered. + fn visit_poly_trait_ref( + &mut self, + trait_ref: &'a ast::PolyTraitRef, + modifier: &'a ast::TraitBoundModifier, + ) { + let stack_len = self.bound_generic_params_stack.len(); + self.bound_generic_params_stack + .extend(trait_ref.bound_generic_params.clone().into_iter()); + + visit::walk_poly_trait_ref(self, trait_ref, modifier); + + self.bound_generic_params_stack.truncate(stack_len); + } + fn visit_mac_call(&mut self, mac: &ast::MacCall) { self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros"); } } - let mut visitor = Visitor { cx, ty_param_names, types: Vec::new() }; + let mut visitor = Visitor { + cx, + ty_param_names, + bound_generic_params_stack: Vec::new(), + type_params: Vec::new(), + }; visit::Visitor::visit_ty(&mut visitor, ty); - visitor.types + visitor.type_params } impl<'a> TraitDef<'a> { @@ -617,11 +647,11 @@ impl<'a> TraitDef<'a> { ty_params.map(|ty_param| ty_param.ident.name).collect(); for field_ty in field_tys { - let tys = find_type_parameters(&field_ty, &ty_param_names, cx); + let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx); - for ty in tys { + for field_ty_param in field_ty_params { // if we have already handled this type, skip it - if let ast::TyKind::Path(_, ref p) = ty.kind { + if let ast::TyKind::Path(_, ref p) = field_ty_param.ty.kind { if p.segments.len() == 1 && ty_param_names.contains(&p.segments[0].ident.name) { @@ -639,8 +669,8 @@ impl<'a> TraitDef<'a> { let predicate = ast::WhereBoundPredicate { span: self.span, - bound_generic_params: Vec::new(), - bounded_ty: ty, + bound_generic_params: field_ty_param.bound_generic_params, + bounded_ty: field_ty_param.ty, bounds, }; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 9b9adc2d7f3b8..f0056cb79766a 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -164,23 +164,22 @@ fn parse_args<'a>( p.clear_expected_tokens(); } - // `Parser::expect` tries to recover using the - // `Parser::unexpected_try_recover` function. This function is able - // to recover if the expected token is a closing delimiter. - // - // As `,` is not a closing delimiter, it will always return an `Err` - // variant. - let mut err = p.expect(&token::Comma).unwrap_err(); - - match token::TokenKind::Comma.similar_tokens() { - Some(tks) if tks.contains(&p.token.kind) => { - // If a similar token is found, then it may be a typo. We - // consider it as a comma, and continue parsing. - err.emit(); - p.bump(); + match p.expect(&token::Comma) { + Err(mut err) => { + match token::TokenKind::Comma.similar_tokens() { + Some(tks) if tks.contains(&p.token.kind) => { + // If a similar token is found, then it may be a typo. We + // consider it as a comma, and continue parsing. + err.emit(); + p.bump(); + } + // Otherwise stop the parsing and return the error. + _ => return Err(err), + } + } + Ok(recovered) => { + assert!(recovered); } - // Otherwise stop the parsing and return the error. - _ => return Err(err), } } first = false; @@ -1155,11 +1154,12 @@ pub fn expand_preparsed_format_args( // account for `"` and account for raw strings `r#` let padding = str_style.map(|i| i + 2).unwrap_or(1); for sub in foreign::$kind::iter_subs(fmt_str, padding) { - let trn = match sub.translate() { - Some(trn) => trn, + let (trn, success) = match sub.translate() { + Ok(trn) => (trn, true), + Err(Some(msg)) => (msg, false), // If it has no translation, don't call it out specifically. - None => continue, + _ => continue, }; let pos = sub.position(); @@ -1176,9 +1176,24 @@ pub fn expand_preparsed_format_args( if let Some(inner_sp) = pos { let sp = fmt_sp.from_inner(inner_sp); - suggestions.push((sp, trn)); + + if success { + suggestions.push((sp, trn)); + } else { + diag.span_note( + sp, + &format!("format specifiers use curly braces, and {}", trn), + ); + } } else { - diag.help(&format!("`{}` should be written as `{}`", sub, trn)); + if success { + diag.help(&format!("`{}` should be written as `{}`", sub, trn)); + } else { + diag.note(&format!( + "`{}` should use curly braces, and {}", + sub, trn + )); + } } } diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 0cc520e5bd1f0..bfddd7073ff2c 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -1,4 +1,4 @@ -pub mod printf { +pub(crate) mod printf { use super::strcursor::StrCursor as Cur; use rustc_span::InnerSpan; @@ -36,10 +36,10 @@ pub mod printf { /// /// This ignores cases where the substitution does not have an exact equivalent, or where /// the substitution would be unnecessary. - pub fn translate(&self) -> Option { + pub fn translate(&self) -> Result> { match *self { Substitution::Format(ref fmt) => fmt.translate(), - Substitution::Escape => None, + Substitution::Escape => Err(None), } } } @@ -68,9 +68,9 @@ pub mod printf { impl Format<'_> { /// Translate this directive into an equivalent Rust formatting directive. /// - /// Returns `None` in cases where the `printf` directive does not have an exact Rust + /// Returns `Err` in cases where the `printf` directive does not have an exact Rust /// equivalent, rather than guessing. - pub fn translate(&self) -> Option { + pub fn translate(&self) -> Result> { use std::fmt::Write; let (c_alt, c_zero, c_left, c_plus) = { @@ -84,7 +84,12 @@ pub mod printf { '0' => c_zero = true, '-' => c_left = true, '+' => c_plus = true, - _ => return None, + _ => { + return Err(Some(format!( + "the flag `{}` is unknown or unsupported", + c + ))); + } } } (c_alt, c_zero, c_left, c_plus) @@ -104,7 +109,9 @@ pub mod printf { let width = match self.width { Some(Num::Next) => { // NOTE: Rust doesn't support this. - return None; + return Err(Some( + "you have to use a positional or named parameter for the width".to_string(), + )); } w @ Some(Num::Arg(_)) => w, w @ Some(Num::Num(_)) => w, @@ -125,13 +132,21 @@ pub mod printf { "p" => (Some(self.type_), false, true), "g" => (Some("e"), true, false), "G" => (Some("E"), true, false), - _ => return None, + _ => { + return Err(Some(format!( + "the conversion specifier `{}` is unknown or unsupported", + self.type_ + ))); + } }; let (fill, width, precision) = match (is_int, width, precision) { (true, Some(_), Some(_)) => { // Rust can't duplicate this insanity. - return None; + return Err(Some( + "width and precision cannot both be specified for integer conversions" + .to_string(), + )); } (true, None, Some(p)) => (Some("0"), Some(p), None), (true, w, None) => (fill, w, None), @@ -169,7 +184,17 @@ pub mod printf { s.push('{'); if let Some(arg) = self.parameter { - write!(s, "{}", arg.checked_sub(1)?).ok()?; + match write!( + s, + "{}", + match arg.checked_sub(1) { + Some(a) => a, + None => return Err(None), + } + ) { + Err(_) => return Err(None), + _ => {} + } } if has_options { @@ -199,12 +224,18 @@ pub mod printf { } if let Some(width) = width { - width.translate(&mut s).ok()?; + match width.translate(&mut s) { + Err(_) => return Err(None), + _ => {} + } } if let Some(precision) = precision { s.push('.'); - precision.translate(&mut s).ok()?; + match precision.translate(&mut s) { + Err(_) => return Err(None), + _ => {} + } } if let Some(type_) = type_ { @@ -213,7 +244,7 @@ pub mod printf { } s.push('}'); - Some(s) + Ok(s) } } @@ -623,11 +654,11 @@ pub mod shell { } } - pub fn translate(&self) -> Option { + pub fn translate(&self) -> Result> { match *self { - Substitution::Ordinal(n, _) => Some(format!("{{{}}}", n)), - Substitution::Name(n, _) => Some(format!("{{{}}}", n)), - Substitution::Escape(_) => None, + Substitution::Ordinal(n, _) => Ok(format!("{{{}}}", n)), + Substitution::Name(n, _) => Ok(format!("{{{}}}", n)), + Substitution::Escape(_) => Err(None), } } } diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs index 33c54c9cee001..1336aab731674 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs @@ -3,7 +3,7 @@ use super::{iter_subs, parse_next_substitution as pns, Format as F, Num as N, Su macro_rules! assert_eq_pnsat { ($lhs:expr, $rhs:expr) => { assert_eq!( - pns($lhs).and_then(|(s, _)| s.translate()), + pns($lhs).and_then(|(s, _)| s.translate().ok()), $rhs.map(>::from) ) }; @@ -98,7 +98,7 @@ fn test_parse() { #[test] fn test_iter() { let s = "The %d'th word %% is: `%.*s` %!\n"; - let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect(); + let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); assert_eq!( subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), vec![Some("{}"), None, Some("{:.*}"), None] diff --git a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs index ed8fe81dfcdd8..f5f82732f2034 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs @@ -3,7 +3,7 @@ use super::{parse_next_substitution as pns, Substitution as S}; macro_rules! assert_eq_pnsat { ($lhs:expr, $rhs:expr) => { assert_eq!( - pns($lhs).and_then(|(f, _)| f.translate()), + pns($lhs).and_then(|(f, _)| f.translate().ok()), $rhs.map(>::from) ) }; @@ -37,7 +37,7 @@ fn test_parse() { fn test_iter() { use super::iter_subs; let s = "The $0'th word $$ is: `$WORD` $!\n"; - let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate()).collect(); + let subs: Vec<_> = iter_subs(s, 0).map(|sub| sub.translate().ok()).collect(); assert_eq!( subs.iter().map(|ms| ms.as_ref().map(|s| &s[..])).collect::>(), vec![Some("{0}"), None, Some("{WORD}")] diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 99544ddb66e66..bbca07085ea36 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -382,7 +382,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { .note( "errors in this attribute were erroneously \ allowed and will become a hard error in a \ - future release.", + future release", ) .emit(); ShouldPanic::Yes(None) diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore index 25080488a88b5..b6567aca78679 100644 --- a/compiler/rustc_codegen_cranelift/.gitignore +++ b/compiler/rustc_codegen_cranelift/.gitignore @@ -15,4 +15,4 @@ perf.data.old /rand /regex /simple-raytracer -/stdsimd +/portable-simd diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 23c1fdc6ee425..4afddf76869de 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -33,16 +33,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-bforest", "cranelift-codegen-meta", @@ -57,8 +57,8 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -66,18 +66,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" [[package]] name = "cranelift-entity" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" [[package]] name = "cranelift-frontend" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-codegen", "log", @@ -87,8 +87,8 @@ dependencies = [ [[package]] name = "cranelift-jit" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "anyhow", "cranelift-codegen", @@ -104,8 +104,8 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "anyhow", "cranelift-codegen", @@ -115,8 +115,8 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "cranelift-codegen", "libc", @@ -125,8 +125,8 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.75.0" -source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b" +version = "0.76.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b" dependencies = [ "anyhow", "cranelift-codegen", diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index e068f084234bc..22be21cb8dee9 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.14.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" dependencies = [ "compiler_builtins", "gimli", @@ -40,9 +40,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "cc" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "cfg-if" @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.46" +version = "0.1.50" dependencies = [ "rustc-std-workspace-core", ] @@ -99,9 +99,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.23.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -132,13 +132,23 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.98" +version = "0.2.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-core", +] + [[package]] name = "miniz_oxide" version = "0.4.4" @@ -154,11 +164,12 @@ dependencies = [ [[package]] name = "object" -version = "0.22.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" +checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" dependencies = [ "compiler_builtins", + "memchr", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -195,9 +206,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -286,9 +297,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs index 4b2051b605abd..ae9a35048bda9 100644 --- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs +++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs @@ -28,11 +28,11 @@ pub(crate) fn prepare() { ); clone_repo( - "stdsimd", - "https://github.com/rust-lang/stdsimd", - "be96995d8ddec03fac9a0caf4d4c51c7fbc33507", + "portable-simd", + "https://github.com/rust-lang/portable-simd", + "8cf7a62e5d2552961df51e5200aaa5b7c890a4bf", ); - apply_patches("stdsimd", Path::new("stdsimd")); + apply_patches("portable-simd", Path::new("portable-simd")); clone_repo( "simple-raytracer", @@ -92,7 +92,7 @@ fn prepare_sysroot() { clone_repo( "build_sysroot/compiler-builtins", "https://github.com/rust-lang/compiler-builtins.git", - "0.1.46", + "0.1.50", ); apply_patches("compiler-builtins", Path::new("build_sysroot/compiler-builtins")); } diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh index 23e5bf2e0a8fd..865de7d234f14 100755 --- a/compiler/rustc_codegen_cranelift/clean_all.sh +++ b/compiler/rustc_codegen_cranelift/clean_all.sh @@ -3,4 +3,4 @@ set -e rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version} rm -rf target/ build/ perf.data{,.old} -rm -rf rand/ regex/ simple-raytracer/ stdsimd/ +rm -rf rand/ regex/ simple-raytracer/ portable-simd/ diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md index 87eec0e818bb2..bcc5745d9d197 100644 --- a/compiler/rustc_codegen_cranelift/docs/usage.md +++ b/compiler/rustc_codegen_cranelift/docs/usage.md @@ -24,6 +24,8 @@ $ $cg_clif_dir/build/bin/cg_clif my_crate.rs ## Jit mode +> ⚠⚠⚠ The JIT mode is highly experimental. It may be slower than AOT compilation due to lack of incremental compilation. It may also be hard to setup if you have cargo dependencies. ⚠⚠⚠ + In jit mode cg_clif will immediately execute your code without creating an executable file. > This requires all dependencies to be available as dynamic library. diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs index 2a9f7e58e01c2..d0d492e96742d 100644 --- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs +++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs @@ -1,4 +1,4 @@ -#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler)] +#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler, box_syntax)] #![no_std] extern crate alloc; diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 6e13e4dcbfbff..cbfdb3c44f33e 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -1,4 +1,4 @@ -#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)] +#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, box_syntax)] #![no_core] #![allow(dead_code, non_camel_case_types)] diff --git a/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch similarity index 77% rename from compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch rename to compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch index 731c60fda58d6..2e68369466363 100644 --- a/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch @@ -4,21 +4,20 @@ Date: Sun, 25 Jul 2021 18:39:31 +0200 Subject: [PATCH] Disable unsupported tests --- - crates/core_simd/src/array.rs | 2 ++ - crates/core_simd/src/lib.rs | 2 +- + crates/core_simd/src/vector.rs | 2 ++ crates/core_simd/src/math.rs | 4 ++++ crates/core_simd/tests/masks.rs | 12 ------------ crates/core_simd/tests/ops_macros.rs | 6 ++++++ crates/core_simd/tests/round.rs | 2 ++ 6 files changed, 15 insertions(+), 13 deletions(-) -diff --git a/crates/core_simd/src/array.rs b/crates/core_simd/src/array.rs +diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index 25c5309..2b3d819 100644 ---- a/crates/core_simd/src/array.rs -+++ b/crates/core_simd/src/array.rs +--- a/crates/core_simd/src/vector.rs ++++ b/crates/core_simd/src/vector.rs @@ -22,6 +22,7 @@ where - #[must_use] - fn splat(val: Self::Scalar) -> Self; + self.0 + } + /* /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices. @@ -31,27 +30,14 @@ index 25c5309..2b3d819 100644 + */ } - macro_rules! impl_simdarray_for { -diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs -index a64904d..299eb11 100644 ---- a/crates/core_simd/src/lib.rs -+++ b/crates/core_simd/src/lib.rs -@@ -1,7 +1,7 @@ - #![no_std] - #![allow(incomplete_features)] - #![feature( -- const_generics, -+ const_generics, - platform_intrinsics, - repr_simd, - simd_ffi, + impl Copy for Simd diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs index 7290a28..e394730 100644 --- a/crates/core_simd/src/math.rs +++ b/crates/core_simd/src/math.rs @@ -2,6 +2,7 @@ macro_rules! impl_uint_arith { - ($(($name:ident, $n:ident)),+) => { - $( impl $name where Self: crate::LanesAtMost32 { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { + /* /// Lanewise saturating add. @@ -66,8 +52,8 @@ index 7290a28..e394730 100644 } } @@ -46,6 +48,7 @@ macro_rules! impl_int_arith { - ($(($name:ident, $n:ident)),+) => { - $( impl $name where Self: crate::LanesAtMost32 { + ($($ty:ty),+) => { + $( impl Simd<$ty, LANES> where LaneCount: SupportedLaneCount { + /* /// Lanewise saturating add. @@ -85,21 +71,22 @@ diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs index 61d8e44..2bccae2 100644 --- a/crates/core_simd/tests/masks.rs +++ b/crates/core_simd/tests/masks.rs -@@ -67,18 +67,6 @@ macro_rules! test_mask_api { +@@ -67,19 +67,6 @@ macro_rules! test_mask_api { assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]); - assert_eq!(core_simd::$name::<8>::from_int(int), mask); + assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask); } - +- #[cfg(feature = "generic_const_exprs")] - #[test] - fn roundtrip_bitmask_conversion() { - let values = [ - true, false, false, true, false, false, true, false, - true, true, false, false, false, false, false, true, - ]; -- let mask = core_simd::$name::<16>::from_array(values); +- let mask = core_simd::Mask::<$type, 16>::from_array(values); - let bitmask = mask.to_bitmask(); - assert_eq!(bitmask, [0b01001001, 0b10000011]); -- assert_eq!(core_simd::$name::<16>::from_bitmask(bitmask), mask); +- assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask); - } } } @@ -122,7 +109,7 @@ index cb39e73..fc0ebe1 100644 } + */ - fn sqrt() { + fn recip() { test_helpers::test_unary_elementwise( @@ -581,6 +585,7 @@ macro_rules! impl_float_tests { }); @@ -138,8 +125,8 @@ index cb39e73..fc0ebe1 100644 } + */ } - } - } + + #[cfg(feature = "std")] diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs index 37044a7..4cdc6b7 100644 --- a/crates/core_simd/tests/round.rs diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch index cda8153083c33..e2d07bd126702 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch @@ -1,4 +1,4 @@ -From 6a4e6f5dc8c8a529a822eb9b57f9e57519595439 Mon Sep 17 00:00:00 2001 +From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 18 Feb 2021 18:45:28 +0100 Subject: [PATCH] Disable 128bit atomic operations @@ -8,7 +8,8 @@ Cranelift doesn't support them yet library/core/src/panic/unwind_safe.rs | 6 ----- library/core/src/sync/atomic.rs | 38 --------------------------- library/core/tests/atomic.rs | 4 --- - 3 files changed, 48 deletions(-) + library/std/src/time/monotonic.rs | 6 +++-- + 4 files changed, 4 insertions(+), 50 deletions(-) diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 092b7cf..158cf71 100644 @@ -35,10 +36,10 @@ index 092b7cf..158cf71 100644 #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs -index 0194c58..25a0038 100644 +index d9de37e..8293fce 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -2229,44 +2229,6 @@ atomic_int! { +@@ -2234,44 +2234,6 @@ atomic_int! { "AtomicU64::new(0)", u64 AtomicU64 ATOMIC_U64_INIT } @@ -98,6 +99,38 @@ index b735957..ea728b6 100644 #[cfg(target_has_atomic = "ptr")] assert_eq!(align_of::(), size_of::()); #[cfg(target_has_atomic = "ptr")] +diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs +index fa96b7a..2854f9c 100644 +--- a/library/std/src/time/monotonic.rs ++++ b/library/std/src/time/monotonic.rs +@@ -5,7 +5,7 @@ pub(super) fn monotonize(raw: time::Instant) -> time::Instant { + inner::monotonize(raw) + } + +-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))] ++#[cfg(target_has_atomic = "64")] + pub mod inner { + use crate::sync::atomic::AtomicU64; + use crate::sync::atomic::Ordering::*; +@@ -70,6 +70,7 @@ pub mod inner { + } + } + ++/* + #[cfg(target_has_atomic = "128")] + pub mod inner { + use crate::sync::atomic::AtomicU128; +@@ -94,8 +95,9 @@ pub mod inner { + ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap() + } + } ++*/ + +-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))] ++#[cfg(not(target_has_atomic = "64"))] + pub mod inner { + use crate::cmp; + use crate::sys::time; -- 2.26.2.7.g19db9cfb68 diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index f074ebe7a42e0..360570b3ae7a1 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-08-05" +channel = "nightly-2021-09-19" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs index 7a51293f5cda5..a0e99267c2b70 100755 --- a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs +++ b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs @@ -96,7 +96,7 @@ fn main() -> Result<(), Box> { stack = &stack[..index + REPORT_SYMBOL_NAMES.len()]; } - const ENCODE_METADATA: &str = "rustc_middle::ty::context::TyCtxt::encode_metadata"; + const ENCODE_METADATA: &str = "rustc_metadata::rmeta::encoder::encode_metadata"; if let Some(index) = stack.find(ENCODE_METADATA) { stack = &stack[..index + ENCODE_METADATA.len()]; } diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 0ac49dd35740f..b714d47fec2a6 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 cargo install ripgrep rm -r src/test/ui/{extern/,panics/,unsized-locals/,thinlto/,simd*,*lto*.rs,linkage*,unwind-*.rs} || true -for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto" src/test/ui); do +for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto|// needs-asm-support" src/test/ui); do rm $test done diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh index 0eef710239bdd..28a7980d6613c 100755 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -137,8 +137,8 @@ function extended_sysroot_tests() { fi popd - pushd stdsimd - echo "[TEST] rust-lang/stdsimd" + pushd portable-simd + echo "[TEST] rust-lang/portable-simd" ../build/cargo clean ../build/cargo build --all-targets --target $TARGET_TRIPLE if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 0fa228fc944a1..71f510c037f11 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -1,17 +1,20 @@ //! Creation of ar archives like for the lib and staticlib crate type use std::collections::BTreeMap; +use std::convert::TryFrom; use std::fs::File; +use std::io::{self, Read, Seek}; use std::path::{Path, PathBuf}; use rustc_codegen_ssa::back::archive::ArchiveBuilder; use rustc_session::Session; -use object::{Object, ObjectSymbol, SymbolKind}; +use object::read::archive::ArchiveFile; +use object::{Object, ObjectSymbol, ReadCache, SymbolKind}; #[derive(Debug)] enum ArchiveEntry { - FromArchive { archive_index: usize, entry_index: usize }, + FromArchive { archive_index: usize, file_range: (u64, u64) }, File(PathBuf), } @@ -21,29 +24,28 @@ pub(crate) struct ArArchiveBuilder<'a> { use_gnu_style_archive: bool, no_builtin_ranlib: bool, - src_archives: Vec<(PathBuf, ar::Archive)>, + src_archives: Vec, // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at // the end of an archive for linkers to not get confused. - entries: Vec<(String, ArchiveEntry)>, + entries: Vec<(Vec, ArchiveEntry)>, } impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self { let (src_archives, entries) = if let Some(input) = input { - let mut archive = ar::Archive::new(File::open(input).unwrap()); + let read_cache = ReadCache::new(File::open(input).unwrap()); + let archive = ArchiveFile::parse(&read_cache).unwrap(); let mut entries = Vec::new(); - let mut i = 0; - while let Some(entry) = archive.next_entry() { + for entry in archive.members() { let entry = entry.unwrap(); entries.push(( - String::from_utf8(entry.header().identifier().to_vec()).unwrap(), - ArchiveEntry::FromArchive { archive_index: 0, entry_index: i }, + entry.name().to_vec(), + ArchiveEntry::FromArchive { archive_index: 0, file_range: entry.file_range() }, )); - i += 1; } - (vec![(input.to_owned(), archive)], entries) + (vec![read_cache.into_inner()], entries) } else { (vec![], Vec::new()) }; @@ -61,21 +63,21 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } fn src_files(&mut self) -> Vec { - self.entries.iter().map(|(name, _)| name.clone()).collect() + self.entries.iter().map(|(name, _)| String::from_utf8(name.clone()).unwrap()).collect() } fn remove_file(&mut self, name: &str) { let index = self .entries .iter() - .position(|(entry_name, _)| entry_name == name) + .position(|(entry_name, _)| entry_name == name.as_bytes()) .expect("Tried to remove file not existing in src archive"); self.entries.remove(index); } fn add_file(&mut self, file: &Path) { self.entries.push(( - file.file_name().unwrap().to_str().unwrap().to_string(), + file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(), ArchiveEntry::File(file.to_owned()), )); } @@ -84,22 +86,23 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { where F: FnMut(&str) -> bool + 'static, { - let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); + let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?); + let archive = ArchiveFile::parse(&read_cache).unwrap(); let archive_index = self.src_archives.len(); - let mut i = 0; - while let Some(entry) = archive.next_entry() { - let entry = entry?; - let file_name = String::from_utf8(entry.header().identifier().to_vec()) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; + for entry in archive.members() { + let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; + let file_name = String::from_utf8(entry.name().to_vec()) + .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; if !skip(&file_name) { - self.entries - .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i })); + self.entries.push(( + file_name.into_bytes(), + ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() }, + )); } - i += 1; } - self.src_archives.push((archive_path.to_owned(), archive)); + self.src_archives.push(read_cache.into_inner()); Ok(()) } @@ -121,14 +124,14 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { // FIXME only read the symbol table of the object files to avoid having to keep all // object files in memory at once, or read them twice. let data = match entry { - ArchiveEntry::FromArchive { archive_index, entry_index } => { + ArchiveEntry::FromArchive { archive_index, file_range } => { // FIXME read symbols from symtab - use std::io::Read; - let (ref _src_archive_path, ref mut src_archive) = - self.src_archives[archive_index]; - let mut entry = src_archive.jump_to_entry(entry_index).unwrap(); - let mut data = Vec::new(); - entry.read_to_end(&mut data).unwrap(); + let src_read_cache = &mut self.src_archives[archive_index]; + + src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap(); + let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap()); + src_read_cache.read_exact(&mut data).unwrap(); + data } ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| { @@ -143,7 +146,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { match object::File::parse(&*data) { Ok(object) => { symbol_table.insert( - entry_name.as_bytes().to_vec(), + entry_name.to_vec(), object .symbols() .filter_map(|symbol| { @@ -168,7 +171,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { } else { sess.fatal(&format!( "error parsing `{}` during archive creation: {}", - entry_name, err + String::from_utf8_lossy(&entry_name), + err )); } } @@ -187,7 +191,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { err )); }), - entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(), + entries.iter().map(|(name, _)| name.clone()).collect(), ar::GnuSymbolTableFormat::Size32, symbol_table, ) @@ -210,7 +214,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { // Add all files for (entry_name, data) in entries.into_iter() { - let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64); + let header = ar::Header::new(entry_name, data.len() as u64); match builder { BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(), BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(), @@ -238,7 +242,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { fn inject_dll_import_lib( &mut self, _lib_name: &str, - _dll_imports: &[rustc_middle::middle::cstore::DllImport], + _dll_imports: &[rustc_session::cstore::DllImport], _tmpdir: &rustc_data_structures::temp_dir::MaybeTempDir, ) { bug!("injecting dll imports is not supported"); diff --git a/compiler/rustc_codegen_cranelift/src/backend.rs b/compiler/rustc_codegen_cranelift/src/backend.rs deleted file mode 100644 index 05c06bac27db4..0000000000000 --- a/compiler/rustc_codegen_cranelift/src/backend.rs +++ /dev/null @@ -1,152 +0,0 @@ -//! Abstraction around the object writing crate - -use std::convert::{TryFrom, TryInto}; - -use rustc_data_structures::fx::FxHashMap; -use rustc_session::Session; - -use cranelift_codegen::isa::TargetIsa; -use cranelift_module::FuncId; -use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct}; - -use object::write::*; -use object::{RelocationEncoding, SectionKind, SymbolFlags}; - -use gimli::SectionId; - -use crate::debuginfo::{DebugReloc, DebugRelocName}; - -pub(crate) trait WriteMetadata { - fn add_rustc_section(&mut self, symbol_name: String, data: Vec); -} - -impl WriteMetadata for object::write::Object { - fn add_rustc_section(&mut self, symbol_name: String, data: Vec) { - let segment = self.segment_name(object::write::StandardSegment::Data).to_vec(); - let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data); - let offset = self.append_section_data(section_id, &data, 1); - // For MachO and probably PE this is necessary to prevent the linker from throwing away the - // .rustc section. For ELF this isn't necessary, but it also doesn't harm. - self.add_symbol(object::write::Symbol { - name: symbol_name.into_bytes(), - value: offset, - size: data.len() as u64, - kind: object::SymbolKind::Data, - scope: object::SymbolScope::Dynamic, - weak: false, - section: SymbolSection::Section(section_id), - flags: SymbolFlags::None, - }); - } -} - -pub(crate) trait WriteDebugInfo { - type SectionId: Copy; - - fn add_debug_section(&mut self, name: SectionId, data: Vec) -> Self::SectionId; - fn add_debug_reloc( - &mut self, - section_map: &FxHashMap, - from: &Self::SectionId, - reloc: &DebugReloc, - ); -} - -impl WriteDebugInfo for ObjectProduct { - type SectionId = (object::write::SectionId, object::write::SymbolId); - - fn add_debug_section( - &mut self, - id: SectionId, - data: Vec, - ) -> (object::write::SectionId, object::write::SymbolId) { - let name = if self.object.format() == object::BinaryFormat::MachO { - id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info - } else { - id.name().to_string() - } - .into_bytes(); - - let segment = self.object.segment_name(StandardSegment::Debug).to_vec(); - // FIXME use SHT_X86_64_UNWIND for .eh_frame - let section_id = self.object.add_section( - segment, - name, - if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug }, - ); - self.object - .section_mut(section_id) - .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 }); - let symbol_id = self.object.section_symbol(section_id); - (section_id, symbol_id) - } - - fn add_debug_reloc( - &mut self, - section_map: &FxHashMap, - from: &Self::SectionId, - reloc: &DebugReloc, - ) { - let (symbol, symbol_offset) = match reloc.name { - DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0), - DebugRelocName::Symbol(id) => { - let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap())); - self.object - .symbol_section_and_offset(symbol_id) - .expect("Debug reloc for undef sym???") - } - }; - self.object - .add_relocation( - from.0, - Relocation { - offset: u64::from(reloc.offset), - symbol, - kind: reloc.kind, - encoding: RelocationEncoding::Generic, - size: reloc.size * 8, - addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, - }, - ) - .unwrap(); - } -} - -pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec { - let triple = crate::target_triple(sess); - - let binary_format = match triple.binary_format { - target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf, - target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff, - target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO, - binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)), - }; - let architecture = match triple.architecture { - target_lexicon::Architecture::X86_32(_) => object::Architecture::I386, - target_lexicon::Architecture::X86_64 => object::Architecture::X86_64, - target_lexicon::Architecture::Arm(_) => object::Architecture::Arm, - target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64, - architecture => { - sess.fatal(&format!("target architecture {:?} is unsupported", architecture,)) - } - }; - let endian = match triple.endianness().unwrap() { - target_lexicon::Endianness::Little => object::Endianness::Little, - target_lexicon::Endianness::Big => object::Endianness::Big, - }; - - let mut metadata_object = object::write::Object::new(binary_format, architecture, endian); - metadata_object.add_file_symbol(name.as_bytes().to_vec()); - f(&mut metadata_object); - metadata_object.write().unwrap() -} - -pub(crate) fn make_module(sess: &Session, isa: Box, name: String) -> ObjectModule { - let mut builder = - ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); - // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size - // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections - // can easily double the amount of time necessary to perform linking. - builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false)); - ObjectModule::new(builder) -} diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index d8fa2c7690468..1b30edd293862 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -701,6 +701,13 @@ fn codegen_stmt<'tcx>( let len = codegen_array_len(fx, place); lval.write_cvalue(fx, CValue::by_val(len, usize_layout)); } + Rvalue::ShallowInitBox(ref operand, content_ty) => { + let content_ty = fx.monomorphize(content_ty); + let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty)); + let operand = codegen_operand(fx, operand); + let operand = operand.load_scalar(fx); + lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); + } Rvalue::NullaryOp(NullOp::Box, content_ty) => { let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap(); let content_ty = fx.monomorphize(content_ty); diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs index a044b43b86470..b924f2085a0fc 100644 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs @@ -1,4 +1,7 @@ #![feature(rustc_private, once_cell)] +#![warn(rust_2018_idioms)] +#![warn(unused_lifetimes)] +#![warn(unreachable_pub)] extern crate rustc_data_structures; extern crate rustc_driver; diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs index 89e0cb8d90ecd..bde4d71b9a33c 100644 --- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs @@ -7,6 +7,9 @@ //! target crates. #![feature(rustc_private)] +#![warn(rust_2018_idioms)] +#![warn(unused_lifetimes)] +#![warn(unreachable_pub)] extern crate rustc_driver; extern crate rustc_interface; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index fb6ccd7c53584..c8c2d50b03409 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -1,16 +1,16 @@ //! Write the debuginfo into an object file. +use cranelift_object::ObjectProduct; use rustc_data_structures::fx::FxHashMap; use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer}; use gimli::{RunTimeEndian, SectionId}; -use crate::backend::WriteDebugInfo; - +use super::object::WriteDebugInfo; use super::DebugContext; impl DebugContext<'_> { - pub(crate) fn emit(&mut self, product: &mut P) { + pub(crate) fn emit(&mut self, product: &mut ObjectProduct) { let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone()); let root = self.dwarf.unit.root(); let root = self.dwarf.unit.get_mut(root); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index cabe3e43b342c..6d172817cb12e 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -2,6 +2,7 @@ mod emit; mod line_info; +mod object; mod unwind; use crate::prelude::*; diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs new file mode 100644 index 0000000000000..9984dc92c44d0 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs @@ -0,0 +1,85 @@ +use std::convert::{TryFrom, TryInto}; + +use rustc_data_structures::fx::FxHashMap; + +use cranelift_module::FuncId; +use cranelift_object::ObjectProduct; + +use object::write::{Relocation, StandardSegment}; +use object::{RelocationEncoding, SectionKind}; + +use gimli::SectionId; + +use crate::debuginfo::{DebugReloc, DebugRelocName}; + +pub(super) trait WriteDebugInfo { + type SectionId: Copy; + + fn add_debug_section(&mut self, name: SectionId, data: Vec) -> Self::SectionId; + fn add_debug_reloc( + &mut self, + section_map: &FxHashMap, + from: &Self::SectionId, + reloc: &DebugReloc, + ); +} + +impl WriteDebugInfo for ObjectProduct { + type SectionId = (object::write::SectionId, object::write::SymbolId); + + fn add_debug_section( + &mut self, + id: SectionId, + data: Vec, + ) -> (object::write::SectionId, object::write::SymbolId) { + let name = if self.object.format() == object::BinaryFormat::MachO { + id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info + } else { + id.name().to_string() + } + .into_bytes(); + + let segment = self.object.segment_name(StandardSegment::Debug).to_vec(); + // FIXME use SHT_X86_64_UNWIND for .eh_frame + let section_id = self.object.add_section( + segment, + name, + if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug }, + ); + self.object + .section_mut(section_id) + .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 }); + let symbol_id = self.object.section_symbol(section_id); + (section_id, symbol_id) + } + + fn add_debug_reloc( + &mut self, + section_map: &FxHashMap, + from: &Self::SectionId, + reloc: &DebugReloc, + ) { + let (symbol, symbol_offset) = match reloc.name { + DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0), + DebugRelocName::Symbol(id) => { + let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap())); + self.object + .symbol_section_and_offset(symbol_id) + .expect("Debug reloc for undef sym???") + } + }; + self.object + .add_relocation( + from.0, + Relocation { + offset: u64::from(reloc.offset), + symbol, + kind: reloc.kind, + encoding: RelocationEncoding::Generic, + size: reloc.size * 8, + addend: i64::try_from(symbol_offset).unwrap() + reloc.addend, + }, + ) + .unwrap(); + } +} diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index d1251e749f31f..f0896ea0e167f 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -4,10 +4,11 @@ use crate::prelude::*; use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa}; +use cranelift_object::ObjectProduct; use gimli::write::{Address, CieId, EhFrame, FrameTable, Section}; use gimli::RunTimeEndian; -use crate::backend::WriteDebugInfo; +use super::object::WriteDebugInfo; pub(crate) struct UnwindContext { endian: RunTimeEndian, @@ -55,7 +56,7 @@ impl UnwindContext { } } - pub(crate) fn emit(self, product: &mut P) { + pub(crate) fn emit(self, product: &mut ObjectProduct) { let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian)); self.frame_table.write_eh_frame(&mut eh_frame).unwrap(); diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 3de706ed6d7af..32cc50eebe436 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -6,13 +6,15 @@ use std::path::PathBuf; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{DebugInfo, OutputType}; +use rustc_session::Session; -use cranelift_object::ObjectModule; +use cranelift_codegen::isa::TargetIsa; +use cranelift_object::{ObjectBuilder, ObjectModule}; use crate::{prelude::*, BackendConfig}; @@ -24,6 +26,16 @@ impl HashStable for ModuleCodegenResult { } } +fn make_module(sess: &Session, isa: Box, name: String) -> ObjectModule { + let mut builder = + ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); + // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size + // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections + // can easily double the amount of time necessary to perform linking. + builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false)); + ObjectModule::new(builder) +} + fn emit_module( tcx: TyCtxt<'_>, backend_config: &BackendConfig, @@ -104,7 +116,7 @@ fn module_codegen( let mono_items = cgu.items_in_deterministic_order(tcx); let isa = crate::build_isa(tcx.sess, &backend_config); - let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string()); + let mut module = make_module(tcx.sess, isa, cgu_name.as_str().to_string()); let mut cx = crate::CodegenCx::new( tcx, @@ -227,8 +239,7 @@ pub(crate) fn run_aot( tcx.sess.abort_if_errors(); let isa = crate::build_isa(tcx.sess, &backend_config); - let mut allocator_module = - crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string()); + let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string()); assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type()); let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true); let created_alloc_shim = @@ -266,9 +277,7 @@ pub(crate) fn run_aot( let tmp_file = tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); - let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| { - crate::metadata::write_metadata(tcx, object); - }); + let obj = crate::metadata::new_metadata_object(tcx, &metadata_cgu_name, &metadata); if let Err(err) = std::fs::write(&tmp_file, obj) { tcx.sess.fatal(&format!("error writing metadata object file: {}", err)); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 87193e3ef5341..beb97edf09e89 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -1,4 +1,5 @@ -#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts, once_cell)] +#![feature(rustc_private, decl_macro)] +#![cfg_attr(feature = "jit", feature(never_type, vec_into_raw_parts, once_cell))] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![warn(unreachable_pub)] @@ -29,8 +30,8 @@ use std::any::Any; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::CodegenResults; use rustc_errors::ErrorReported; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_session::config::OutputFilenames; use rustc_session::Session; @@ -44,7 +45,6 @@ mod abi; mod allocator; mod analyze; mod archive; -mod backend; mod base; mod cast; mod codegen_i128; diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs index db24bf65eb5a2..1c8fd0b01d9d9 100644 --- a/compiler/rustc_codegen_cranelift/src/metadata.rs +++ b/compiler/rustc_codegen_cranelift/src/metadata.rs @@ -1,20 +1,76 @@ //! Writing of the rustc metadata for dylibs -use rustc_middle::ty::TyCtxt; +use object::write::{Object, StandardSegment, Symbol, SymbolSection}; +use object::{SectionKind, SymbolFlags, SymbolKind, SymbolScope}; -use crate::backend::WriteMetadata; +use rustc_metadata::EncodedMetadata; +use rustc_middle::ty::TyCtxt; // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112 -pub(crate) fn write_metadata(tcx: TyCtxt<'_>, object: &mut O) { +pub(crate) fn new_metadata_object( + tcx: TyCtxt<'_>, + cgu_name: &str, + metadata: &EncodedMetadata, +) -> Vec { use snap::write::FrameEncoder; use std::io::Write; - let metadata = tcx.encode_metadata(); let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); - FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); + FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap(); + + let triple = crate::target_triple(tcx.sess); + + let binary_format = match triple.binary_format { + target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf, + target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff, + target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO, + binary_format => tcx.sess.fatal(&format!("binary format {} is unsupported", binary_format)), + }; + let architecture = match triple.architecture { + target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64, + target_lexicon::Architecture::Arm(_) => object::Architecture::Arm, + target_lexicon::Architecture::Avr => object::Architecture::Avr, + target_lexicon::Architecture::Hexagon => object::Architecture::Hexagon, + target_lexicon::Architecture::Mips32(_) => object::Architecture::Mips, + target_lexicon::Architecture::Mips64(_) => object::Architecture::Mips64, + target_lexicon::Architecture::Msp430 => object::Architecture::Msp430, + target_lexicon::Architecture::Powerpc => object::Architecture::PowerPc, + target_lexicon::Architecture::Powerpc64 => object::Architecture::PowerPc64, + target_lexicon::Architecture::Powerpc64le => todo!(), + target_lexicon::Architecture::Riscv32(_) => object::Architecture::Riscv32, + target_lexicon::Architecture::Riscv64(_) => object::Architecture::Riscv64, + target_lexicon::Architecture::S390x => object::Architecture::S390x, + target_lexicon::Architecture::Sparc64 => object::Architecture::Sparc64, + target_lexicon::Architecture::Sparcv9 => object::Architecture::Sparc64, + target_lexicon::Architecture::X86_32(_) => object::Architecture::I386, + target_lexicon::Architecture::X86_64 => object::Architecture::X86_64, + architecture => { + tcx.sess.fatal(&format!("target architecture {:?} is unsupported", architecture,)) + } + }; + let endian = match triple.endianness().unwrap() { + target_lexicon::Endianness::Little => object::Endianness::Little, + target_lexicon::Endianness::Big => object::Endianness::Big, + }; + + let mut object = Object::new(binary_format, architecture, endian); + object.add_file_symbol(cgu_name.as_bytes().to_vec()); + + let segment = object.segment_name(StandardSegment::Data).to_vec(); + let section_id = object.add_section(segment, b".rustc".to_vec(), SectionKind::Data); + let offset = object.append_section_data(section_id, &compressed, 1); + // For MachO and probably PE this is necessary to prevent the linker from throwing away the + // .rustc section. For ELF this isn't necessary, but it also doesn't harm. + object.add_symbol(Symbol { + name: rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx).into_bytes(), + value: offset, + size: compressed.len() as u64, + kind: SymbolKind::Data, + scope: SymbolScope::Dynamic, + weak: false, + section: SymbolSection::Section(section_id), + flags: SymbolFlags::None, + }); - object.add_rustc_section( - rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx), - compressed, - ); + object.write().unwrap() } diff --git a/compiler/rustc_codegen_gcc/.github/workflows/main.yml b/compiler/rustc_codegen_gcc/.github/workflows/main.yml new file mode 100644 index 0000000000000..98bed8ef387ff --- /dev/null +++ b/compiler/rustc_codegen_gcc/.github/workflows/main.yml @@ -0,0 +1,96 @@ +name: CI + +on: + - push + - pull_request + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v2 + + - name: Install packages + run: sudo apt-get install ninja-build ripgrep + + - name: Download artifact + uses: dawidd6/action-download-artifact@v2 + with: + workflow: main.yml + name: libgccjit.so + path: gcc-build + repo: antoyo/gcc + + - name: Setup path to libgccjit + run: | + echo $(readlink -f gcc-build) > gcc_path + ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0 + + - name: Set LIBRARY_PATH + run: | + echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV + + # https://github.com/actions/cache/issues/133 + - name: Fixup owner of ~/.cargo/ + # Don't remove the trailing /. It is necessary to follow the symlink. + run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/ + + - name: Cache cargo installed crates + uses: actions/cache@v1.1.2 + with: + path: ~/.cargo/bin + key: cargo-installed-crates2-ubuntu-latest + + - name: Cache cargo registry + uses: actions/cache@v1 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo index + uses: actions/cache@v1 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo target dir + uses: actions/cache@v1.1.2 + with: + path: target + key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }} + + - name: Build + run: | + ./prepare_build.sh + ./build.sh + cargo test + ./clean_all.sh + + - name: Prepare dependencies + run: | + git config --global user.email "user@example.com" + git config --global user.name "User" + ./prepare.sh + + # Compile is a separate step, as the actions-rs/cargo action supports error annotations + - name: Compile + uses: actions-rs/cargo@v1.0.3 + with: + command: build + args: --release + + - 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 + + ./test.sh --release diff --git a/compiler/rustc_codegen_gcc/.gitignore b/compiler/rustc_codegen_gcc/.gitignore new file mode 100644 index 0000000000000..1e2f9e3aebb2c --- /dev/null +++ b/compiler/rustc_codegen_gcc/.gitignore @@ -0,0 +1,20 @@ +target +**/*.rs.bk +*.rlib +*.o +perf.data +perf.data.old +*.events +*.string* +/build_sysroot/sysroot +/build_sysroot/sysroot_src +/build_sysroot/Cargo.lock +/build_sysroot/test_target/Cargo.lock +/rust +/simple-raytracer +/regex +gimple* +*asm +res +test-backend +gcc_path diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock new file mode 100644 index 0000000000000..60a2101c689cc --- /dev/null +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -0,0 +1,373 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ar" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68fda3cff2cce84c19e5dfa5179a4b35d2c0f18b893f108002b8a6a54984acca" +dependencies = [ + "regex", +] + +[[package]] +name = "gccjit" +version = "1.0.0" +source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e" +dependencies = [ + "gccjit_sys", +] + +[[package]] +name = "gccjit_sys" +version = "0.0.1" +source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e" +dependencies = [ + "libc 0.1.12", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc 0.2.102", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc 0.2.102", +] + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "lang_tester" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090" +dependencies = [ + "fm", + "getopts", + "libc 0.2.102", + "num_cpus", + "termcolor", + "threadpool", + "wait-timeout", + "walkdir", +] + +[[package]] +name = "libc" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" + +[[package]] +name = "libc" +version = "0.2.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc 0.2.102", +] + +[[package]] +name = "object" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" +dependencies = [ + "crc32fast", + "indexmap", + "memchr", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc 0.2.102", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rustc_codegen_gcc" +version = "0.1.0" +dependencies = [ + "ar", + "gccjit", + "lang_tester", + "object", + "target-lexicon", + "tempfile", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "target-lexicon" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d" + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc 0.2.102", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc 0.2.102", +] + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml new file mode 100644 index 0000000000000..9e8c195c15f60 --- /dev/null +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "rustc_codegen_gcc" +version = "0.1.0" +authors = ["Antoni Boucher "] +edition = "2018" +license = "MIT OR Apache-2.0" + +[lib] +crate-type = ["dylib"] + +[[test]] +name = "lang_tests" +path = "tests/lib.rs" +harness = false + +[dependencies] +gccjit = { git = "https://github.com/antoyo/gccjit.rs" } + +# Local copy. +#gccjit = { path = "../gccjit.rs" } + +target-lexicon = "0.10.0" + +ar = "0.8.0" + +[dependencies.object] +version = "0.25.0" +default-features = false +features = ["read", "std", "write"] # We don't need WASM support. + +[dev-dependencies] +lang_tester = "0.3.9" +tempfile = "3.1.0" + +[profile.dev] +# By compiling dependencies with optimizations, performing tests gets much faster. +opt-level = 3 + +[profile.dev.package.rustc_codegen_gcc] +# Disabling optimizations for cg_gccjit itself makes compilation after a change faster. +opt-level = 0 + +# Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the +# execution time of build scripts is so fast that optimizing them slows down the total build time. +[profile.dev.build-override] +opt-level = 0 +debug = false + +[profile.release.build-override] +opt-level = 0 +debug = false diff --git a/compiler/rustc_codegen_gcc/LICENSE-APACHE b/compiler/rustc_codegen_gcc/LICENSE-APACHE new file mode 100644 index 0000000000000..1b5ec8b78e237 --- /dev/null +++ b/compiler/rustc_codegen_gcc/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/compiler/rustc_codegen_gcc/LICENSE-MIT b/compiler/rustc_codegen_gcc/LICENSE-MIT new file mode 100644 index 0000000000000..31aa79387f27e --- /dev/null +++ b/compiler/rustc_codegen_gcc/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md new file mode 100644 index 0000000000000..709d93c6edb05 --- /dev/null +++ b/compiler/rustc_codegen_gcc/Readme.md @@ -0,0 +1,135 @@ +# WIP libgccjit codegen backend for rust + +This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used. + +**Despite its name, libgccjit can be used for ahead-of-time compilation, as is used here.** + +## Motivation + +The primary goal of this project is to be able to compile Rust code on platforms unsupported by LLVM. +A secondary goal is to check if using the gcc backend will provide any run-time speed improvement for the programs compiled using rustc. + +## Building + +**This requires a patched libgccjit in order to work. +The patches in [this repostory](https://github.com/antoyo/libgccjit-patches) need to be applied. +(Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.) +You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.** + +**Put the path to your custom build of libgccjit in the file `gcc_path`.** + +```bash +$ git clone https://github.com/rust-lang/rustc_codegen_gcc.git +$ cd rustc_codegen_gcc +$ ./prepare_build.sh # download and patch sysroot src +$ ./build.sh --release +``` + +To run the tests: + +```bash +$ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking +$ ./test.sh --release +``` + +## Usage + +`$cg_gccjit_dir` is the directory you cloned this repo into in the following instructions. + +### Cargo + +```bash +$ CHANNEL="release" $cg_gccjit_dir/cargo.sh run +``` + +If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely. + +### Rustc + +> You should prefer using the Cargo method. + +```bash +$ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$cg_gccjit_dir/target/release/librustc_codegen_gcc.so --sysroot $cg_gccjit_dir/build_sysroot/sysroot my_crate.rs +``` + +## Env vars + +
+
CG_GCCJIT_INCR_CACHE_DISABLED
+
Don't cache object files in the incremental cache. Useful during development of cg_gccjit + to make it possible to use incremental mode for all analyses performed by rustc without caching + object files when their content should have been changed by a change to cg_gccjit.
+
CG_GCCJIT_DISPLAY_CG_TIME
+
Display the time it took to perform codegen for a crate
+
+ +## Debugging + +Sometimes, libgccjit will crash and output an error like this: + +``` +during RTL pass: expand +libgccjit.so: error: in expmed_mode_index, at expmed.h:249 +0x7f0da2e61a35 expmed_mode_index + ../../../gcc/gcc/expmed.h:249 +0x7f0da2e61aa4 expmed_op_cost_ptr + ../../../gcc/gcc/expmed.h:271 +0x7f0da2e620dc sdiv_cost_ptr + ../../../gcc/gcc/expmed.h:540 +0x7f0da2e62129 sdiv_cost + ../../../gcc/gcc/expmed.h:558 +0x7f0da2e73c12 expand_divmod(int, tree_code, machine_mode, rtx_def*, rtx_def*, rtx_def*, int) + ../../../gcc/gcc/expmed.c:4335 +0x7f0da2ea1423 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier) + ../../../gcc/gcc/expr.c:9240 +0x7f0da2cd1a1e expand_gimple_stmt_1 + ../../../gcc/gcc/cfgexpand.c:3796 +0x7f0da2cd1c30 expand_gimple_stmt + ../../../gcc/gcc/cfgexpand.c:3857 +0x7f0da2cd90a9 expand_gimple_basic_block + ../../../gcc/gcc/cfgexpand.c:5898 +0x7f0da2cdade8 execute + ../../../gcc/gcc/cfgexpand.c:6582 +``` + +To see the code which causes this error, call the following function: + +```c +gcc_jit_context_dump_to_file(ctxt, "/tmp/output.c", 1 /* update_locations */) +``` + +This will create a C-like file and add the locations into the IR pointing to this C file. +Then, rerun the program and it will output the location in the second line: + +``` +libgccjit.so: /tmp/something.c:61322:0: error: in expmed_mode_index, at expmed.h:249 +``` + +Or add a breakpoint to `add_error` in gdb and print the line number using: + +``` +p loc->m_line +``` + +### How to use a custom-build rustc + + * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). + * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`. + +### How to build a cross-compiling libgccjit + +#### Building libgccjit + + * Follow these instructions: https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ with the following changes: + * Configure gcc with `../gcc/configure --enable-host-shared --disable-multilib --enable-languages=c,jit,c++ --disable-bootstrap --enable-checking=release --prefix=/opt/m68k-gcc/ --target=m68k-linux --without-headers`. + * Some shells, like fish, don't define the environment variable `$MACHTYPE`. + * Add `CFLAGS="-Wno-error=attributes -g -O2"` at the end of the configure command for building glibc (`CFLAGS="-Wno-error=attributes -Wno-error=array-parameter -Wno-error=stringop-overflow -Wno-error=array-bounds -g -O2"` for glibc 2.31, which is useful for Debian). + +#### Configuring rustc_codegen_gcc + + * Set `TARGET_TRIPLE="m68k-unknown-linux-gnu"` in config.sh. + * Since rustc doesn't support this architecture yet, set it back to `TARGET_TRIPLE="mips-unknown-linux-gnu"` (or another target having the same attributes). Alternatively, create a [target specification file](https://book.avr-rust.com/005.1-the-target-specification-json-file.html) (note that the `arch` specified in this file must be supported by the rust compiler). + * Set `linker='-Clinker=m68k-linux-gcc'`. + * Set the path to the cross-compiling libgccjit in `gcc_path`. + * Disable the 128-bit integer types if the target doesn't support them by using `let i128_type = context.new_type::();` in `context.rs` (same for u128_type). + * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?). diff --git a/compiler/rustc_codegen_gcc/build.sh b/compiler/rustc_codegen_gcc/build.sh new file mode 100755 index 0000000000000..17a0d2ab3f060 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +#set -x +set -e + +if [ -f ./gcc_path ]; then + export GCC_PATH=$(cat gcc_path) +else + echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details' + exit 1 +fi + +export LD_LIBRARY_PATH="$GCC_PATH" +export LIBRARY_PATH="$GCC_PATH" + +if [[ "$1" == "--release" ]]; then + export CHANNEL='release' + CARGO_INCREMENTAL=1 cargo rustc --release +else + echo $LD_LIBRARY_PATH + export CHANNEL='debug' + cargo rustc +fi + +source config.sh + +rm -r target/out || true +mkdir -p target/out/gccjit + +echo "[BUILD] sysroot" +time ./build_sysroot/build_sysroot.sh $CHANNEL diff --git a/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml new file mode 100644 index 0000000000000..cfadf47cc3f86 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["bjorn3 "] +name = "sysroot" +version = "0.0.0" + +[dependencies] +core = { path = "./sysroot_src/library/core" } +compiler_builtins = "0.1" +alloc = { path = "./sysroot_src/library/alloc" } +std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] } +test = { path = "./sysroot_src/library/test" } + +[patch.crates-io] +rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" } +rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" } +rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" } + +[profile.release] +debug = true diff --git a/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh new file mode 100755 index 0000000000000..d1dcf495db8a3 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Requires the CHANNEL env var to be set to `debug` or `release.` + +set -e +cd $(dirname "$0") + +pushd ../ >/dev/null +source ./config.sh +popd >/dev/null + +# Cleanup for previous run +# v Clean target dir except for build scripts and incremental cache +rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true +rm Cargo.lock test_target/Cargo.lock 2>/dev/null || true +rm -r sysroot/ 2>/dev/null || true + +# Build libs +export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked -Cpanic=abort" +if [[ "$1" == "--release" ]]; then + sysroot_channel='release' + RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target $TARGET_TRIPLE --release +else + sysroot_channel='debug' + cargo build --target $TARGET_TRIPLE +fi + +# Copy files to sysroot +mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ +cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/ diff --git a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh new file mode 100755 index 0000000000000..071e7ed1f85df --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -e +cd $(dirname "$0") + +SRC_DIR=$(dirname $(rustup which rustc))"/../lib/rustlib/src/rust/" +DST_DIR="sysroot_src" + +if [ ! -e $SRC_DIR ]; then + echo "Please install rust-src component" + exit 1 +fi + +rm -rf $DST_DIR +mkdir -p $DST_DIR/library +cp -r $SRC_DIR/library $DST_DIR/ + +pushd $DST_DIR +echo "[GIT] init" +git init +echo "[GIT] add" +git add . +echo "[GIT] commit" + +# This is needed on systems where nothing is configured. +# git really needs something here, or it will fail. +# Even using --author is not enough. +git config user.email || git config user.email "none@example.com" +git config user.name || git config user.name "None" + +git commit -m "Initial commit" -q +for file in $(ls ../../patches/ | grep -v patcha); do +echo "[GIT] apply" $file +git apply ../../patches/$file +git add -A +git commit --no-gpg-sign -m "Patch $file" +done +popd + +echo "Successfully prepared libcore for building" diff --git a/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs b/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs new file mode 100644 index 0000000000000..0c9ac1ac8e4bd --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs @@ -0,0 +1 @@ +#![no_std] diff --git a/compiler/rustc_codegen_gcc/cargo.sh b/compiler/rustc_codegen_gcc/cargo.sh new file mode 100755 index 0000000000000..1001c522052c8 --- /dev/null +++ b/compiler/rustc_codegen_gcc/cargo.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ -z $CHANNEL ]; then +export CHANNEL='debug' +fi + +pushd $(dirname "$0") >/dev/null +source config.sh + +# read nightly compiler from rust-toolchain file +TOOLCHAIN=$(cat rust-toolchain) + +popd >/dev/null + +if [[ $(rustc -V) != $(rustc +${TOOLCHAIN} -V) ]]; then + echo "rustc_codegen_gcc is build for $(rustc +${TOOLCHAIN} -V) but the default rustc version is $(rustc -V)." + echo "Using $(rustc +${TOOLCHAIN} -V)." +fi + +cmd=$1 +shift + +RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd --target $TARGET_TRIPLE $@ diff --git a/compiler/rustc_codegen_gcc/clean_all.sh b/compiler/rustc_codegen_gcc/clean_all.sh new file mode 100755 index 0000000000000..a77d1486fe283 --- /dev/null +++ b/compiler/rustc_codegen_gcc/clean_all.sh @@ -0,0 +1,5 @@ +#!/bin/bash --verbose +set -e + +rm -rf target/ build_sysroot/{sysroot/,sysroot_src/,target/,Cargo.lock} perf.data{,.old} +rm -rf regex/ simple-raytracer/ diff --git a/compiler/rustc_codegen_gcc/config.sh b/compiler/rustc_codegen_gcc/config.sh new file mode 100644 index 0000000000000..87df2f2102bcd --- /dev/null +++ b/compiler/rustc_codegen_gcc/config.sh @@ -0,0 +1,52 @@ +set -e + +export CARGO_INCREMENTAL=0 + +if [ -f ./gcc_path ]; then + export GCC_PATH=$(cat gcc_path) +else + echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details' + exit 1 +fi + +unamestr=`uname` +if [[ "$unamestr" == 'Linux' ]]; then + dylib_ext='so' +elif [[ "$unamestr" == 'Darwin' ]]; then + dylib_ext='dylib' +else + echo "Unsupported os" + exit 1 +fi + +HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ") +TARGET_TRIPLE=$HOST_TRIPLE +#TARGET_TRIPLE="m68k-unknown-linux-gnu" + +linker='' +RUN_WRAPPER='' +if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then + if [[ "$TARGET_TRIPLE" == "m68k-unknown-linux-gnu" ]]; then + TARGET_TRIPLE="mips-unknown-linux-gnu" + linker='-Clinker=m68k-linux-gcc' + elif [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then + # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. + linker='-Clinker=aarch64-linux-gnu-gcc' + RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu' + else + echo "Unknown non-native platform" + fi +fi + +export RUSTFLAGS="$linker -Cpanic=abort -Zsymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot" + +# FIXME(antoyo): remove once the atomic shim is gone +if [[ `uname` == 'Darwin' ]]; then + export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" +fi + +RUSTC="rustc $RUSTFLAGS -L crate=target/out --out-dir target/out" +export RUSTC_LOG=warn # display metadata load errors + +export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib:$GCC_PATH" +export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs new file mode 100644 index 0000000000000..bc6dd007ba010 --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs @@ -0,0 +1,41 @@ +#![feature(start, box_syntax, core_intrinsics, alloc_prelude, alloc_error_handler)] +#![no_std] + +extern crate alloc; +extern crate alloc_system; + +use alloc::prelude::v1::*; + +use alloc_system::System; + +#[global_allocator] +static ALLOC: System = System; + +#[link(name = "c")] +extern "C" { + fn puts(s: *const u8) -> i32; +} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + unsafe { + core::intrinsics::abort(); + } +} + +#[alloc_error_handler] +fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { + unsafe { + core::intrinsics::abort(); + } +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + let world: Box<&str> = box "Hello World!\0"; + unsafe { + puts(*world as *const str as *const u8); + } + + 0 +} diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs new file mode 100644 index 0000000000000..5f66ca67f2d40 --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs @@ -0,0 +1,212 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![no_std] +#![feature(allocator_api, rustc_private)] +#![cfg_attr(any(unix, target_os = "redox"), feature(libc))] + +// The minimum alignment guaranteed by the architecture. This value is used to +// add fast paths for low alignment values. +#[cfg(all(any(target_arch = "x86", + target_arch = "arm", + target_arch = "mips", + target_arch = "powerpc", + target_arch = "powerpc64")))] +const MIN_ALIGN: usize = 8; +#[cfg(all(any(target_arch = "x86_64", + target_arch = "aarch64", + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64")))] +const MIN_ALIGN: usize = 16; + +pub struct System; +#[cfg(any(windows, unix, target_os = "redox"))] +mod realloc_fallback { + use core::alloc::{GlobalAlloc, Layout}; + use core::cmp; + use core::ptr; + impl super::System { + pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout, + new_size: usize) -> *mut u8 { + // Docs for GlobalAlloc::realloc require this to be valid: + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + let new_ptr = GlobalAlloc::alloc(self, new_layout); + if !new_ptr.is_null() { + let size = cmp::min(old_layout.size(), new_size); + ptr::copy_nonoverlapping(ptr, new_ptr, size); + GlobalAlloc::dealloc(self, ptr, old_layout); + } + new_ptr + } + } +} +#[cfg(any(unix, target_os = "redox"))] +mod platform { + extern crate libc; + use core::ptr; + use MIN_ALIGN; + use System; + use core::alloc::{GlobalAlloc, Layout}; + unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::malloc(layout.size()) as *mut u8 + } else { + #[cfg(target_os = "macos")] + { + if layout.align() > (1 << 31) { + return ptr::null_mut() + } + } + aligned_malloc(&layout) + } + } + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::calloc(layout.size(), 1) as *mut u8 + } else { + let ptr = self.alloc(layout.clone()); + if !ptr.is_null() { + ptr::write_bytes(ptr, 0, layout.size()); + } + ptr + } + } + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + libc::free(ptr as *mut libc::c_void) + } + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + } else { + self.realloc_fallback(ptr, layout, new_size) + } + } + } + #[cfg(any(target_os = "android", + target_os = "hermit", + target_os = "redox", + target_os = "solaris"))] + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + // On android we currently target API level 9 which unfortunately + // doesn't have the `posix_memalign` API used below. Instead we use + // `memalign`, but this unfortunately has the property on some systems + // where the memory returned cannot be deallocated by `free`! + // + // Upon closer inspection, however, this appears to work just fine with + // Android, so for this platform we should be fine to call `memalign` + // (which is present in API level 9). Some helpful references could + // possibly be chromium using memalign [1], attempts at documenting that + // memalign + free is ok [2] [3], or the current source of chromium + // which still uses memalign on android [4]. + // + // [1]: https://codereview.chromium.org/10796020/ + // [2]: https://code.google.com/p/android/issues/detail?id=35391 + // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 + // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ + // /memory/aligned_memory.cc + libc::memalign(layout.align(), layout.size()) as *mut u8 + } + #[cfg(not(any(target_os = "android", + target_os = "hermit", + target_os = "redox", + target_os = "solaris")))] + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + let mut out = ptr::null_mut(); + let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); + if ret != 0 { + ptr::null_mut() + } else { + out as *mut u8 + } + } +} +#[cfg(windows)] +#[allow(nonstandard_style)] +mod platform { + use MIN_ALIGN; + use System; + use core::alloc::{GlobalAlloc, Layout}; + type LPVOID = *mut u8; + type HANDLE = LPVOID; + type SIZE_T = usize; + type DWORD = u32; + type BOOL = i32; + extern "system" { + fn GetProcessHeap() -> HANDLE; + fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; + fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; + fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; + fn GetLastError() -> DWORD; + } + #[repr(C)] + struct Header(*mut u8); + const HEAP_ZERO_MEMORY: DWORD = 0x00000008; + unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header { + &mut *(ptr as *mut Header).offset(-1) + } + unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 { + let aligned = ptr.add(align - (ptr as usize & (align - 1))); + *get_header(aligned) = Header(ptr); + aligned + } + #[inline] + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 { + let ptr = if layout.align() <= MIN_ALIGN { + HeapAlloc(GetProcessHeap(), flags, layout.size()) + } else { + let size = layout.size() + layout.align(); + let ptr = HeapAlloc(GetProcessHeap(), flags, size); + if ptr.is_null() { + ptr + } else { + align_ptr(ptr, layout.align()) + } + }; + ptr as *mut u8 + } + unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + allocate_with_flags(layout, 0) + } + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + allocate_with_flags(layout, HEAP_ZERO_MEMORY) + } + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + if layout.align() <= MIN_ALIGN { + let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); + debug_assert!(err != 0, "Failed to free heap memory: {}", + GetLastError()); + } else { + let header = get_header(ptr); + let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); + debug_assert!(err != 0, "Failed to free heap memory: {}", + GetLastError()); + } + } + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if layout.align() <= MIN_ALIGN { + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8 + } else { + self.realloc_fallback(ptr, layout, new_size) + } + } + } +} diff --git a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs new file mode 100644 index 0000000000000..ddeb752f93ed7 --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs @@ -0,0 +1,69 @@ +// Adapted from rustc run-pass test suite + +#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] +#![feature(rustc_attrs)] + +use std::{ + ops::{Deref, CoerceUnsized, DispatchFromDyn}, + marker::Unsize, +}; + +struct Ptr(Box); + +impl Deref for Ptr { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} + +impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} +impl + ?Sized, U: ?Sized> DispatchFromDyn> for Ptr {} + +struct Wrapper(T); + +impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl, U> CoerceUnsized> for Wrapper {} +impl, U> DispatchFromDyn> for Wrapper {} + + +trait Trait { + // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable + // without unsized_locals), but wrappers arond `Self` currently are not. + // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented + // fn wrapper(self: Wrapper) -> i32; + fn ptr_wrapper(self: Ptr>) -> i32; + fn wrapper_ptr(self: Wrapper>) -> i32; + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; +} + +impl Trait for i32 { + fn ptr_wrapper(self: Ptr>) -> i32 { + **self + } + fn wrapper_ptr(self: Wrapper>) -> i32 { + **self + } + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32 { + ***self + } +} + +fn main() { + let pw = Ptr(Box::new(Wrapper(5))) as Ptr>; + assert_eq!(pw.ptr_wrapper(), 5); + + let wp = Wrapper(Ptr(Box::new(6))) as Wrapper>; + assert_eq!(wp.wrapper_ptr(), 6); + + let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper>>; + assert_eq!(wpw.wrapper_ptr_wrapper(), 7); +} diff --git a/compiler/rustc_codegen_gcc/example/dst-field-align.rs b/compiler/rustc_codegen_gcc/example/dst-field-align.rs new file mode 100644 index 0000000000000..6c338e99912ec --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/dst-field-align.rs @@ -0,0 +1,67 @@ +// run-pass +#![allow(dead_code)] +struct Foo { + a: u16, + b: T +} + +trait Bar { + fn get(&self) -> usize; +} + +impl Bar for usize { + fn get(&self) -> usize { *self } +} + +struct Baz { + a: T +} + +struct HasDrop { + ptr: Box, + data: T +} + +fn main() { + // Test that zero-offset works properly + let b : Baz = Baz { a: 7 }; + assert_eq!(b.a.get(), 7); + let b : &Baz = &b; + assert_eq!(b.a.get(), 7); + + // Test that the field is aligned properly + let f : Foo = Foo { a: 0, b: 11 }; + assert_eq!(f.b.get(), 11); + let ptr1 : *const u8 = &f.b as *const _ as *const u8; + + let f : &Foo = &f; + let ptr2 : *const u8 = &f.b as *const _ as *const u8; + assert_eq!(f.b.get(), 11); + + // The pointers should be the same + assert_eq!(ptr1, ptr2); + + // Test that nested DSTs work properly + let f : Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 }}; + assert_eq!(f.b.b.get(), 17); + let f : &Foo> = &f; + assert_eq!(f.b.b.get(), 17); + + // Test that get the pointer via destructuring works + + let f : Foo = Foo { a: 0, b: 11 }; + let f : &Foo = &f; + let &Foo { a: _, b: ref bar } = f; + assert_eq!(bar.get(), 11); + + // Make sure that drop flags don't screw things up + + let d : HasDrop> = HasDrop { + ptr: Box::new(0), + data: Baz { a: [1,2,3,4] } + }; + assert_eq!([1,2,3,4], d.data.a); + + let d : &HasDrop> = &d; + assert_eq!(&[1,2,3,4], &d.data.a); +} diff --git a/compiler/rustc_codegen_gcc/example/example.rs b/compiler/rustc_codegen_gcc/example/example.rs new file mode 100644 index 0000000000000..5878e8548d926 --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/example.rs @@ -0,0 +1,208 @@ +#![feature(no_core, unboxed_closures)] +#![no_core] +#![allow(dead_code)] + +extern crate mini_core; + +use mini_core::*; + +fn abc(a: u8) -> u8 { + a * 2 +} + +fn bcd(b: bool, a: u8) -> u8 { + if b { + a * 2 + } else { + a * 3 + } +} + +fn call() { + abc(42); +} + +fn indirect_call() { + let f: fn() = call; + f(); +} + +enum BoolOption { + Some(bool), + None, +} + +fn option_unwrap_or(o: BoolOption, d: bool) -> bool { + match o { + BoolOption::Some(b) => b, + BoolOption::None => d, + } +} + +fn ret_42() -> u8 { + 42 +} + +fn return_str() -> &'static str { + "hello world" +} + +fn promoted_val() -> &'static u8 { + &(1 * 2) +} + +fn cast_ref_to_raw_ptr(abc: &u8) -> *const u8 { + abc as *const u8 +} + +fn cmp_raw_ptr(a: *const u8, b: *const u8) -> bool { + a == b +} + +fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) { + ( + a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8, + b as u32, + ) +} + +fn char_cast(c: char) -> u8 { + c as u8 +} + +pub struct DebugTuple(()); + +fn debug_tuple() -> DebugTuple { + DebugTuple(()) +} + +fn size_of() -> usize { + intrinsics::size_of::() +} + +fn use_size_of() -> usize { + size_of::() +} + +unsafe fn use_copy_intrinsic(src: *const u8, dst: *mut u8) { + intrinsics::copy::(src, dst, 1); +} + +unsafe fn use_copy_intrinsic_ref(src: *const u8, dst: *mut u8) { + let copy2 = &intrinsics::copy::; + copy2(src, dst, 1); +} + +const ABC: u8 = 6 * 7; + +fn use_const() -> u8 { + ABC +} + +pub fn call_closure_3arg() { + (|_, _, _| {})(0u8, 42u16, 0u8) +} + +pub fn call_closure_2arg() { + (|_, _| {})(0u8, 42u16) +} + +struct IsNotEmpty; + +impl<'a, 'b> FnOnce<(&'a &'b [u16],)> for IsNotEmpty { + type Output = (u8, u8); + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u16],)) -> (u8, u8) { + self.call_mut(arg) + } +} + +impl<'a, 'b> FnMut<(&'a &'b [u16],)> for IsNotEmpty { + #[inline] + extern "rust-call" fn call_mut(&mut self, _arg: (&'a &'b [u16],)) -> (u8, u8) { + (0, 42) + } +} + +pub fn call_is_not_empty() { + IsNotEmpty.call_once((&(&[0u16] as &[_]),)); +} + +fn eq_char(a: char, b: char) -> bool { + a == b +} + +unsafe fn transmute(c: char) -> u32 { + intrinsics::transmute(c) +} + +unsafe fn deref_str_ptr(s: *const str) -> &'static str { + &*s +} + +fn use_array(arr: [u8; 3]) -> u8 { + arr[1] +} + +fn repeat_array() -> [u8; 3] { + [0; 3] +} + +fn array_as_slice(arr: &[u8; 3]) -> &[u8] { + arr +} + +unsafe fn use_ctlz_nonzero(a: u16) -> u16 { + intrinsics::ctlz_nonzero(a) +} + +fn ptr_as_usize(ptr: *const u8) -> usize { + ptr as usize +} + +fn float_cast(a: f32, b: f64) -> (f64, f32) { + (a as f64, b as f32) +} + +fn int_to_float(a: u8, b: i32) -> (f64, f32) { + (a as f64, b as f32) +} + +fn make_array() -> [u8; 3] { + [42, 0, 5] +} + +fn some_promoted_tuple() -> &'static (&'static str, &'static str) { + &("abc", "some") +} + +fn index_slice(s: &[u8]) -> u8 { + s[2] +} + +pub struct StrWrapper { + s: str, +} + +fn str_wrapper_get(w: &StrWrapper) -> &str { + &w.s +} + +fn i16_as_i8(a: i16) -> i8 { + a as i8 +} + +struct Unsized(u8, str); + +fn get_sized_field_ref_from_unsized_type(u: &Unsized) -> &u8 { + &u.0 +} + +fn get_unsized_field_ref_from_unsized_type(u: &Unsized) -> &str { + &u.1 +} + +pub fn reuse_byref_argument_storage(a: (u8, u16, u32)) -> u8 { + a.0 +} diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs new file mode 100644 index 0000000000000..1067cee881487 --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -0,0 +1,585 @@ +#![feature( + no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, + untagged_unions, decl_macro, rustc_attrs, transparent_unions, auto_traits, + thread_local +)] +#![no_core] +#![allow(dead_code)] + +#[no_mangle] +unsafe extern "C" fn _Unwind_Resume() { + intrinsics::unreachable(); +} + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "unsize"] +pub trait Unsize {} + +#[lang = "coerce_unsized"] +pub trait CoerceUnsized {} + +impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + +#[lang = "dispatch_from_dyn"] +pub trait DispatchFromDyn {} + +// &T -> &U +impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} +// &mut T -> &mut U +impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} +// *const T -> *const U +impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} +// *mut T -> *mut U +impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} +impl, U: ?Sized> DispatchFromDyn> for Box {} + +#[lang = "receiver"] +pub trait Receiver {} + +impl Receiver for &T {} +impl Receiver for &mut T {} +impl Receiver for Box {} + +#[lang = "copy"] +pub unsafe trait Copy {} + +unsafe impl Copy for bool {} +unsafe impl Copy for u8 {} +unsafe impl Copy for u16 {} +unsafe impl Copy for u32 {} +unsafe impl Copy for u64 {} +unsafe impl Copy for usize {} +unsafe impl Copy for i8 {} +unsafe impl Copy for i16 {} +unsafe impl Copy for i32 {} +unsafe impl Copy for isize {} +unsafe impl Copy for f32 {} +unsafe impl Copy for char {} +unsafe impl<'a, T: ?Sized> Copy for &'a T {} +unsafe impl Copy for *const T {} +unsafe impl Copy for *mut T {} + +#[lang = "sync"] +pub unsafe trait Sync {} + +unsafe impl Sync for bool {} +unsafe impl Sync for u8 {} +unsafe impl Sync for u16 {} +unsafe impl Sync for u32 {} +unsafe impl Sync for u64 {} +unsafe impl Sync for usize {} +unsafe impl Sync for i8 {} +unsafe impl Sync for i16 {} +unsafe impl Sync for i32 {} +unsafe impl Sync for isize {} +unsafe impl Sync for char {} +unsafe impl<'a, T: ?Sized> Sync for &'a T {} +unsafe impl Sync for [u8; 16] {} + +#[lang = "freeze"] +unsafe auto trait Freeze {} + +unsafe impl Freeze for PhantomData {} +unsafe impl Freeze for *const T {} +unsafe impl Freeze for *mut T {} +unsafe impl Freeze for &T {} +unsafe impl Freeze for &mut T {} + +#[lang = "structural_peq"] +pub trait StructuralPartialEq {} + +#[lang = "structural_teq"] +pub trait StructuralEq {} + +#[lang = "not"] +pub trait Not { + type Output; + + fn not(self) -> Self::Output; +} + +impl Not for bool { + type Output = bool; + + fn not(self) -> bool { + !self + } +} + +#[lang = "mul"] +pub trait Mul { + type Output; + + #[must_use] + fn mul(self, rhs: RHS) -> Self::Output; +} + +impl Mul for u8 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +impl Mul for usize { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +#[lang = "add"] +pub trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +#[lang = "rem"] +pub trait Rem { + type Output; + + fn rem(self, rhs: RHS) -> Self::Output; +} + +impl Rem for usize { + type Output = Self; + + fn rem(self, rhs: Self) -> Self { + self % rhs + } +} + +#[lang = "bitor"] +pub trait BitOr { + type Output; + + #[must_use] + fn bitor(self, rhs: RHS) -> Self::Output; +} + +impl BitOr for bool { + type Output = bool; + + fn bitor(self, rhs: bool) -> bool { + self | rhs + } +} + +impl<'a> BitOr for &'a bool { + type Output = bool; + + fn bitor(self, rhs: bool) -> bool { + *self | rhs + } +} + +#[lang = "eq"] +pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + fn ne(&self, other: &Rhs) -> bool; +} + +impl PartialEq for u8 { + fn eq(&self, other: &u8) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u8) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for u16 { + fn eq(&self, other: &u16) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u16) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for u32 { + fn eq(&self, other: &u32) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u32) -> bool { + (*self) != (*other) + } +} + + +impl PartialEq for u64 { + fn eq(&self, other: &u64) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u64) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for usize { + fn eq(&self, other: &usize) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &usize) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for i8 { + fn eq(&self, other: &i8) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &i8) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &i32) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &i32) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for isize { + fn eq(&self, other: &isize) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &isize) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for char { + fn eq(&self, other: &char) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &char) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for *const T { + fn eq(&self, other: &*const T) -> bool { + *self == *other + } + fn ne(&self, other: &*const T) -> bool { + *self != *other + } +} + +#[lang = "neg"] +pub trait Neg { + type Output; + + fn neg(self) -> Self::Output; +} + +impl Neg for i8 { + type Output = i8; + + fn neg(self) -> i8 { + -self + } +} + +impl Neg for i16 { + type Output = i16; + + fn neg(self) -> i16 { + self + } +} + +impl Neg for isize { + type Output = isize; + + fn neg(self) -> isize { + -self + } +} + +impl Neg for f32 { + type Output = f32; + + fn neg(self) -> f32 { + -self + } +} + +pub enum Option { + Some(T), + None, +} + +pub use Option::*; + +#[lang = "phantom_data"] +pub struct PhantomData; + +#[lang = "fn_once"] +#[rustc_paren_sugar] +pub trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +#[lang = "fn_mut"] +#[rustc_paren_sugar] +pub trait FnMut: FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[lang = "panic"] +#[track_caller] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\n\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_bounds_check"] +#[track_caller] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +#[lang = "eh_personality"] +fn eh_personality() -> ! { + loop {} +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "deref"] +pub trait Deref { + type Target: ?Sized; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "owned_box"] +pub struct Box(*mut T); + +impl, U: ?Sized> CoerceUnsized> for Box {} + +impl Drop for Box { + fn drop(&mut self) { + // drop is currently performed by compiler. + } +} + +impl Deref for Box { + type Target = T; + + fn deref(&self) -> &Self::Target { + &**self + } +} + +#[lang = "exchange_malloc"] +unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { + libc::malloc(size) +} + +#[lang = "box_free"] +unsafe fn box_free(ptr: *mut T) { + libc::free(ptr as *mut u8); +} + +#[lang = "drop"] +pub trait Drop { + fn drop(&mut self); +} + +#[lang = "manually_drop"] +#[repr(transparent)] +pub struct ManuallyDrop { + pub value: T, +} + +#[lang = "maybe_uninit"] +#[repr(transparent)] +pub union MaybeUninit { + pub uninit: (), + pub value: ManuallyDrop, +} + +pub mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + pub fn size_of() -> usize; + pub fn size_of_val(val: *const T) -> usize; + pub fn min_align_of() -> usize; + pub fn min_align_of_val(val: *const T) -> usize; + pub fn copy(src: *const T, dst: *mut T, count: usize); + pub fn transmute(e: T) -> U; + pub fn ctlz_nonzero(x: T) -> T; + pub fn needs_drop() -> bool; + pub fn bitreverse(x: T) -> T; + pub fn bswap(x: T) -> T; + pub fn write_bytes(dst: *mut T, val: u8, count: usize); + pub fn unreachable() -> !; + } +} + +pub mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn printf(format: *const i8, ...) -> i32; + pub fn malloc(size: usize) -> *mut u8; + pub fn free(ptr: *mut u8); + pub fn memcpy(dst: *mut u8, src: *const u8, size: usize); + pub fn memmove(dst: *mut u8, src: *const u8, size: usize); + pub fn strncpy(dst: *mut u8, src: *const u8, size: usize); + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +extern { + type VaListImpl; +} + +#[lang = "va_list"] +#[repr(transparent)] +pub struct VaList<'a>(&'a mut VaListImpl); + +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro stringify($($t:tt)*) { /* compiler built-in */ } + +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro file() { /* compiler built-in */ } + +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro line() { /* compiler built-in */ } + +#[rustc_builtin_macro] +#[rustc_macro_transparency = "semitransparent"] +pub macro cfg() { /* compiler built-in */ } + +pub static A_STATIC: u8 = 42; + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[no_mangle] +pub fn get_tls() -> u8 { + #[thread_local] + static A: u8 = 42; + + A +} diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs new file mode 100644 index 0000000000000..69d591565acfa --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -0,0 +1,424 @@ +// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs + +#![feature( + no_core, unboxed_closures, start, lang_items, box_syntax, never_type, linkage, + extern_types, thread_local +)] +#![no_core] +#![allow(dead_code, non_camel_case_types)] + +extern crate mini_core; + +use mini_core::*; +use mini_core::libc::*; + +unsafe extern "C" fn my_puts(s: *const u8) { + puts(s); +} + +#[lang = "termination"] +trait Termination { + fn report(self) -> i32; +} + +impl Termination for () { + fn report(self) -> i32 { + unsafe { + NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44 + *NUM_REF as i32 + } + } +} + +trait SomeTrait { + fn object_safe(&self); +} + +impl SomeTrait for &'static str { + fn object_safe(&self) { + unsafe { + puts(*self as *const str as *const u8); + } + } +} + +struct NoisyDrop { + text: &'static str, + inner: NoisyDropInner, +} + +struct NoisyDropInner; + +impl Drop for NoisyDrop { + fn drop(&mut self) { + unsafe { + puts(self.text as *const str as *const u8); + } + } +} + +impl Drop for NoisyDropInner { + fn drop(&mut self) { + unsafe { + puts("Inner got dropped!\0" as *const str as *const u8); + } + } +} + +impl SomeTrait for NoisyDrop { + fn object_safe(&self) {} +} + +enum Ordering { + Less = -1, + Equal = 0, + Greater = 1, +} + +#[lang = "start"] +fn start( + main: fn() -> T, + argc: isize, + argv: *const *const u8, +) -> isize { + if argc == 3 { + unsafe { puts(*argv); } + unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const u8)); } + unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const u8)); } + } + + main().report(); + 0 +} + +static mut NUM: u8 = 6 * 7; +static NUM_REF: &'static u8 = unsafe { &NUM }; + +macro_rules! assert { + ($e:expr) => { + if !$e { + panic(stringify!(! $e)); + } + }; +} + +macro_rules! assert_eq { + ($l:expr, $r: expr) => { + if $l != $r { + panic(stringify!($l != $r)); + } + } +} + +struct Unique { + pointer: *const T, + _marker: PhantomData, +} + +impl CoerceUnsized> for Unique where T: Unsize {} + +unsafe fn zeroed() -> T { + let mut uninit = MaybeUninit { uninit: () }; + intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1); + uninit.value.value +} + +fn take_f32(_f: f32) {} +fn take_unique(_u: Unique<()>) {} + +fn return_u128_pair() -> (u128, u128) { + (0, 0) +} + +fn call_return_u128_pair() { + return_u128_pair(); +} + +fn main() { + take_unique(Unique { + pointer: 0 as *const (), + _marker: PhantomData, + }); + take_f32(0.1); + + //call_return_u128_pair(); + + let slice = &[0, 1] as &[i32]; + let slice_ptr = slice as *const [i32] as *const i32; + + assert_eq!(slice_ptr as usize % 4, 0); + + //return; + + unsafe { + printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8); + + let hello: &[u8] = b"Hello\0" as &[u8; 6]; + let ptr: *const u8 = hello as *const [u8] as *const u8; + puts(ptr); + + let world: Box<&str> = box "World!\0"; + puts(*world as *const str as *const u8); + world as Box; + + assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8); + + assert_eq!(intrinsics::bswap(0xabu8), 0xabu8); + assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16); + assert_eq!(intrinsics::bswap(0xffee_ddccu32), 0xccdd_eeffu32); + assert_eq!(intrinsics::bswap(0x1234_5678_ffee_ddccu64), 0xccdd_eeff_7856_3412u64); + + assert_eq!(intrinsics::size_of_val(hello) as u8, 6); + + let chars = &['C', 'h', 'a', 'r', 's']; + let chars = chars as &[char]; + assert_eq!(intrinsics::size_of_val(chars) as u8, 4 * 5); + + let a: &dyn SomeTrait = &"abc\0"; + a.object_safe(); + + assert_eq!(intrinsics::size_of_val(a) as u8, 16); + assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); + + assert_eq!(intrinsics::min_align_of::() as u8, 2); + assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8); + + assert!(!intrinsics::needs_drop::()); + assert!(intrinsics::needs_drop::()); + + Unique { + pointer: 0 as *const &str, + _marker: PhantomData, + } as Unique; + + struct MyDst(T); + + intrinsics::size_of_val(&MyDst([0u8; 4]) as &MyDst<[u8]>); + + struct Foo { + x: u8, + y: !, + } + + unsafe fn uninitialized() -> T { + MaybeUninit { uninit: () }.value.value + } + + zeroed::<(u8, u8)>(); + #[allow(unreachable_code)] + { + if false { + zeroed::(); + zeroed::(); + uninitialized::(); + } + } + } + + let _ = box NoisyDrop { + text: "Boxed outer got dropped!\0", + inner: NoisyDropInner, + } as Box; + + const FUNC_REF: Option = Some(main); + match FUNC_REF { + Some(_) => {}, + None => assert!(false), + } + + match Ordering::Less { + Ordering::Less => {}, + _ => assert!(false), + } + + [NoisyDropInner, NoisyDropInner]; + + let x = &[0u32, 42u32] as &[u32]; + match x { + [] => assert_eq!(0u32, 1), + [_, ref y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize), + } + + assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42); + + extern { + #[linkage = "weak"] + static ABC: *const u8; + } + + { + extern { + #[linkage = "weak"] + static ABC: *const u8; + } + } + + // TODO(antoyo): to make this work, support weak linkage. + //unsafe { assert_eq!(ABC as usize, 0); } + + &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>; + + let f = 1000.0; + assert_eq!(f as u8, 255); + let f2 = -1000.0; + assert_eq!(f2 as i8, -128); + assert_eq!(f2 as u8, 0); + + static ANOTHER_STATIC: &u8 = &A_STATIC; + assert_eq!(*ANOTHER_STATIC, 42); + + check_niche_behavior(); + + extern "C" { + type ExternType; + } + + struct ExternTypeWrapper { + _a: ExternType, + } + + let nullptr = 0 as *const (); + let extern_nullptr = nullptr as *const ExternTypeWrapper; + extern_nullptr as *const (); + let slice_ptr = &[] as *const [u8]; + slice_ptr as *const u8; + + #[cfg(not(jit))] + test_tls(); +} + +#[repr(C)] +enum c_void { + _1, + _2, +} + +type c_int = i32; +type c_ulong = u64; + +type pthread_t = c_ulong; + +#[repr(C)] +struct pthread_attr_t { + __size: [u64; 7], +} + +#[link(name = "pthread")] +extern "C" { + fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int; + + fn pthread_create( + native: *mut pthread_t, + attr: *const pthread_attr_t, + f: extern "C" fn(_: *mut c_void) -> *mut c_void, + value: *mut c_void + ) -> c_int; + + fn pthread_join( + native: pthread_t, + value: *mut *mut c_void + ) -> c_int; +} + +#[thread_local] +#[cfg(not(jit))] +static mut TLS: u8 = 42; + +#[cfg(not(jit))] +extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void { + unsafe { TLS = 0; } + 0 as *mut c_void +} + +#[cfg(not(jit))] +fn test_tls() { + unsafe { + let mut attr: pthread_attr_t = zeroed(); + let mut thread: pthread_t = 0; + + assert_eq!(TLS, 42); + + if pthread_attr_init(&mut attr) != 0 { + assert!(false); + } + + if pthread_create(&mut thread, &attr, mutate_tls, 0 as *mut c_void) != 0 { + assert!(false); + } + + let mut res = 0 as *mut c_void; + pthread_join(thread, &mut res); + + // TLS of main thread must not have been changed by the other thread. + assert_eq!(TLS, 42); + + puts("TLS works!\n\0" as *const str as *const u8); + } +} + +// Copied ui/issues/issue-61696.rs + +pub enum Infallible {} + +// The check that the `bool` field of `V1` is encoding a "niche variant" +// (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect, +// causing valid `V1` values to be interpreted as other variants. +pub enum E1 { + V1 { f: bool }, + V2 { f: Infallible }, + V3, + V4, +} + +// Computing the discriminant used to be done using the niche type (here `u8`, +// from the `bool` field of `V1`), overflowing for variants with large enough +// indices (`V3` and `V4`), causing them to be interpreted as other variants. +pub enum E2 { + V1 { f: bool }, + + /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X), + _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X), + _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X), + _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X), + _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X), + _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X), + _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X), + _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X), + _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X), + _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X), + _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X), + _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X), + _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X), + _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X), + _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X), + _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X), + _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X), + _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X), + _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X), + _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X), + _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X), + _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X), + _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X), + _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X), + _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X), + _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X), + _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X), + _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X), + _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X), + _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X), + _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X), + _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X), + + V3, + V4, +} + +fn check_niche_behavior () { + if let E1::V2 { .. } = (E1::V1 { f: true }) { + intrinsics::abort(); + } + + if let E2::V1 { .. } = E2::V3:: { + intrinsics::abort(); + } +} diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs new file mode 100644 index 0000000000000..2e2b0052dee8b --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/mod_bench.rs @@ -0,0 +1,37 @@ +#![feature(start, box_syntax, core_intrinsics, lang_items)] +#![no_std] + +#[link(name = "c")] +extern {} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + unsafe { + core::intrinsics::abort(); + } +} + +#[lang="eh_personality"] +fn eh_personality(){} + +// Required for rustc_codegen_llvm +#[no_mangle] +unsafe extern "C" fn _Unwind_Resume() { + core::intrinsics::unreachable(); +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + for i in 2..100_000_000 { + black_box((i + 1) % i); + } + + 0 +} + +#[inline(never)] +fn black_box(i: u32) { + if i != 1 { + unsafe { core::intrinsics::abort(); } + } +} diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs new file mode 100644 index 0000000000000..eba0eb8289600 --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/std_example.rs @@ -0,0 +1,278 @@ +#![feature(core_intrinsics, generators, generator_trait, is_sorted)] + +use std::arch::x86_64::*; +use std::io::Write; +use std::ops::Generator; + +extern { + pub fn printf(format: *const i8, ...) -> i32; +} + +fn main() { + let mutex = std::sync::Mutex::new(()); + let _guard = mutex.lock().unwrap(); + + let _ = ::std::iter::repeat('a' as u8).take(10).collect::>(); + let stderr = ::std::io::stderr(); + let mut stderr = stderr.lock(); + + std::thread::spawn(move || { + println!("Hello from another thread!"); + }); + + writeln!(stderr, "some {} text", "").unwrap(); + + let _ = std::process::Command::new("true").env("c", "d").spawn(); + + println!("cargo:rustc-link-lib=z"); + + static ONCE: std::sync::Once = std::sync::Once::new(); + ONCE.call_once(|| {}); + + let _eq = LoopState::Continue(()) == LoopState::Break(()); + + // Make sure ByValPair values with differently sized components are correctly passed + map(None::<(u8, Box)>); + + println!("{}", 2.3f32.exp()); + println!("{}", 2.3f32.exp2()); + println!("{}", 2.3f32.abs()); + println!("{}", 2.3f32.sqrt()); + println!("{}", 2.3f32.floor()); + println!("{}", 2.3f32.ceil()); + println!("{}", 2.3f32.min(1.0)); + println!("{}", 2.3f32.max(1.0)); + println!("{}", 2.3f32.powi(2)); + println!("{}", 2.3f32.log2()); + assert_eq!(2.3f32.copysign(-1.0), -2.3f32); + println!("{}", 2.3f32.powf(2.0)); + + assert_eq!(-128i8, (-128i8).saturating_sub(1)); + assert_eq!(127i8, 127i8.saturating_sub(-128)); + assert_eq!(-128i8, (-128i8).saturating_add(-128)); + assert_eq!(127i8, 127i8.saturating_add(1)); + + assert_eq!(-32768i16, (-32768i16).saturating_add(-32768)); + assert_eq!(32767i16, 32767i16.saturating_add(1)); + + assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26); + assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7); + + let _d = 0i128.checked_div(2i128); + let _d = 0u128.checked_div(2u128); + assert_eq!(1u128 + 2, 3); + + assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128); + assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128); + assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128); + + let tmp = 353985398u128; + assert_eq!(tmp * 932490u128, 330087843781020u128); + + let tmp = -0x1234_5678_9ABC_DEF0i64; + assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128); + + // Check that all u/i128 <-> float casts work correctly. + let houndred_u128 = 100u128; + let houndred_i128 = 100i128; + let houndred_f32 = 100.0f32; + let houndred_f64 = 100.0f64; + assert_eq!(houndred_u128 as f32, 100.0); + assert_eq!(houndred_u128 as f64, 100.0); + assert_eq!(houndred_f32 as u128, 100); + assert_eq!(houndred_f64 as u128, 100); + assert_eq!(houndred_i128 as f32, 100.0); + assert_eq!(houndred_i128 as f64, 100.0); + assert_eq!(houndred_f32 as i128, 100); + assert_eq!(houndred_f64 as i128, 100); + + let _a = 1u32 << 2u8; + + let empty: [i32; 0] = []; + assert!(empty.is_sorted()); + + println!("{:?}", std::intrinsics::caller_location()); + + /*unsafe { + test_simd(); + }*/ + + Box::pin(move |mut _task_context| { + yield (); + }).as_mut().resume(0); + + println!("End"); +} + +/*#[target_feature(enable = "sse2")] +unsafe fn test_simd() { + let x = _mm_setzero_si128(); + let y = _mm_set1_epi16(7); + let or = _mm_or_si128(x, y); + let cmp_eq = _mm_cmpeq_epi8(y, y); + let cmp_lt = _mm_cmplt_epi8(y, y); + + /*assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]); + assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]); + assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]); + + test_mm_slli_si128(); + test_mm_movemask_epi8(); + test_mm256_movemask_epi8(); + test_mm_add_epi8(); + test_mm_add_pd(); + test_mm_cvtepi8_epi16(); + test_mm_cvtsi128_si64(); + + // FIXME(#666) implement `#[rustc_arg_required_const(..)]` support + //test_mm_extract_epi8(); + + let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); + assert_eq!(mask1, 1);*/ +}*/ + +/*#[target_feature(enable = "sse2")] +unsafe fn test_mm_slli_si128() { + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, 1); + let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m128i(r, e); + + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, 15); + let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + assert_eq_m128i(r, e); + + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, 16); + assert_eq_m128i(r, _mm_set1_epi8(0)); + + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, -1); + assert_eq_m128i(_mm_set1_epi8(0), r); + + #[rustfmt::skip] + let a = _mm_setr_epi8( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + ); + let r = _mm_slli_si128(a, -0x80000000); + assert_eq_m128i(r, _mm_set1_epi8(0)); +} + +#[target_feature(enable = "sse2")] +unsafe fn test_mm_movemask_epi8() { + #[rustfmt::skip] + let a = _mm_setr_epi8( + 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01, + 0b0101, 0b1111_0000u8 as i8, 0, 0, + 0, 0, 0b1111_0000u8 as i8, 0b0101, + 0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, + ); + let r = _mm_movemask_epi8(a); + assert_eq!(r, 0b10100100_00100101); +} + +#[target_feature(enable = "avx2")] +unsafe fn test_mm256_movemask_epi8() { + let a = _mm256_set1_epi8(-1); + let r = _mm256_movemask_epi8(a); + let e = -1; + assert_eq!(r, e); +} + +#[target_feature(enable = "sse2")] +unsafe fn test_mm_add_epi8() { + let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + #[rustfmt::skip] + let b = _mm_setr_epi8( + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + ); + let r = _mm_add_epi8(a, b); + #[rustfmt::skip] + let e = _mm_setr_epi8( + 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, + ); + assert_eq_m128i(r, e); +} + +#[target_feature(enable = "sse2")] +unsafe fn test_mm_add_pd() { + let a = _mm_setr_pd(1.0, 2.0); + let b = _mm_setr_pd(5.0, 10.0); + let r = _mm_add_pd(a, b); + assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0)); +} + +fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) { + unsafe { + assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y)); + } +} + +#[target_feature(enable = "sse2")] +pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) { + if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 { + panic!("{:?} != {:?}", a, b); + } +} + +#[target_feature(enable = "sse2")] +unsafe fn test_mm_cvtsi128_si64() { + let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0])); + assert_eq!(r, 5); +} + +#[target_feature(enable = "sse4.1")] +unsafe fn test_mm_cvtepi8_epi16() { + let a = _mm_set1_epi8(10); + let r = _mm_cvtepi8_epi16(a); + let e = _mm_set1_epi16(10); + assert_eq_m128i(r, e); + let a = _mm_set1_epi8(-10); + let r = _mm_cvtepi8_epi16(a); + let e = _mm_set1_epi16(-10); + assert_eq_m128i(r, e); +} + +#[target_feature(enable = "sse4.1")] +unsafe fn test_mm_extract_epi8() { + #[rustfmt::skip] + let a = _mm_setr_epi8( + -1, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15 + ); + let r1 = _mm_extract_epi8(a, 0); + let r2 = _mm_extract_epi8(a, 19); + assert_eq!(r1, 0xFF); + assert_eq!(r2, 3); +}*/ + +#[derive(PartialEq)] +enum LoopState { + Continue(()), + Break(()) +} + +pub enum Instruction { + Increment, + Loop, +} + +fn map(a: Option<(u8, Box)>) -> Option> { + match a { + None => None, + Some((_, instr)) => Some(instr), + } +} diff --git a/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs b/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs new file mode 100644 index 0000000000000..2cb84786f56d0 --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs @@ -0,0 +1,97 @@ +// Based on https://github.com/rust-lang/rust/blob/c5840f9d252c2f5cc16698dbf385a29c5de3ca07/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs + +// Test that array subslice patterns are correctly handled in const evaluation. + +// run-pass + +#[derive(PartialEq, Debug, Clone)] +struct N(u8); + +#[derive(PartialEq, Debug, Clone)] +struct Z; + +macro_rules! n { + ($($e:expr),* $(,)?) => { + [$(N($e)),*] + } +} + +// This macro has an unused variable so that it can be repeated base on the +// number of times a repeated variable (`$e` in `z`) occurs. +macro_rules! zed { + ($e:expr) => { Z } +} + +macro_rules! z { + ($($e:expr),* $(,)?) => { + [$(zed!($e)),*] + } +} + +// Compare constant evaluation and runtime evaluation of a given expression. +macro_rules! compare_evaluation { + ($e:expr, $t:ty $(,)?) => {{ + const CONST_EVAL: $t = $e; + const fn const_eval() -> $t { $e } + static CONST_EVAL2: $t = const_eval(); + let runtime_eval = $e; + assert_eq!(CONST_EVAL, runtime_eval); + assert_eq!(CONST_EVAL2, runtime_eval); + }} +} + +// Repeat `$test`, substituting the given macro variables with the given +// identifiers. +// +// For example: +// +// repeat! { +// ($name); X; Y: +// struct $name; +// } +// +// Expands to: +// +// struct X; struct Y; +// +// This is used to repeat the tests using both the `N` and `Z` +// types. +macro_rules! repeat { + (($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => { + macro_rules! single { + ($($dollar $placeholder:ident),*) => { $($test)* } + } + $(single!($($values),+);)* + } +} + +fn main() { + repeat! { + ($arr $Ty); n, N; z, Z: + compare_evaluation!({ let [_, x @ .., _] = $arr!(1, 2, 3, 4); x }, [$Ty; 2]); + compare_evaluation!({ let [_, ref x @ .., _] = $arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]); + compare_evaluation!({ let [_, x @ .., _] = &$arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]); + + compare_evaluation!({ let [_, _, x @ .., _, _] = $arr!(1, 2, 3, 4); x }, [$Ty; 0]); + compare_evaluation!( + { let [_, _, ref x @ .., _, _] = $arr!(1, 2, 3, 4); x }, + &'static [$Ty; 0], + ); + compare_evaluation!( + { let [_, _, x @ .., _, _] = &$arr!(1, 2, 3, 4); x }, + &'static [$Ty; 0], + ); + + compare_evaluation!({ let [_, .., x] = $arr!(1, 2, 3, 4); x }, $Ty); + compare_evaluation!({ let [_, .., ref x] = $arr!(1, 2, 3, 4); x }, &'static $Ty); + compare_evaluation!({ let [_, _y @ .., x] = &$arr!(1, 2, 3, 4); x }, &'static $Ty); + } + + compare_evaluation!({ let [_, .., N(x)] = n!(1, 2, 3, 4); x }, u8); + compare_evaluation!({ let [_, .., N(ref x)] = n!(1, 2, 3, 4); x }, &'static u8); + compare_evaluation!({ let [_, .., N(x)] = &n!(1, 2, 3, 4); x }, &'static u8); + + compare_evaluation!({ let [N(x), .., _] = n!(1, 2, 3, 4); x }, u8); + compare_evaluation!({ let [N(ref x), .., _] = n!(1, 2, 3, 4); x }, &'static u8); + compare_evaluation!({ let [N(x), .., _] = &n!(1, 2, 3, 4); x }, &'static u8); +} diff --git a/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs b/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs new file mode 100644 index 0000000000000..93bab17e46b27 --- /dev/null +++ b/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs @@ -0,0 +1,40 @@ +// Based on https://github.com/anp/rust/blob/175631311716d7dfeceec40d2587cde7142ffa8c/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs + +// run-pass + +use std::panic::Location; + +#[track_caller] +fn tracked() -> &'static Location<'static> { + Location::caller() +} + +fn nested_intrinsic() -> &'static Location<'static> { + Location::caller() +} + +fn nested_tracked() -> &'static Location<'static> { + tracked() +} + +fn main() { + let location = Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), 21); + assert_eq!(location.column(), 20); + + let tracked = tracked(); + assert_eq!(tracked.file(), file!()); + assert_eq!(tracked.line(), 26); + assert_eq!(tracked.column(), 19); + + let nested = nested_intrinsic(); + assert_eq!(nested.file(), file!()); + assert_eq!(nested.line(), 13); + assert_eq!(nested.column(), 5); + + let contained = nested_tracked(); + assert_eq!(contained.file(), file!()); + assert_eq!(contained.line(), 17); + assert_eq!(contained.column(), 5); +} diff --git a/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch new file mode 100644 index 0000000000000..aae62a938b457 --- /dev/null +++ b/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch @@ -0,0 +1,63 @@ +From f6befc4bb51d84f5f1cf35938a168c953d421350 Mon Sep 17 00:00:00 2001 +From: bjorn3 +Date: Sun, 24 Nov 2019 15:10:23 +0100 +Subject: [PATCH] [core] Disable not compiling tests + +--- + library/core/tests/Cargo.toml | 8 ++++++++ + library/core/tests/num/flt2dec/mod.rs | 1 - + library/core/tests/num/int_macros.rs | 2 ++ + library/core/tests/num/uint_macros.rs | 2 ++ + library/core/tests/ptr.rs | 2 ++ + library/core/tests/slice.rs | 2 ++ + 6 files changed, 16 insertions(+), 1 deletion(-) + create mode 100644 library/core/tests/Cargo.toml + +diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml +new file mode 100644 +index 0000000..46fd999 +--- /dev/null ++++ b/library/core/tests/Cargo.toml +@@ -0,0 +1,8 @@ ++[package] ++name = "core" ++version = "0.0.0" ++edition = "2018" ++ ++[lib] ++name = "coretests" ++path = "lib.rs" +diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs +index a35897e..f0bf645 100644 +--- a/library/core/tests/num/flt2dec/mod.rs ++++ b/library/core/tests/num/flt2dec/mod.rs +@@ -13,7 +13,6 @@ mod strategy { + mod dragon; + mod grisu; + } +-mod random; + + pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { +diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs +index 6609bc3..241b497 100644 +--- a/library/core/tests/slice.rs ++++ b/library/core/tests/slice.rs +@@ -1209,6 +1209,7 @@ fn brute_force_rotate_test_1() { + } + } + ++/* + #[test] + #[cfg(not(target_arch = "wasm32"))] + fn sort_unstable() { +@@ -1394,6 +1395,7 @@ fn partition_at_index() { + v.select_nth_unstable(0); + assert!(v == [0xDEADBEEF]); + } ++*/ + + #[test] + #[should_panic(expected = "index 0 greater than length of slice")] +-- +2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch new file mode 100644 index 0000000000000..ee5ba449fb8e6 --- /dev/null +++ b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch @@ -0,0 +1,49 @@ +From dd82e95c9de212524e14fc60155de1ae40156dfc Mon Sep 17 00:00:00 2001 +From: bjorn3 +Date: Sun, 24 Nov 2019 15:34:06 +0100 +Subject: [PATCH] [core] Ignore failing tests + +--- + library/core/tests/iter.rs | 4 ++++ + library/core/tests/num/bignum.rs | 10 ++++++++++ + library/core/tests/num/mod.rs | 5 +++-- + library/core/tests/time.rs | 1 + + 4 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs +index 4bc44e9..8e3c7a4 100644 +--- a/library/core/tests/array.rs ++++ b/library/core/tests/array.rs +@@ -242,6 +242,7 @@ fn iterator_drops() { + assert_eq!(i.get(), 5); + } + ++/* + // This test does not work on targets without panic=unwind support. + // To work around this problem, test is marked is should_panic, so it will + // be automagically skipped on unsuitable targets, such as +@@ -283,6 +284,7 @@ fn array_default_impl_avoids_leaks_on_panic() { + assert_eq!(COUNTER.load(Relaxed), 0); + panic!("test succeeded") + } ++*/ + + #[test] + fn empty_array_is_always_default() { +@@ -304,6 +304,7 @@ fn array_map() { + assert_eq!(b, [1, 2, 3]); + } + ++/* + // See note on above test for why `should_panic` is used. + #[test] + #[should_panic(expected = "test succeeded")] +@@ -332,6 +333,7 @@ fn array_map_drop_safety() { + assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create); + panic!("test succeeded") + } ++*/ + + #[test] + fn cell_allows_array_cycle() { +-- 2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_gcc/prepare.sh b/compiler/rustc_codegen_gcc/prepare.sh new file mode 100755 index 0000000000000..503fa29b36269 --- /dev/null +++ b/compiler/rustc_codegen_gcc/prepare.sh @@ -0,0 +1,22 @@ +#!/bin/bash --verbose +set -e + +source prepare_build.sh + +cargo install hyperfine || echo "Skipping hyperfine install" + +git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned" +pushd regex +git checkout -- . +git checkout 341f207c1071f7290e3f228c710817c280c8dca1 +popd + +git clone https://github.com/ebobby/simple-raytracer || echo "ebobby/simple-raytracer has already been cloned" +pushd simple-raytracer +git checkout -- . +git checkout 804a7a21b9e673a482797aa289a18ed480e4d813 + +# build with cg_llvm for perf comparison +cargo build +mv target/debug/main raytracer_cg_llvm +popd diff --git a/compiler/rustc_codegen_gcc/prepare_build.sh b/compiler/rustc_codegen_gcc/prepare_build.sh new file mode 100755 index 0000000000000..ccf5350983015 --- /dev/null +++ b/compiler/rustc_codegen_gcc/prepare_build.sh @@ -0,0 +1,5 @@ +#!/bin/bash --verbose +set -e + +rustup component add rust-src rustc-dev llvm-tools-preview +./build_sysroot/prepare_sysroot_src.sh diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain new file mode 100644 index 0000000000000..d311a33f807b7 --- /dev/null +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -0,0 +1 @@ +nightly-2021-09-28 diff --git a/compiler/rustc_codegen_gcc/rustup.sh b/compiler/rustc_codegen_gcc/rustup.sh new file mode 100755 index 0000000000000..01ce5bb78be0f --- /dev/null +++ b/compiler/rustc_codegen_gcc/rustup.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -e + +case $1 in + "prepare") + TOOLCHAIN=$(date +%Y-%m-%d) + + echo "=> Installing new nightly" + rustup toolchain install --profile minimal nightly-${TOOLCHAIN} # Sanity check to see if the nightly exists + echo nightly-${TOOLCHAIN} > rust-toolchain + + echo "=> Uninstalling all old nighlies" + for nightly in $(rustup toolchain list | grep nightly | grep -v $TOOLCHAIN | grep -v nightly-x86_64); do + rustup toolchain uninstall $nightly + done + + ./clean_all.sh + ./prepare.sh + ;; + "commit") + git add rust-toolchain + git commit -m "Rustup to $(rustc -V)" + ;; + *) + echo "Unknown command '$1'" + echo "Usage: ./rustup.sh prepare|commit" + ;; +esac diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs new file mode 100644 index 0000000000000..ce428c589a478 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -0,0 +1,160 @@ +use gccjit::{ToRValue, Type}; +use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods}; +use rustc_middle::bug; +use rustc_middle::ty::Ty; +use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind}; + +use crate::builder::Builder; +use crate::context::CodegenCx; +use crate::intrinsic::ArgAbiExt; +use crate::type_of::LayoutGccExt; + +impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) { + // TODO(antoyo) + } + + fn get_param(&self, index: usize) -> Self::Value { + self.cx.current_func.borrow().expect("current func") + .get_param(index as i32) + .to_rvalue() + } +} + +impl GccType for CastTarget { + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> { + let rest_gcc_unit = self.rest.unit.gcc_type(cx); + let (rest_count, rem_bytes) = + if self.rest.unit.size.bytes() == 0 { + (0, 0) + } + else { + (self.rest.total.bytes() / self.rest.unit.size.bytes(), self.rest.total.bytes() % self.rest.unit.size.bytes()) + }; + + if self.prefix.iter().all(|x| x.is_none()) { + // Simplify to a single unit when there is no prefix and size <= unit size + if self.rest.total <= self.rest.unit.size { + return rest_gcc_unit; + } + + // Simplify to array when all chunks are the same size and type + if rem_bytes == 0 { + return cx.type_array(rest_gcc_unit, rest_count); + } + } + + // Create list of fields in the main structure + let mut args: Vec<_> = self + .prefix + .iter() + .flat_map(|option_kind| { + option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.gcc_type(cx)) + }) + .chain((0..rest_count).map(|_| rest_gcc_unit)) + .collect(); + + // Append final integer + if rem_bytes != 0 { + // Only integers can be really split further. + assert_eq!(self.rest.unit.kind, RegKind::Integer); + args.push(cx.type_ix(rem_bytes * 8)); + } + + cx.type_struct(&args, false) + } +} + +pub trait GccType { + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc>; +} + +impl GccType for Reg { + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> { + match self.kind { + RegKind::Integer => cx.type_ix(self.size.bits()), + RegKind::Float => { + match self.size.bits() { + 32 => cx.type_f32(), + 64 => cx.type_f64(), + _ => bug!("unsupported float: {:?}", self), + } + }, + RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()), + } + } +} + +pub trait FnAbiGccExt<'gcc, 'tcx> { + // TODO(antoyo): return a function pointer type instead? + fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec>, bool); + fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; +} + +impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { + fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec>, bool) { + let args_capacity: usize = self.args.iter().map(|arg| + if arg.pad.is_some() { + 1 + } + else { + 0 + } + + if let PassMode::Pair(_, _) = arg.mode { + 2 + } else { + 1 + } + ).sum(); + let mut argument_tys = Vec::with_capacity( + if let PassMode::Indirect { .. } = self.ret.mode { + 1 + } + else { + 0 + } + args_capacity, + ); + + let return_ty = + match self.ret.mode { + PassMode::Ignore => cx.type_void(), + PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), + PassMode::Cast(cast) => cast.gcc_type(cx), + PassMode::Indirect { .. } => { + argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); + cx.type_void() + } + }; + + for arg in &self.args { + // add padding + if let Some(ty) = arg.pad { + argument_tys.push(ty.gcc_type(cx)); + } + + let arg_ty = match arg.mode { + PassMode::Ignore => continue, + PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx), + PassMode::Pair(..) => { + argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0, true)); + argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1, true)); + continue; + } + PassMode::Indirect { extra_attrs: Some(_), .. } => { + unimplemented!(); + } + PassMode::Cast(cast) => cast.gcc_type(cx), + PassMode::Indirect { extra_attrs: None, .. } => cx.type_ptr_to(arg.memory_ty(cx)), + }; + argument_tys.push(arg_ty); + } + + (return_ty, argument_tys, self.c_variadic) + } + + fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + let (return_type, params, variadic) = self.gcc_type(cx); + let pointer_type = cx.context.new_function_pointer_type(None, return_type, ¶ms, variadic); + pointer_type + } +} diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs new file mode 100644 index 0000000000000..6378a31202c1b --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -0,0 +1,116 @@ +use gccjit::{FunctionType, ToRValue}; +use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; +use rustc_middle::bug; +use rustc_middle::ty::TyCtxt; +use rustc_span::symbol::sym; + +use crate::GccContext; + +pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) { + let context = &mods.context; + let usize = + match tcx.sess.target.pointer_width { + 16 => context.new_type::(), + 32 => context.new_type::(), + 64 => context.new_type::(), + tws => bug!("Unsupported target word size for int: {}", tws), + }; + let i8 = context.new_type::(); + let i8p = i8.make_pointer(); + let void = context.new_type::<()>(); + + for method in ALLOCATOR_METHODS { + let mut types = Vec::with_capacity(method.inputs.len()); + for ty in method.inputs.iter() { + match *ty { + AllocatorTy::Layout => { + types.push(usize); + types.push(usize); + } + AllocatorTy::Ptr => types.push(i8p), + AllocatorTy::Usize => types.push(usize), + + AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), + } + } + let output = match method.output { + AllocatorTy::ResultPtr => Some(i8p), + AllocatorTy::Unit => None, + + AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { + panic!("invalid allocator output") + } + }; + let name = format!("__rust_{}", method.name); + + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false); + + if tcx.sess.target.options.default_hidden_visibility { + // TODO(antoyo): set visibility. + } + if tcx.sess.must_emit_unwind_tables() { + // TODO(antoyo): emit unwind tables. + } + + let callee = kind.fn_name(method.name); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false); + // TODO(antoyo): set visibility. + + let block = func.new_block("entry"); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::>(); + let ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + block.end_with_return(None, ret); + } + else { + block.end_with_void_return(None); + } + + // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances + // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 + } + + let types = [usize, usize]; + let name = "__rust_alloc_error_handler".to_string(); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); + + let kind = + if has_alloc_error_handler { + AllocatorKind::Global + } + else { + AllocatorKind::Default + }; + let callee = kind.fn_name(sym::oom); + let args: Vec<_> = types.iter().enumerate() + .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) + .collect(); + let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false); + //llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden); + + let block = func.new_block("entry"); + + let args = args + .iter() + .enumerate() + .map(|(i, _)| func.get_param(i as i32).to_rvalue()) + .collect::>(); + let _ret = context.new_call(None, callee, &args); + //llvm::LLVMSetTailCall(ret, True); + block.end_with_void_return(None); +} diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs new file mode 100644 index 0000000000000..11dd6d49aa768 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/archive.rs @@ -0,0 +1,217 @@ +use std::fs::File; +use std::path::{Path, PathBuf}; + +use rustc_codegen_ssa::back::archive::ArchiveBuilder; +use rustc_session::Session; + +use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_session::cstore::DllImport; + +struct ArchiveConfig<'a> { + sess: &'a Session, + dst: PathBuf, + use_native_ar: bool, + use_gnu_style_archive: bool, +} + +#[derive(Debug)] +enum ArchiveEntry { + FromArchive { + archive_index: usize, + entry_index: usize, + }, + File(PathBuf), +} + +pub struct ArArchiveBuilder<'a> { + config: ArchiveConfig<'a>, + src_archives: Vec<(PathBuf, ar::Archive)>, + // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at + // the end of an archive for linkers to not get confused. + entries: Vec<(String, ArchiveEntry)>, +} + +impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { + fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self { + let config = ArchiveConfig { + sess, + dst: output.to_path_buf(), + use_native_ar: false, + // FIXME test for linux and System V derivatives instead + use_gnu_style_archive: sess.target.options.archive_format == "gnu", + }; + + let (src_archives, entries) = if let Some(input) = input { + let mut archive = ar::Archive::new(File::open(input).unwrap()); + let mut entries = Vec::new(); + + let mut i = 0; + while let Some(entry) = archive.next_entry() { + let entry = entry.unwrap(); + entries.push(( + String::from_utf8(entry.header().identifier().to_vec()).unwrap(), + ArchiveEntry::FromArchive { + archive_index: 0, + entry_index: i, + }, + )); + i += 1; + } + + (vec![(input.to_owned(), archive)], entries) + } else { + (vec![], Vec::new()) + }; + + ArArchiveBuilder { + config, + src_archives, + entries, + } + } + + fn src_files(&mut self) -> Vec { + self.entries.iter().map(|(name, _)| name.clone()).collect() + } + + fn remove_file(&mut self, name: &str) { + let index = self + .entries + .iter() + .position(|(entry_name, _)| entry_name == name) + .expect("Tried to remove file not existing in src archive"); + self.entries.remove(index); + } + + fn add_file(&mut self, file: &Path) { + self.entries.push(( + file.file_name().unwrap().to_str().unwrap().to_string(), + ArchiveEntry::File(file.to_owned()), + )); + } + + fn add_archive(&mut self, archive_path: &Path, mut skip: F) -> std::io::Result<()> + where + F: FnMut(&str) -> bool + 'static, + { + let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?); + let archive_index = self.src_archives.len(); + + let mut i = 0; + while let Some(entry) = archive.next_entry() { + let entry = entry?; + let file_name = String::from_utf8(entry.header().identifier().to_vec()) + .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?; + if !skip(&file_name) { + self.entries + .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i })); + } + i += 1; + } + + self.src_archives.push((archive_path.to_owned(), archive)); + Ok(()) + } + + fn update_symbols(&mut self) { + } + + fn build(mut self) { + use std::process::Command; + + fn add_file_using_ar(archive: &Path, file: &Path) { + Command::new("ar") + .arg("r") // add or replace file + .arg("-c") // silence created file message + .arg(archive) + .arg(&file) + .status() + .unwrap(); + } + + enum BuilderKind<'a> { + Bsd(ar::Builder), + Gnu(ar::GnuBuilder), + NativeAr(&'a Path), + } + + let mut builder = if self.config.use_native_ar { + BuilderKind::NativeAr(&self.config.dst) + } else if self.config.use_gnu_style_archive { + BuilderKind::Gnu(ar::GnuBuilder::new( + File::create(&self.config.dst).unwrap(), + self.entries + .iter() + .map(|(name, _)| name.as_bytes().to_vec()) + .collect(), + )) + } else { + BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap())) + }; + + // Add all files + for (entry_name, entry) in self.entries.into_iter() { + match entry { + ArchiveEntry::FromArchive { + archive_index, + entry_index, + } => { + let (ref src_archive_path, ref mut src_archive) = + self.src_archives[archive_index]; + let entry = src_archive.jump_to_entry(entry_index).unwrap(); + let header = entry.header().clone(); + + match builder { + BuilderKind::Bsd(ref mut builder) => { + builder.append(&header, entry).unwrap() + } + BuilderKind::Gnu(ref mut builder) => { + builder.append(&header, entry).unwrap() + } + BuilderKind::NativeAr(archive_file) => { + Command::new("ar") + .arg("x") + .arg(src_archive_path) + .arg(&entry_name) + .status() + .unwrap(); + add_file_using_ar(archive_file, Path::new(&entry_name)); + std::fs::remove_file(entry_name).unwrap(); + } + } + } + ArchiveEntry::File(file) => + match builder { + BuilderKind::Bsd(ref mut builder) => { + builder + .append_file(entry_name.as_bytes(), &mut File::open(file).expect("file for bsd builder")) + .unwrap() + }, + BuilderKind::Gnu(ref mut builder) => { + builder + .append_file(entry_name.as_bytes(), &mut File::open(&file).expect(&format!("file {:?} for gnu builder", file))) + .unwrap() + }, + BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file), + }, + } + } + + // Finalize archive + std::mem::drop(builder); + + // Run ranlib to be able to link the archive + let status = std::process::Command::new("ranlib") + .arg(self.config.dst) + .status() + .expect("Couldn't run ranlib"); + + if !status.success() { + self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code())); + } + } + + fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) { + unimplemented!(); + } +} diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs new file mode 100644 index 0000000000000..3b77097e9ad00 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -0,0 +1,785 @@ +use gccjit::{LValue, RValue, ToRValue, Type}; +use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_codegen_ssa::mir::operand::OperandValue; +use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; + +use rustc_hir::LlvmInlineAsmInner; +use rustc_middle::{bug, ty::Instance}; +use rustc_span::{Span, Symbol}; +use rustc_target::asm::*; + +use std::borrow::Cow; + +use crate::builder::Builder; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + + +// Rust asm! and GCC Extended Asm semantics differ substantially. +// +// 1. Rust asm operands go along as one list of operands. Operands themselves indicate +// if they're "in" or "out". "In" and "out" operands can interleave. One operand can be +// both "in" and "out" (`inout(reg)`). +// +// GCC asm has two different lists for "in" and "out" operands. In terms of gccjit, +// this means that all "out" operands must go before "in" operands. "In" and "out" operands +// cannot interleave. +// +// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important +// because the asm template refers to operands by index. +// +// Mapping from Rust to GCC index would be 1-1 if it wasn't for... +// +// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. +// Contrary, Rust expresses clobbers through "out" operands that aren't tied to +// a variable (`_`), and such "clobbers" do have index. +// +// 4. Furthermore, GCC Extended Asm does not support explicit register constraints +// (like `out("eax")`) directly, offering so-called "local register variables" +// as a workaround. These variables need to be declared and initialized *before* +// the Extended Asm block but *after* normal local variables +// (see comment in `codegen_inline_asm` for explanation). +// +// With that in mind, let's see how we translate Rust syntax to GCC +// (from now on, `CC` stands for "constraint code"): +// +// * `out(reg_class) var` -> translated to output operand: `"=CC"(var)` +// * `inout(reg_class) var` -> translated to output operand: `"+CC"(var)` +// * `in(reg_class) var` -> translated to input operand: `"CC"(var)` +// +// * `out(reg_class) _` -> translated to one `=r(tmp)`, where "tmp" is a temporary unused variable +// +// * `out("explicit register") _` -> not translated to any operands, register is simply added to clobbers list +// +// * `inout(reg_class) in_var => out_var` -> translated to two operands: +// output: `"=CC"(in_var)` +// input: `"num"(out_var)` where num is the GCC index +// of the corresponding output operand +// +// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`, +// where "tmp" is a temporary unused variable +// +// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above +// with `"r"(var)` constraint, +// and one register variable assigned to the desired register. +// + +const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t"; +const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix"; + + +struct AsmOutOperand<'a, 'tcx, 'gcc> { + rust_idx: usize, + constraint: &'a str, + late: bool, + readwrite: bool, + + tmp_var: LValue<'gcc>, + out_place: Option>> +} + +struct AsmInOperand<'a, 'tcx> { + rust_idx: usize, + constraint: Cow<'a, str>, + val: RValue<'tcx> +} + +impl AsmOutOperand<'_, '_, '_> { + fn to_constraint(&self) -> String { + let mut res = String::with_capacity(self.constraint.len() + self.late as usize + 1); + + let sign = if self.readwrite { '+' } else { '=' }; + res.push(sign); + if !self.late { + res.push('&'); + } + + res.push_str(&self.constraint); + res + } +} + +enum ConstraintOrRegister { + Constraint(&'static str), + Register(&'static str) +} + + +impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec>>, _inputs: Vec>, span: Span) -> bool { + self.sess().struct_span_err(span, "GCC backend does not support `llvm_asm!`") + .help("consider using the `asm!` macro instead") + .emit(); + + // We return `true` even if we've failed to generate the asm + // because we want to suppress the "malformed inline assembly" error + // generated by the frontend. + true + } + + fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) { + let asm_arch = self.tcx.sess.asm_arch.unwrap(); + let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64); + let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX); + let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX); + + // GCC index of an output operand equals its position in the array + let mut outputs = vec![]; + + // GCC index of an input operand equals its position in the array + // added to `outputs.len()` + let mut inputs = vec![]; + + // Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _` + let mut clobbers = vec![]; + + // We're trying to preallocate space for the template + let mut constants_len = 0; + + // There are rules we must adhere to if we want GCC to do the right thing: + // + // * Every local variable that the asm block uses as an output must be declared *before* + // the asm block. + // * There must be no instructions whatsoever between the register variables and the asm. + // + // Therefore, the backend must generate the instructions strictly in this order: + // + // 1. Output variables. + // 2. Register variables. + // 3. The asm block. + // + // We also must make sure that no input operands are emitted before output operands. + // + // This is why we work in passes, first emitting local vars, then local register vars. + // Also, we don't emit any asm operands immediately; we save them to + // the one of the buffers to be emitted later. + + // 1. Normal variables (and saving operands to buffers). + for (rust_idx, op) in rust_operands.iter().enumerate() { + match *op { + InlineAsmOperandRef::Out { reg, late, place } => { + use ConstraintOrRegister::*; + + let (constraint, ty) = match (reg_to_gcc(reg), place) { + (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)), + // When `reg` is a class and not an explicit register but the out place is not specified, + // we need to create an unused output variable to assign the output to. This var + // needs to be of a type that's "compatible" with the register class, but specific type + // doesn't matter. + (Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())), + (Register(_), Some(_)) => { + // left for the next pass + continue + }, + (Register(reg_name), None) => { + // `clobber_abi` can add lots of clobbers that are not supported by the target, + // such as AVX-512 registers, so we just ignore unsupported registers + let is_target_supported = reg.reg_class().supported_types(asm_arch).iter() + .any(|&(_, feature)| { + if let Some(feature) = feature { + self.tcx.sess.target_features.contains(&Symbol::intern(feature)) + } else { + true // Register class is unconditionally supported + } + }); + + if is_target_supported && !clobbers.contains(®_name) { + clobbers.push(reg_name); + } + continue + } + }; + + let tmp_var = self.current_func().new_local(None, ty, "output_register"); + outputs.push(AsmOutOperand { + constraint, + rust_idx, + late, + readwrite: false, + tmp_var, + out_place: place + }); + } + + InlineAsmOperandRef::In { reg, value } => { + if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { + inputs.push(AsmInOperand { + constraint: Cow::Borrowed(constraint), + rust_idx, + val: value.immediate() + }); + } + else { + // left for the next pass + continue + } + } + + InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { + let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { + constraint + } + else { + // left for the next pass + continue + }; + + // Rustc frontend guarantees that input and output types are "compatible", + // so we can just use input var's type for the output variable. + // + // This decision is also backed by the fact that LLVM needs in and out + // values to be of *exactly the same type*, not just "compatible". + // I'm not sure if GCC is so picky too, but better safe than sorry. + let ty = in_value.layout.gcc_type(self.cx, false); + let tmp_var = self.current_func().new_local(None, ty, "output_register"); + + // If the out_place is None (i.e `inout(reg) _` syntax was used), we translate + // it to one "readwrite (+) output variable", otherwise we translate it to two + // "out and tied in" vars as described above. + let readwrite = out_place.is_none(); + outputs.push(AsmOutOperand { + constraint, + rust_idx, + late, + readwrite, + tmp_var, + out_place, + }); + + if !readwrite { + let out_gcc_idx = outputs.len() - 1; + let constraint = Cow::Owned(out_gcc_idx.to_string()); + + inputs.push(AsmInOperand { + constraint, + rust_idx, + val: in_value.immediate() + }); + } + } + + InlineAsmOperandRef::Const { ref string } => { + constants_len += string.len() + att_dialect as usize; + } + + InlineAsmOperandRef::SymFn { instance } => { + constants_len += self.tcx.symbol_name(instance).name.len(); + } + InlineAsmOperandRef::SymStatic { def_id } => { + constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len(); + } + } + } + + // 2. Register variables. + for (rust_idx, op) in rust_operands.iter().enumerate() { + match *op { + // `out("explicit register") var` + InlineAsmOperandRef::Out { reg, late, place } => { + if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { + let out_place = if let Some(place) = place { + place + } + else { + // processed in the previous pass + continue + }; + + let ty = out_place.layout.gcc_type(self.cx, false); + let tmp_var = self.current_func().new_local(None, ty, "output_register"); + tmp_var.set_register_name(reg_name); + + outputs.push(AsmOutOperand { + constraint: "r".into(), + rust_idx, + late, + readwrite: false, + tmp_var, + out_place: Some(out_place) + }); + } + + // processed in the previous pass + } + + // `in("explicit register") var` + InlineAsmOperandRef::In { reg, value } => { + if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { + let ty = value.layout.gcc_type(self.cx, false); + let reg_var = self.current_func().new_local(None, ty, "input_register"); + reg_var.set_register_name(reg_name); + self.llbb().add_assignment(None, reg_var, value.immediate()); + + inputs.push(AsmInOperand { + constraint: "r".into(), + rust_idx, + val: reg_var.to_rvalue() + }); + } + + // processed in the previous pass + } + + // `inout("explicit register") in_var => out_var` + InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { + if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { + let out_place = if let Some(place) = out_place { + place + } + else { + // processed in the previous pass + continue + }; + + // See explanation in the first pass. + let ty = in_value.layout.gcc_type(self.cx, false); + let tmp_var = self.current_func().new_local(None, ty, "output_register"); + tmp_var.set_register_name(reg_name); + + outputs.push(AsmOutOperand { + constraint: "r".into(), + rust_idx, + late, + readwrite: false, + tmp_var, + out_place: Some(out_place) + }); + + let constraint = Cow::Owned((outputs.len() - 1).to_string()); + inputs.push(AsmInOperand { + constraint, + rust_idx, + val: in_value.immediate() + }); + } + + // processed in the previous pass + } + + InlineAsmOperandRef::Const { .. } + | InlineAsmOperandRef::SymFn { .. } + | InlineAsmOperandRef::SymStatic { .. } => { + // processed in the previous pass + } + } + } + + // 3. Build the template string + + let mut template_str = String::with_capacity(estimate_template_length(template, constants_len, att_dialect)); + if !intel_dialect { + template_str.push_str(ATT_SYNTAX_INS); + } + + for piece in template { + match *piece { + InlineAsmTemplatePiece::String(ref string) => { + // TODO(@Commeownist): switch to `Iterator::intersperse` once it's stable + let mut iter = string.split('%'); + if let Some(s) = iter.next() { + template_str.push_str(s); + } + + for s in iter { + template_str.push_str("%%"); + template_str.push_str(s); + } + } + InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span: _ } => { + let mut push_to_template = |modifier, gcc_idx| { + use std::fmt::Write; + + template_str.push('%'); + if let Some(modifier) = modifier { + template_str.push(modifier); + } + write!(template_str, "{}", gcc_idx).expect("pushing to string failed"); + }; + + match rust_operands[operand_idx] { + InlineAsmOperandRef::Out { reg, .. } => { + let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier); + let gcc_index = outputs.iter() + .position(|op| operand_idx == op.rust_idx) + .expect("wrong rust index"); + push_to_template(modifier, gcc_index); + } + + InlineAsmOperandRef::In { reg, .. } => { + let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier); + let in_gcc_index = inputs.iter() + .position(|op| operand_idx == op.rust_idx) + .expect("wrong rust index"); + let gcc_index = in_gcc_index + outputs.len(); + push_to_template(modifier, gcc_index); + } + + InlineAsmOperandRef::InOut { reg, .. } => { + let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier); + + // The input register is tied to the output, so we can just use the index of the output register + let gcc_index = outputs.iter() + .position(|op| operand_idx == op.rust_idx) + .expect("wrong rust index"); + push_to_template(modifier, gcc_index); + } + + InlineAsmOperandRef::SymFn { instance } => { + let name = self.tcx.symbol_name(instance).name; + template_str.push_str(name); + } + + InlineAsmOperandRef::SymStatic { def_id } => { + // TODO(@Commeownist): This may not be sufficient for all kinds of statics. + // Some statics may need the `@plt` suffix, like thread-local vars. + let instance = Instance::mono(self.tcx, def_id); + let name = self.tcx.symbol_name(instance).name; + template_str.push_str(name); + } + + InlineAsmOperandRef::Const { ref string } => { + // Const operands get injected directly into the template + if att_dialect { + template_str.push('$'); + } + template_str.push_str(string); + } + } + } + } + } + + if !intel_dialect { + template_str.push_str(INTEL_SYNTAX_INS); + } + + // 4. Generate Extended Asm block + + let block = self.llbb(); + let extended_asm = block.add_extended_asm(None, &template_str); + + for op in &outputs { + extended_asm.add_output_operand(None, &op.to_constraint(), op.tmp_var); + } + + for op in &inputs { + extended_asm.add_input_operand(None, &op.constraint, op.val); + } + + for clobber in clobbers.iter() { + extended_asm.add_clobber(clobber); + } + + if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) { + // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient + // on all architectures. For instance, what about FP stack? + extended_asm.add_clobber("cc"); + } + if !options.contains(InlineAsmOptions::NOMEM) { + extended_asm.add_clobber("memory"); + } + if !options.contains(InlineAsmOptions::PURE) { + extended_asm.set_volatile_flag(true); + } + if !options.contains(InlineAsmOptions::NOSTACK) { + // TODO(@Commeownist): figure out how to align stack + } + if options.contains(InlineAsmOptions::NORETURN) { + let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable"); + let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) }; + self.call(self.type_void(), builtin_unreachable, &[], None); + } + + // Write results to outputs. + // + // We need to do this because: + // 1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases + // (especially with current `rustc_backend_ssa` API). + // 2. Not every output operand has an `out_place`, and it's required by `add_output_operand`. + // + // Instead, we generate a temporary output variable for each output operand, and then this loop, + // generates `out_place = tmp_var;` assignments if out_place exists. + for op in &outputs { + if let Some(place) = op.out_place { + OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place); + } + } + + } +} + +fn estimate_template_length(template: &[InlineAsmTemplatePiece], constants_len: usize, att_dialect: bool) -> usize { + let len: usize = template.iter().map(|piece| { + match *piece { + InlineAsmTemplatePiece::String(ref string) => { + string.len() + } + InlineAsmTemplatePiece::Placeholder { .. } => { + // '%' + 1 char modifier + 1 char index + 3 + } + } + }) + .sum(); + + // increase it by 5% to account for possible '%' signs that'll be duplicated + // I pulled the number out of blue, but should be fair enough + // as the upper bound + let mut res = (len as f32 * 1.05) as usize + constants_len; + + if att_dialect { + res += INTEL_SYNTAX_INS.len() + ATT_SYNTAX_INS.len(); + } + res +} + +/// Converts a register class to a GCC constraint code. +fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { + let constraint = match reg { + // For vector registers LLVM wants the register name to match the type size. + InlineAsmRegOrRegClass::Reg(reg) => { + match reg { + InlineAsmReg::X86(_) => { + // TODO(antoyo): add support for vector register. + // + // // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119 + return ConstraintOrRegister::Register(match reg.name() { + // Some of registers' names does not map 1-1 from rust to gcc + "st(0)" => "st", + + name => name, + }); + } + + _ => unimplemented!(), + } + }, + InlineAsmRegOrRegClass::RegClass(reg) => match reg { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => unimplemented!(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => unimplemented!(), + InlineAsmRegClass::Bpf(_) => unimplemented!(), + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => unimplemented!(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + unreachable!("clobber-only") + }, + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q", + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q", + InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x", + InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", + InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(), + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(), + InlineAsmRegClass::X86( + X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg, + ) => unreachable!("clobber-only"), + InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { + bug!("GCC backend does not support SPIR-V") + } + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::Err => unreachable!(), + } + }; + + ConstraintOrRegister::Constraint(constraint) +} + +/// Type to use for outputs that are discarded. It doesn't really matter what +/// the type is, as long as it is valid for the constraint code. +fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegClass) -> Type<'gcc> { + match reg { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(), + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { + unimplemented!() + } + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => cx.type_f64(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { + unimplemented!() + } + InlineAsmRegClass::Bpf(_) => unimplemented!(), + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), + InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(), + InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr) + | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => { + unreachable!("clobber-only") + }, + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => cx.type_f32(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::mmx_reg) => unimplemented!(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(), + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), + InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { + bug!("LLVM backend does not support SPIR-V") + }, + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), + InlineAsmRegClass::Err => unreachable!(), + } +} + +impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> { + fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef], options: InlineAsmOptions, _line_spans: &[Span]) { + let asm_arch = self.tcx.sess.asm_arch.unwrap(); + + // Default to Intel syntax on x86 + let intel_syntax = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) + && !options.contains(InlineAsmOptions::ATT_SYNTAX); + + // Build the template string + let mut template_str = String::new(); + for piece in template { + match *piece { + InlineAsmTemplatePiece::String(ref string) => { + for line in string.lines() { + // NOTE: gcc does not allow inline comment, so remove them. + let line = + if let Some(index) = line.rfind("//") { + &line[..index] + } + else { + line + }; + template_str.push_str(line); + template_str.push('\n'); + } + }, + InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => { + match operands[operand_idx] { + GlobalAsmOperandRef::Const { ref string } => { + // Const operands get injected directly into the + // template. Note that we don't need to escape % + // here unlike normal inline assembly. + template_str.push_str(string); + } + } + } + } + } + + let template_str = + if intel_syntax { + format!("{}\n\t.intel_syntax noprefix", template_str) + } + else { + format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", template_str) + }; + // NOTE: seems like gcc will put the asm in the wrong section, so set it to .text manually. + let template_str = format!(".pushsection .text\n{}\n.popsection", template_str); + self.context.add_top_level_asm(None, &template_str); + } +} + +fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option) -> Option { + match reg { + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier, + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => modifier, + InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) + | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { + unimplemented!() + } + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) + | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => { + unimplemented!() + } + InlineAsmRegClass::Bpf(_) => unimplemented!(), + InlineAsmRegClass::Hexagon(_) => unimplemented!(), + InlineAsmRegClass::Mips(_) => unimplemented!(), + InlineAsmRegClass::Nvptx(_) => unimplemented!(), + InlineAsmRegClass::PowerPC(_) => unimplemented!(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) + | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) + | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier { + None => if arch == InlineAsmArch::X86_64 { Some('q') } else { Some('k') }, + Some('l') => Some('b'), + Some('h') => Some('h'), + Some('x') => Some('w'), + Some('e') => Some('k'), + Some('r') => Some('q'), + _ => unreachable!(), + }, + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => None, + InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::xmm_reg) + | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::ymm_reg) + | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) { + (X86InlineAsmRegClass::xmm_reg, None) => Some('x'), + (X86InlineAsmRegClass::ymm_reg, None) => Some('t'), + (X86InlineAsmRegClass::zmm_reg, None) => Some('g'), + (_, Some('x')) => Some('x'), + (_, Some('y')) => Some('t'), + (_, Some('z')) => Some('g'), + _ => unreachable!(), + }, + InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None, + InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => { + unreachable!("clobber-only") + } + InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(), + InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => { + bug!("LLVM backend does not support SPIR-V") + }, + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(), + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(), + InlineAsmRegClass::Err => unreachable!(), + } +} diff --git a/compiler/rustc_codegen_gcc/src/back/mod.rs b/compiler/rustc_codegen_gcc/src/back/mod.rs new file mode 100644 index 0000000000000..d692799d7642f --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/back/mod.rs @@ -0,0 +1 @@ +pub mod write; diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs new file mode 100644 index 0000000000000..c3e3847823d91 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -0,0 +1,78 @@ +use std::fs; + +use gccjit::OutputKind; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; +use rustc_codegen_ssa::back::write::{CodegenContext, EmitObj, ModuleConfig}; +use rustc_errors::Handler; +use rustc_session::config::OutputType; +use rustc_span::fatal_error::FatalError; +use rustc_target::spec::SplitDebuginfo; + +use crate::{GccCodegenBackend, GccContext}; + +pub(crate) unsafe fn codegen(cgcx: &CodegenContext, _diag_handler: &Handler, module: ModuleCodegen, config: &ModuleConfig) -> Result { + let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &module.name[..]); + { + let context = &module.module_llvm.context; + + let module_name = module.name.clone(); + let module_name = Some(&module_name[..]); + + let _bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); + let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); + + if config.bitcode_needed() { + // TODO(antoyo) + } + + if config.emit_ir { + unimplemented!(); + } + + if config.emit_asm { + let _timer = cgcx + .prof + .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &module.name[..]); + let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); + context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str")); + } + + match config.emit_obj { + EmitObj::ObjectCode(_) => { + let _timer = cgcx + .prof + .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]); + match &*module.name { + "std_example.7rcbfp3g-cgu.15" => { + println!("Dumping reproducer {}", module.name); + let _ = fs::create_dir("/tmp/reproducers"); + // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by + // transmuting an rvalue to an lvalue. + // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue + context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name)); + println!("Dumped reproducer {}", module.name); + }, + _ => (), + } + context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str")); + } + + EmitObj::Bitcode => { + // TODO(antoyo) + } + + EmitObj::None => {} + } + } + + Ok(module.into_compiled_module( + config.emit_obj != EmitObj::None, + cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked, + config.emit_bc, + &cgcx.output_filenames, + )) +} + +pub(crate) fn link(_cgcx: &CodegenContext, _diag_handler: &Handler, mut _modules: Vec>) -> Result, FatalError> { + unimplemented!(); +} diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs new file mode 100644 index 0000000000000..9f96096574fe1 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -0,0 +1,165 @@ +use std::env; +use std::time::Instant; + +use gccjit::{ + Context, + FunctionType, + GlobalKind, +}; +use rustc_middle::dep_graph; +use rustc_middle::middle::exported_symbols; +use rustc_middle::ty::TyCtxt; +use rustc_middle::mir::mono::Linkage; +use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; +use rustc_codegen_ssa::base::maybe_create_entry_wrapper; +use rustc_codegen_ssa::mono_item::MonoItemExt; +use rustc_codegen_ssa::traits::DebugInfoMethods; +use rustc_metadata::EncodedMetadata; +use rustc_session::config::DebugInfo; +use rustc_span::Symbol; + +use crate::GccContext; +use crate::builder::Builder; +use crate::context::CodegenCx; + +pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind { + match linkage { + Linkage::External => GlobalKind::Imported, + Linkage::AvailableExternally => GlobalKind::Imported, + Linkage::LinkOnceAny => unimplemented!(), + Linkage::LinkOnceODR => unimplemented!(), + Linkage::WeakAny => unimplemented!(), + Linkage::WeakODR => unimplemented!(), + Linkage::Appending => unimplemented!(), + Linkage::Internal => GlobalKind::Internal, + Linkage::Private => GlobalKind::Internal, + Linkage::ExternalWeak => GlobalKind::Imported, // TODO(antoyo): should be weak linkage. + Linkage::Common => unimplemented!(), + } +} + +pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType { + match linkage { + Linkage::External => FunctionType::Exported, + Linkage::AvailableExternally => FunctionType::Extern, + Linkage::LinkOnceAny => unimplemented!(), + Linkage::LinkOnceODR => unimplemented!(), + Linkage::WeakAny => FunctionType::Exported, // FIXME(antoyo): should be similar to linkonce. + Linkage::WeakODR => unimplemented!(), + Linkage::Appending => unimplemented!(), + Linkage::Internal => FunctionType::Internal, + Linkage::Private => FunctionType::Internal, + Linkage::ExternalWeak => unimplemented!(), + Linkage::Common => unimplemented!(), + } +} + +pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen, u64) { + let prof_timer = tcx.prof.generic_activity("codegen_module"); + let start_time = Instant::now(); + + let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); + let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result); + let time_to_codegen = start_time.elapsed(); + drop(prof_timer); + + // We assume that the cost to run GCC on a CGU is proportional to + // the time we needed for codegenning it. + let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64; + + fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen { + let cgu = tcx.codegen_unit(cgu_name); + // Instantiate monomorphizations without filling out definitions yet... + //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); + let context = Context::default(); + // TODO(antoyo): only set on x86 platforms. + context.add_command_line_option("-masm=intel"); + for arg in &tcx.sess.opts.cg.llvm_args { + context.add_command_line_option(arg); + } + context.add_command_line_option("-fno-semantic-interposition"); + if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") { + context.set_dump_code_on_compile(true); + } + if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") { + context.set_dump_initial_gimple(true); + } + context.set_debug_info(true); + if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") { + context.set_dump_everything(true); + } + if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") { + context.set_keep_intermediates(true); + } + + { + let cx = CodegenCx::new(&context, cgu, tcx); + + let mono_items = cgu.items_in_deterministic_order(tcx); + for &(mono_item, (linkage, visibility)) in &mono_items { + mono_item.predefine::>(&cx, linkage, visibility); + } + + // ... and now that we have everything pre-defined, fill out those definitions. + for &(mono_item, _) in &mono_items { + mono_item.define::>(&cx); + } + + // If this codegen unit contains the main function, also create the + // wrapper here + maybe_create_entry_wrapper::>(&cx); + + // Finalize debuginfo + if cx.sess().opts.debuginfo != DebugInfo::None { + cx.debuginfo_finalize(); + } + } + + ModuleCodegen { + name: cgu_name.to_string(), + module_llvm: GccContext { + context + }, + kind: ModuleKind::Regular, + } + } + + (module, cost) +} + +pub fn write_compressed_metadata<'tcx>(tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut GccContext) { + use snap::write::FrameEncoder; + use std::io::Write; + + // Historical note: + // + // When using link.exe it was seen that the section name `.note.rustc` + // was getting shortened to `.note.ru`, and according to the PE and COFF + // specification: + // + // > Executable images do not use a string table and do not support + // > section names longer than 8 characters + // + // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format + // + // As a result, we choose a slightly shorter name! As to why + // `.note.rustc` works on MinGW, see + // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197 + let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" }; + + let context = &gcc_module.context; + let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); + FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data()).unwrap(); + + let name = exported_symbols::metadata_symbol_name(tcx); + let typ = context.new_array_type(None, context.new_type::(), compressed.len() as i32); + let global = context.new_global(None, GlobalKind::Exported, typ, name); + global.global_set_initializer(&compressed); + global.set_link_section(section_name); + + // Also generate a .section directive to force no + // flags, at least for ELF outputs, so that the + // metadata doesn't get loaded into memory. + let directive = format!(".section {}", section_name); + context.add_top_level_asm(None, &directive); +} diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs new file mode 100644 index 0000000000000..ac908418ee4bf --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -0,0 +1,1540 @@ +use std::borrow::Cow; +use std::cell::Cell; +use std::convert::TryFrom; +use std::ops::Deref; + +use gccjit::FunctionType; +use gccjit::{ + BinaryOp, + Block, + ComparisonOp, + Function, + LValue, + RValue, + ToRValue, + Type, + UnaryOp, +}; +use rustc_codegen_ssa::MemFlags; +use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope}; +use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; +use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::traits::{ + BackendTypes, + BaseTypeMethods, + BuilderMethods, + ConstMethods, + DerivedTypeMethods, + LayoutTypeMethods, + HasCodegen, + OverflowOp, + StaticBuilderMethods, +}; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout}; +use rustc_span::Span; +use rustc_span::def_id::DefId; +use rustc_target::abi::{ + self, + call::FnAbi, + Align, + HasDataLayout, + Size, + TargetDataLayout, + WrappingRange, +}; +use rustc_target::spec::{HasTargetSpec, Target}; + +use crate::common::{SignType, TypeReflection, type_is_pointer}; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +// TODO(antoyo) +type Funclet = (); + +// TODO(antoyo): remove this variable. +static mut RETURN_VALUE_COUNT: usize = 0; + +enum ExtremumOperation { + Max, + Min, +} + +trait EnumClone { + fn clone(&self) -> Self; +} + +impl EnumClone for AtomicOrdering { + fn clone(&self) -> Self { + match *self { + AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic, + AtomicOrdering::Unordered => AtomicOrdering::Unordered, + AtomicOrdering::Monotonic => AtomicOrdering::Monotonic, + AtomicOrdering::Acquire => AtomicOrdering::Acquire, + AtomicOrdering::Release => AtomicOrdering::Release, + AtomicOrdering::AcquireRelease => AtomicOrdering::AcquireRelease, + AtomicOrdering::SequentiallyConsistent => AtomicOrdering::SequentiallyConsistent, + } + } +} + +pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { + pub cx: &'a CodegenCx<'gcc, 'tcx>, + pub block: Option>, + stack_var_count: Cell, +} + +impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { + fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>) -> Self { + Builder { + cx, + block: None, + stack_var_count: Cell::new(0), + } + } + + fn atomic_extremum(&mut self, operation: ExtremumOperation, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> { + let size = self.cx.int_width(src.get_type()) / 8; + + let func = self.current_func(); + + let load_ordering = + match order { + // TODO(antoyo): does this make sense? + AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire, + _ => order.clone(), + }; + let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering.clone(), Size::from_bytes(size)); + let previous_var = func.new_local(None, previous_value.get_type(), "previous_value"); + let return_value = func.new_local(None, previous_value.get_type(), "return_value"); + self.llbb().add_assignment(None, previous_var, previous_value); + self.llbb().add_assignment(None, return_value, previous_var.to_rvalue()); + + let while_block = func.new_block("while"); + let after_block = func.new_block("after_while"); + self.llbb().end_with_jump(None, while_block); + + // NOTE: since jumps were added and compare_exchange doesn't expect this, the current blocks in the + // state need to be updated. + self.block = Some(while_block); + *self.cx.current_block.borrow_mut() = Some(while_block); + + let comparison_operator = + match operation { + ExtremumOperation::Max => ComparisonOp::LessThan, + ExtremumOperation::Min => ComparisonOp::GreaterThan, + }; + + let cond1 = self.context.new_comparison(None, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(None, src, previous_value.get_type())); + let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false); + let cond2 = self.cx.context.new_unary_op(None, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange); + let cond = self.cx.context.new_binary_op(None, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2); + + while_block.end_with_conditional(None, cond, while_block, after_block); + + // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the + // state need to be updated. + self.block = Some(after_block); + *self.cx.current_block.borrow_mut() = Some(after_block); + + return_value.to_rvalue() + } + + fn compare_exchange(&self, dst: RValue<'gcc>, cmp: LValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { + let size = self.cx.int_width(src.get_type()); + let compare_exchange = self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size / 8)); + let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + let failure_order = self.context.new_rvalue_from_int(self.i32_type, failure_order.to_gcc()); + let weak = self.context.new_rvalue_from_int(self.bool_type, weak as i32); + + let void_ptr_type = self.context.new_type::<*mut ()>(); + let volatile_void_ptr_type = void_ptr_type.make_volatile(); + let dst = self.context.new_cast(None, dst, volatile_void_ptr_type); + let expected = self.context.new_cast(None, cmp.get_address(None), void_ptr_type); + + // NOTE: not sure why, but we have the wrong type here. + let int_type = compare_exchange.get_param(2).to_rvalue().get_type(); + let src = self.context.new_cast(None, src, int_type); + self.context.new_call(None, compare_exchange, &[dst, expected, src, weak, order, failure_order]) + } + + pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) { + self.llbb().add_assignment(None, lvalue, value); + } + + fn check_call<'b>(&mut self, _typ: &str, func: Function<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { + let mut all_args_match = true; + let mut param_types = vec![]; + let param_count = func.get_param_count(); + for (index, arg) in args.iter().enumerate().take(param_count) { + let param = func.get_param(index as i32); + let param = param.to_rvalue().get_type(); + if param != arg.get_type() { + all_args_match = false; + } + param_types.push(param); + } + + if all_args_match { + return Cow::Borrowed(args); + } + + let casted_args: Vec<_> = param_types + .into_iter() + .zip(args.iter()) + .enumerate() + .map(|(_i, (expected_ty, &actual_val))| { + let actual_ty = actual_val.get_type(); + if expected_ty != actual_ty { + self.bitcast(actual_val, expected_ty) + } + else { + actual_val + } + }) + .collect(); + + Cow::Owned(casted_args) + } + + fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { + let mut all_args_match = true; + let mut param_types = vec![]; + let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr"); + for (index, arg) in args.iter().enumerate().take(gcc_func.get_param_count()) { + let param = gcc_func.get_param_type(index); + if param != arg.get_type() { + all_args_match = false; + } + param_types.push(param); + } + + if all_args_match { + return Cow::Borrowed(args); + } + + let casted_args: Vec<_> = param_types + .into_iter() + .zip(args.iter()) + .enumerate() + .map(|(_i, (expected_ty, &actual_val))| { + let actual_ty = actual_val.get_type(); + if expected_ty != actual_ty { + self.bitcast(actual_val, expected_ty) + } + else { + actual_val + } + }) + .collect(); + + Cow::Owned(casted_args) + } + + fn check_store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { + let dest_ptr_ty = self.cx.val_ty(ptr).make_pointer(); // TODO(antoyo): make sure make_pointer() is okay here. + let stored_ty = self.cx.val_ty(val); + let stored_ptr_ty = self.cx.type_ptr_to(stored_ty); + + if dest_ptr_ty == stored_ptr_ty { + ptr + } + else { + self.bitcast(ptr, stored_ptr_ty) + } + } + + pub fn current_func(&self) -> Function<'gcc> { + self.block.expect("block").get_function() + } + + fn function_call(&mut self, func: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + // TODO(antoyo): remove when the API supports a different type for functions. + let func: Function<'gcc> = self.cx.rvalue_as_function(func); + let args = self.check_call("call", func, args); + + // gccjit requires to use the result of functions, even when it's not used. + // That's why we assign the result to a local or call add_eval(). + let return_type = func.get_return_type(); + let current_block = self.current_block.borrow().expect("block"); + let void_type = self.context.new_type::<()>(); + let current_func = current_block.get_function(); + if return_type != void_type { + unsafe { RETURN_VALUE_COUNT += 1 }; + let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); + current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + result.to_rvalue() + } + else { + current_block.add_eval(None, self.cx.context.new_call(None, func, &args)); + // Return dummy value when not having return value. + self.context.new_rvalue_from_long(self.isize_type, 0) + } + } + + fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + let args = self.check_ptr_call("call", func_ptr, args); + + // gccjit requires to use the result of functions, even when it's not used. + // That's why we assign the result to a local or call add_eval(). + let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr"); + let mut return_type = gcc_func.get_return_type(); + let current_block = self.current_block.borrow().expect("block"); + let void_type = self.context.new_type::<()>(); + let current_func = current_block.get_function(); + + // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics. + if gcc_func.get_param_count() == 0 && format!("{:?}", func_ptr) == "__builtin_ia32_pmovmskb128" { + return_type = self.int_type; + } + + if return_type != void_type { + unsafe { RETURN_VALUE_COUNT += 1 }; + let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); + current_block.add_assignment(None, result, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + result.to_rvalue() + } + else { + if gcc_func.get_param_count() == 0 { + // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics. + current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[])); + } + else { + current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args)); + } + // Return dummy value when not having return value. + let result = current_func.new_local(None, self.isize_type, "dummyValueThatShouldNeverBeUsed"); + current_block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0)); + result.to_rvalue() + } + } + + pub fn overflow_call(&mut self, func: Function<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> { + // gccjit requires to use the result of functions, even when it's not used. + // That's why we assign the result to a local. + let return_type = self.context.new_type::(); + let current_block = self.current_block.borrow().expect("block"); + let current_func = current_block.get_function(); + // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects. + unsafe { RETURN_VALUE_COUNT += 1 }; + let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT })); + current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args)); + result.to_rvalue() + } +} + +impl<'gcc, 'tcx> HasCodegen<'tcx> for Builder<'_, 'gcc, 'tcx> { + type CodegenCx = CodegenCx<'gcc, 'tcx>; +} + +impl<'tcx> HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.cx.tcx() + } +} + +impl HasDataLayout for Builder<'_, '_, '_> { + fn data_layout(&self) -> &TargetDataLayout { + self.cx.data_layout() + } +} + +impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + self.cx.handle_layout_err(err, span, ty) + } +} + +impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + self.cx.handle_fn_abi_err(err, span, fn_abi_request) + } +} + +impl<'gcc, 'tcx> Deref for Builder<'_, 'gcc, 'tcx> { + type Target = CodegenCx<'gcc, 'tcx>; + + fn deref(&self) -> &Self::Target { + self.cx + } +} + +impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { + type Value = as BackendTypes>::Value; + type Function = as BackendTypes>::Function; + type BasicBlock = as BackendTypes>::BasicBlock; + type Type = as BackendTypes>::Type; + type Funclet = as BackendTypes>::Funclet; + + type DIScope = as BackendTypes>::DIScope; + type DILocation = as BackendTypes>::DILocation; + type DIVariable = as BackendTypes>::DIVariable; +} + +impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { + fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self { + let mut bx = Builder::with_cx(cx); + *cx.current_block.borrow_mut() = Some(block); + bx.block = Some(block); + bx + } + + fn build_sibling_block(&mut self, name: &str) -> Self { + let block = self.append_sibling_block(name); + Self::build(self.cx, block) + } + + fn llbb(&self) -> Block<'gcc> { + self.block.expect("block") + } + + fn append_block(cx: &'a CodegenCx<'gcc, 'tcx>, func: RValue<'gcc>, name: &str) -> Block<'gcc> { + let func = cx.rvalue_as_function(func); + func.new_block(name) + } + + fn append_sibling_block(&mut self, name: &str) -> Block<'gcc> { + let func = self.current_func(); + func.new_block(name) + } + + fn ret_void(&mut self) { + self.llbb().end_with_void_return(None) + } + + fn ret(&mut self, value: RValue<'gcc>) { + let value = + if self.structs_as_pointer.borrow().contains(&value) { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + value.dereference(None).to_rvalue() + } + else { + value + }; + self.llbb().end_with_return(None, value); + } + + fn br(&mut self, dest: Block<'gcc>) { + self.llbb().end_with_jump(None, dest) + } + + fn cond_br(&mut self, cond: RValue<'gcc>, then_block: Block<'gcc>, else_block: Block<'gcc>) { + self.llbb().end_with_conditional(None, cond, then_block, else_block) + } + + fn switch(&mut self, value: RValue<'gcc>, default_block: Block<'gcc>, cases: impl ExactSizeIterator)>) { + let mut gcc_cases = vec![]; + let typ = self.val_ty(value); + for (on_val, dest) in cases { + let on_val = self.const_uint_big(typ, on_val); + gcc_cases.push(self.context.new_case(on_val, on_val, dest)); + } + self.block.expect("block").end_with_switch(None, value, default_block, &gcc_cases); + } + + fn invoke(&mut self, _typ: Type<'gcc>, _func: RValue<'gcc>, _args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + let condition = self.context.new_rvalue_from_int(self.bool_type, 0); + self.llbb().end_with_conditional(None, condition, then, catch); + self.context.new_rvalue_from_int(self.int_type, 0) + + // TODO(antoyo) + } + + fn unreachable(&mut self) { + let func = self.context.get_builtin_function("__builtin_unreachable"); + let block = self.block.expect("block"); + block.add_eval(None, self.context.new_call(None, func, &[])); + let return_type = block.get_function().get_return_type(); + let void_type = self.context.new_type::<()>(); + if return_type == void_type { + block.end_with_void_return(None) + } + else { + let return_value = self.current_func() + .new_local(None, return_type, "unreachableReturn"); + block.end_with_return(None, return_value) + } + } + + fn add(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): this should not be required. + if format!("{:?}", a.get_type()) != format!("{:?}", b.get_type()) { + b = self.context.new_cast(None, b, a.get_type()); + } + a + b + } + + fn fadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a + b + } + + fn sub(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + if a.get_type() != b.get_type() { + b = self.context.new_cast(None, b, a.get_type()); + } + a - b + } + + fn fsub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a - b + } + + fn mul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a * b + } + + fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a * b + } + + fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): convert the arguments to unsigned? + a / b + } + + fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): convert the arguments to unsigned? + // TODO(antoyo): poison if not exact. + a / b + } + + fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): convert the arguments to signed? + a / b + } + + fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): posion if not exact. + // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they + // should be the same. + let typ = a.get_type().to_signed(self); + let b = self.context.new_cast(None, b, typ); + a / b + } + + fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a / b + } + + fn urem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a % b + } + + fn srem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a % b + } + + fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + if a.get_type() == self.cx.float_type { + let fmodf = self.context.get_builtin_function("fmodf"); + // FIXME(antoyo): this seems to produce the wrong result. + return self.context.new_call(None, fmodf, &[a, b]); + } + assert_eq!(a.get_type(), self.cx.double_type); + + let fmod = self.context.get_builtin_function("fmod"); + return self.context.new_call(None, fmod, &[a, b]); + } + + fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. + let a_type = a.get_type(); + let b_type = b.get_type(); + if a_type.is_unsigned(self) && b_type.is_signed(self) { + let a = self.context.new_cast(None, a, b_type); + let result = a << b; + self.context.new_cast(None, result, a_type) + } + else if a_type.is_signed(self) && b_type.is_unsigned(self) { + let b = self.context.new_cast(None, b, a_type); + a << b + } + else { + a << b + } + } + + fn lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. + // TODO(antoyo): cast to unsigned to do a logical shift if that does not work. + let a_type = a.get_type(); + let b_type = b.get_type(); + if a_type.is_unsigned(self) && b_type.is_signed(self) { + let a = self.context.new_cast(None, a, b_type); + let result = a >> b; + self.context.new_cast(None, result, a_type) + } + else if a_type.is_signed(self) && b_type.is_unsigned(self) { + let b = self.context.new_cast(None, b, a_type); + a >> b + } + else { + a >> b + } + } + + fn ashr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): check whether behavior is an arithmetic shift for >> . + // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number. + let a_type = a.get_type(); + let b_type = b.get_type(); + if a_type.is_unsigned(self) && b_type.is_signed(self) { + let a = self.context.new_cast(None, a, b_type); + let result = a >> b; + self.context.new_cast(None, result, a_type) + } + else if a_type.is_signed(self) && b_type.is_unsigned(self) { + let b = self.context.new_cast(None, b, a_type); + a >> b + } + else { + a >> b + } + } + + fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): hack by putting the result in a variable to workaround this bug: + // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498 + if a.get_type() != b.get_type() { + b = self.context.new_cast(None, b, a.get_type()); + } + let res = self.current_func().new_local(None, b.get_type(), "andResult"); + self.llbb().add_assignment(None, res, a & b); + res.to_rvalue() + } + + fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): hack by putting the result in a variable to workaround this bug: + // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498 + let res = self.current_func().new_local(None, b.get_type(), "orResult"); + self.llbb().add_assignment(None, res, a | b); + res.to_rvalue() + } + + fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a ^ b + } + + fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use new_unary_op()? + self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a + } + + fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { + self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) + } + + fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { + let operation = + if a.get_type().is_bool() { + UnaryOp::LogicalNegate + } + else { + UnaryOp::BitwiseNegate + }; + self.cx.context.new_unary_op(None, operation, a.get_type(), a) + } + + fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a + b + } + + fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a + b + } + + fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a - b + } + + fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): should generate poison value? + a - b + } + + fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a * b + } + + fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { + a * b + } + + fn fadd_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn fsub_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn fmul_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn fdiv_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn frem_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) { + use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*}; + + let new_kind = + match typ.kind() { + Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), + Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), + t @ (Uint(_) | Int(_)) => t.clone(), + _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), + }; + + // TODO(antoyo): remove duplication with intrinsic? + let name = + match oop { + OverflowOp::Add => + match new_kind { + Int(I8) => "__builtin_add_overflow", + Int(I16) => "__builtin_add_overflow", + Int(I32) => "__builtin_sadd_overflow", + Int(I64) => "__builtin_saddll_overflow", + Int(I128) => "__builtin_add_overflow", + + Uint(U8) => "__builtin_add_overflow", + Uint(U16) => "__builtin_add_overflow", + Uint(U32) => "__builtin_uadd_overflow", + Uint(U64) => "__builtin_uaddll_overflow", + Uint(U128) => "__builtin_add_overflow", + + _ => unreachable!(), + }, + OverflowOp::Sub => + match new_kind { + Int(I8) => "__builtin_sub_overflow", + Int(I16) => "__builtin_sub_overflow", + Int(I32) => "__builtin_ssub_overflow", + Int(I64) => "__builtin_ssubll_overflow", + Int(I128) => "__builtin_sub_overflow", + + Uint(U8) => "__builtin_sub_overflow", + Uint(U16) => "__builtin_sub_overflow", + Uint(U32) => "__builtin_usub_overflow", + Uint(U64) => "__builtin_usubll_overflow", + Uint(U128) => "__builtin_sub_overflow", + + _ => unreachable!(), + }, + OverflowOp::Mul => + match new_kind { + Int(I8) => "__builtin_mul_overflow", + Int(I16) => "__builtin_mul_overflow", + Int(I32) => "__builtin_smul_overflow", + Int(I64) => "__builtin_smulll_overflow", + Int(I128) => "__builtin_mul_overflow", + + Uint(U8) => "__builtin_mul_overflow", + Uint(U16) => "__builtin_mul_overflow", + Uint(U32) => "__builtin_umul_overflow", + Uint(U64) => "__builtin_umulll_overflow", + Uint(U128) => "__builtin_mul_overflow", + + _ => unreachable!(), + }, + }; + + let intrinsic = self.context.get_builtin_function(&name); + let res = self.current_func() + // TODO(antoyo): is it correct to use rhs type instead of the parameter typ? + .new_local(None, rhs.get_type(), "binopResult") + .get_address(None); + let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None); + (res.dereference(None).to_rvalue(), overflow) + } + + fn alloca(&mut self, ty: Type<'gcc>, align: Align) -> RValue<'gcc> { + // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type. + // Ideally, we shouldn't need to do this check. + let aligned_type = + if ty == self.cx.u128_type || ty == self.cx.i128_type { + ty + } + else { + ty.get_aligned(align.bytes()) + }; + // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. + self.stack_var_count.set(self.stack_var_count.get() + 1); + self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None) + } + + fn dynamic_alloca(&mut self, _ty: Type<'gcc>, _align: Align) -> RValue<'gcc> { + unimplemented!(); + } + + fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> { + unimplemented!(); + } + + fn load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> { + // TODO(antoyo): use ty. + let block = self.llbb(); + let function = block.get_function(); + // NOTE: instead of returning the dereference here, we have to assign it to a variable in + // the current basic block. Otherwise, it could be used in another basic block, causing a + // dereference after a drop, for instance. + // TODO(antoyo): handle align. + let deref = ptr.dereference(None).to_rvalue(); + let value_type = deref.get_type(); + unsafe { RETURN_VALUE_COUNT += 1 }; + let loaded_value = function.new_local(None, value_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT })); + block.add_assignment(None, loaded_value, deref); + loaded_value.to_rvalue() + } + + fn volatile_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use ty. + let ptr = self.context.new_cast(None, ptr, ptr.get_type().make_volatile()); + ptr.dereference(None).to_rvalue() + } + + fn atomic_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) -> RValue<'gcc> { + // TODO(antoyo): use ty. + // TODO(antoyo): handle alignment. + let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes())); + let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + + let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile(); + let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); + self.context.new_call(None, atomic_load, &[ptr, ordering]) + } + + fn load_operand(&mut self, place: PlaceRef<'tcx, RValue<'gcc>>) -> OperandRef<'tcx, RValue<'gcc>> { + assert_eq!(place.llextra.is_some(), place.layout.is_unsized()); + + if place.layout.is_zst() { + return OperandRef::new_zst(self, place.layout); + } + + fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load: RValue<'gcc>, scalar: &abi::Scalar) { + let vr = scalar.valid_range.clone(); + match scalar.value { + abi::Int(..) => { + if !scalar.is_always_valid(bx) { + bx.range_metadata(load, scalar.valid_range); + } + } + abi::Pointer if vr.start < vr.end && !vr.contains(0) => { + bx.nonnull_metadata(load); + } + _ => {} + } + } + + let val = + if let Some(llextra) = place.llextra { + OperandValue::Ref(place.llval, Some(llextra), place.align) + } + else if place.layout.is_gcc_immediate() { + let load = self.load(place.llval.get_type(), place.llval, place.align); + if let abi::Abi::Scalar(ref scalar) = place.layout.abi { + scalar_load_metadata(self, load, scalar); + } + OperandValue::Immediate(self.to_immediate(load, place.layout)) + } + else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi { + let b_offset = a.value.size(self).align_to(b.value.align(self).abi); + let pair_type = place.layout.gcc_type(self, false); + + let mut load = |i, scalar: &abi::Scalar, align| { + let llptr = self.struct_gep(pair_type, place.llval, i as u64); + let load = self.load(llptr.get_type(), llptr, align); + scalar_load_metadata(self, load, scalar); + if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } + }; + + OperandValue::Pair( + load(0, a, place.align), + load(1, b, place.align.restrict_for_offset(b_offset)), + ) + } + else { + OperandValue::Ref(place.llval, None, place.align) + }; + + OperandRef { val, layout: place.layout } + } + + fn write_operand_repeatedly(mut self, cg_elem: OperandRef<'tcx, RValue<'gcc>>, count: u64, dest: PlaceRef<'tcx, RValue<'gcc>>) -> Self { + let zero = self.const_usize(0); + let count = self.const_usize(count); + let start = dest.project_index(&mut self, zero).llval; + let end = dest.project_index(&mut self, count).llval; + + let mut header_bx = self.build_sibling_block("repeat_loop_header"); + let mut body_bx = self.build_sibling_block("repeat_loop_body"); + let next_bx = self.build_sibling_block("repeat_loop_next"); + + let ptr_type = start.get_type(); + let current = self.llbb().get_function().new_local(None, ptr_type, "loop_var"); + let current_val = current.to_rvalue(); + self.assign(current, start); + + self.br(header_bx.llbb()); + + let keep_going = header_bx.icmp(IntPredicate::IntNE, current_val, end); + header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); + + let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size); + cg_elem.val.store(&mut body_bx, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align)); + + let next = body_bx.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]); + body_bx.llbb().add_assignment(None, current, next); + body_bx.br(header_bx.llbb()); + + next_bx + } + + fn range_metadata(&mut self, _load: RValue<'gcc>, _range: WrappingRange) { + // TODO(antoyo) + } + + fn nonnull_metadata(&mut self, _load: RValue<'gcc>) { + // TODO(antoyo) + } + + fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> { + self.store_with_flags(val, ptr, align, MemFlags::empty()) + } + + fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, _align: Align, _flags: MemFlags) -> RValue<'gcc> { + let ptr = self.check_store(val, ptr); + self.llbb().add_assignment(None, ptr.dereference(None), val); + // TODO(antoyo): handle align and flags. + // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here? + self.cx.context.new_rvalue_zero(self.type_i32()) + } + + fn atomic_store(&mut self, value: RValue<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) { + // TODO(antoyo): handle alignment. + let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes())); + let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile(); + let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); + + // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because + // the following cast is required to avoid this error: + // gcc_jit_context_new_call: mismatching types for argument 2 of function "__atomic_store_4": assignment to param arg1 (type: int) from loadedValue3577 (type: unsigned int __attribute__((aligned(4)))) + let int_type = atomic_store.get_param(1).to_rvalue().get_type(); + let value = self.context.new_cast(None, value, int_type); + self.llbb() + .add_eval(None, self.context.new_call(None, atomic_store, &[ptr, value, ordering])); + } + + fn gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + let mut result = ptr; + for index in indices { + result = self.context.new_array_access(None, result, *index).get_address(None).to_rvalue(); + } + result + } + + fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + // FIXME(antoyo): would be safer if doing the same thing (loop) as gep. + // TODO(antoyo): specify inbounds somehow. + match indices.len() { + 1 => { + self.context.new_array_access(None, ptr, indices[0]).get_address(None) + }, + 2 => { + let array = ptr.dereference(None); // TODO(antoyo): assert that first index is 0? + self.context.new_array_access(None, array, indices[1]).get_address(None) + }, + _ => unimplemented!(), + } + } + + fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> { + // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. + assert_eq!(idx as usize as u64, idx); + let value = ptr.dereference(None).to_rvalue(); + + if value_type.is_array().is_some() { + let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + let element = self.context.new_array_access(None, value, index); + element.get_address(None) + } + else if let Some(vector_type) = value_type.is_vector() { + let array_type = vector_type.get_element_type().make_pointer(); + let array = self.bitcast(ptr, array_type); + let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + let element = self.context.new_array_access(None, array, index); + element.get_address(None) + } + else if let Some(struct_type) = value_type.is_struct() { + ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None) + } + else { + panic!("Unexpected type {:?}", value_type); + } + } + + /* Casts */ + fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): check that it indeed truncate the value. + self.context.new_cast(None, value, dest_ty) + } + + fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): check that it indeed sign extend the value. + if dest_ty.is_vector().is_some() { + // TODO(antoyo): nothing to do as it is only for LLVM? + return value; + } + self.context.new_cast(None, value, dest_ty) + } + + fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): make sure it truncates. + self.context.new_cast(None, value, dest_ty) + } + + fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, value, dest_ty) + } + + fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.cx.ptrtoint(self.block.expect("block"), value, dest_ty) + } + + fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.cx.inttoptr(self.block.expect("block"), value, dest_ty) + } + + fn bitcast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + self.cx.const_bitcast(value, dest_ty) + } + + fn intcast(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>, _is_signed: bool) -> RValue<'gcc> { + // NOTE: is_signed is for value, not dest_typ. + self.cx.context.new_cast(None, value, dest_typ) + } + + fn pointercast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + let val_type = value.get_type(); + match (type_is_pointer(val_type), type_is_pointer(dest_ty)) { + (false, true) => { + // NOTE: Projecting a field of a pointer type will attemp a cast from a signed char to + // a pointer, which is not supported by gccjit. + return self.cx.context.new_cast(None, self.inttoptr(value, val_type.make_pointer()), dest_ty); + }, + (false, false) => { + // When they are not pointers, we want a transmute (or reinterpret_cast). + self.bitcast(value, dest_ty) + }, + (true, true) => self.cx.context.new_cast(None, value, dest_ty), + (true, false) => unimplemented!(), + } + } + + /* Comparisons */ + fn icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> { + let left_type = lhs.get_type(); + let right_type = rhs.get_type(); + if left_type != right_type { + // NOTE: because libgccjit cannot compare function pointers. + if left_type.is_function_ptr_type().is_some() && right_type.is_function_ptr_type().is_some() { + lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer()); + rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer()); + } + // NOTE: hack because we try to cast a vector type to the same vector type. + else if format!("{:?}", left_type) != format!("{:?}", right_type) { + rhs = self.context.new_cast(None, rhs, left_type); + } + } + self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + } + + fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { + self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs) + } + + /* Miscellaneous instructions */ + fn memcpy(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) { + if flags.contains(MemFlags::NONTEMPORAL) { + // HACK(nox): This is inefficient but there is no nontemporal memcpy. + let val = self.load(src.get_type(), src, src_align); + let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val))); + self.store_with_flags(val, ptr, dst_align, flags); + return; + } + let size = self.intcast(size, self.type_size_t(), false); + let _is_volatile = flags.contains(MemFlags::VOLATILE); + let dst = self.pointercast(dst, self.type_i8p()); + let src = self.pointercast(src, self.type_ptr_to(self.type_void())); + let memcpy = self.context.get_builtin_function("memcpy"); + let block = self.block.expect("block"); + // TODO(antoyo): handle aligns and is_volatile. + block.add_eval(None, self.context.new_call(None, memcpy, &[dst, src, size])); + } + + fn memmove(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) { + if flags.contains(MemFlags::NONTEMPORAL) { + // HACK(nox): This is inefficient but there is no nontemporal memmove. + let val = self.load(src.get_type(), src, src_align); + let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val))); + self.store_with_flags(val, ptr, dst_align, flags); + return; + } + let size = self.intcast(size, self.type_size_t(), false); + let _is_volatile = flags.contains(MemFlags::VOLATILE); + let dst = self.pointercast(dst, self.type_i8p()); + let src = self.pointercast(src, self.type_ptr_to(self.type_void())); + + let memmove = self.context.get_builtin_function("memmove"); + let block = self.block.expect("block"); + // TODO(antoyo): handle is_volatile. + block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size])); + } + + fn memset(&mut self, ptr: RValue<'gcc>, fill_byte: RValue<'gcc>, size: RValue<'gcc>, _align: Align, flags: MemFlags) { + let _is_volatile = flags.contains(MemFlags::VOLATILE); + let ptr = self.pointercast(ptr, self.type_i8p()); + let memset = self.context.get_builtin_function("memset"); + let block = self.block.expect("block"); + // TODO(antoyo): handle align and is_volatile. + let fill_byte = self.context.new_cast(None, fill_byte, self.i32_type); + let size = self.intcast(size, self.type_size_t(), false); + block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size])); + } + + fn select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, mut else_val: RValue<'gcc>) -> RValue<'gcc> { + let func = self.current_func(); + let variable = func.new_local(None, then_val.get_type(), "selectVar"); + let then_block = func.new_block("then"); + let else_block = func.new_block("else"); + let after_block = func.new_block("after"); + self.llbb().end_with_conditional(None, cond, then_block, else_block); + + then_block.add_assignment(None, variable, then_val); + then_block.end_with_jump(None, after_block); + + if then_val.get_type() != else_val.get_type() { + else_val = self.context.new_cast(None, else_val, then_val.get_type()); + } + else_block.add_assignment(None, variable, else_val); + else_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the + // state need to be updated. + self.block = Some(after_block); + *self.cx.current_block.borrow_mut() = Some(after_block); + + variable.to_rvalue() + } + + #[allow(dead_code)] + fn va_arg(&mut self, _list: RValue<'gcc>, _ty: Type<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn extract_element(&mut self, _vec: RValue<'gcc>, _idx: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn extract_value(&mut self, aggregate_value: RValue<'gcc>, idx: u64) -> RValue<'gcc> { + // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. + assert_eq!(idx as usize as u64, idx); + let value_type = aggregate_value.get_type(); + + if value_type.is_array().is_some() { + let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + let element = self.context.new_array_access(None, aggregate_value, index); + element.get_address(None) + } + else if value_type.is_vector().is_some() { + panic!(); + } + else if let Some(pointer_type) = value_type.get_pointee() { + if let Some(struct_type) = pointer_type.is_struct() { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)).to_rvalue() + } + else { + panic!("Unexpected type {:?}", value_type); + } + } + else if let Some(struct_type) = value_type.is_struct() { + aggregate_value.access_field(None, struct_type.get_field(idx as i32)).to_rvalue() + } + else { + panic!("Unexpected type {:?}", value_type); + } + } + + fn insert_value(&mut self, aggregate_value: RValue<'gcc>, value: RValue<'gcc>, idx: u64) -> RValue<'gcc> { + // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays. + assert_eq!(idx as usize as u64, idx); + let value_type = aggregate_value.get_type(); + + let lvalue = + if value_type.is_array().is_some() { + let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); + self.context.new_array_access(None, aggregate_value, index) + } + else if value_type.is_vector().is_some() { + panic!(); + } + else if let Some(pointer_type) = value_type.get_pointee() { + if let Some(struct_type) = pointer_type.is_struct() { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)) + } + else { + panic!("Unexpected type {:?}", value_type); + } + } + else { + panic!("Unexpected type {:?}", value_type); + }; + + let lvalue_type = lvalue.to_rvalue().get_type(); + let value = + // NOTE: sometimes, rustc will create a value with the wrong type. + if lvalue_type != value.get_type() { + self.context.new_cast(None, value, lvalue_type) + } + else { + value + }; + + self.llbb().add_assignment(None, lvalue, value); + + aggregate_value + } + + fn landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>, _num_clauses: usize) -> RValue<'gcc> { + let field1 = self.context.new_field(None, self.u8_type, "landing_pad_field_1"); + let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1"); + let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]); + self.current_func().new_local(None, struct_type.as_type(), "landing_pad") + .to_rvalue() + // TODO(antoyo): Properly implement unwinding. + // the above is just to make the compilation work as it seems + // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort. + } + + fn set_cleanup(&mut self, _landing_pad: RValue<'gcc>) { + // TODO(antoyo) + } + + fn resume(&mut self, _exn: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn cleanup_pad(&mut self, _parent: Option>, _args: &[RValue<'gcc>]) -> Funclet { + unimplemented!(); + } + + fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option>) -> RValue<'gcc> { + unimplemented!(); + } + + fn catch_pad(&mut self, _parent: RValue<'gcc>, _args: &[RValue<'gcc>]) -> Funclet { + unimplemented!(); + } + + fn catch_switch(&mut self, _parent: Option>, _unwind: Option>, _num_handlers: usize) -> RValue<'gcc> { + unimplemented!(); + } + + fn add_handler(&mut self, _catch_switch: RValue<'gcc>, _handler: Block<'gcc>) { + unimplemented!(); + } + + fn set_personality_fn(&mut self, _personality: RValue<'gcc>) { + // TODO(antoyo) + } + + // Atomic Operations + fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { + let expected = self.current_func().new_local(None, cmp.get_type(), "expected"); + self.llbb().add_assignment(None, expected, cmp); + let success = self.compare_exchange(dst, expected, src, order, failure_order, weak); + + let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false); + let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result"); + let align = Align::from_bits(64).expect("align"); // TODO(antoyo): use good align. + + let value_type = result.to_rvalue().get_type(); + if let Some(struct_type) = value_type.is_struct() { + self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align); + // NOTE: since success contains the call to the intrinsic, it must be stored before + // expected so that we store expected after the call. + self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align); + } + // TODO(antoyo): handle when value is not a struct. + + result.to_rvalue() + } + + fn atomic_rmw(&mut self, op: AtomicRmwBinOp, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> { + let size = self.cx.int_width(src.get_type()) / 8; + let name = + match op { + AtomicRmwBinOp::AtomicXchg => format!("__atomic_exchange_{}", size), + AtomicRmwBinOp::AtomicAdd => format!("__atomic_fetch_add_{}", size), + AtomicRmwBinOp::AtomicSub => format!("__atomic_fetch_sub_{}", size), + AtomicRmwBinOp::AtomicAnd => format!("__atomic_fetch_and_{}", size), + AtomicRmwBinOp::AtomicNand => format!("__atomic_fetch_nand_{}", size), + AtomicRmwBinOp::AtomicOr => format!("__atomic_fetch_or_{}", size), + AtomicRmwBinOp::AtomicXor => format!("__atomic_fetch_xor_{}", size), + AtomicRmwBinOp::AtomicMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order), + AtomicRmwBinOp::AtomicMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order), + AtomicRmwBinOp::AtomicUMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order), + AtomicRmwBinOp::AtomicUMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order), + }; + + + let atomic_function = self.context.get_builtin_function(name); + let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + + let void_ptr_type = self.context.new_type::<*mut ()>(); + let volatile_void_ptr_type = void_ptr_type.make_volatile(); + let dst = self.context.new_cast(None, dst, volatile_void_ptr_type); + // FIXME(antoyo): not sure why, but we have the wrong type here. + let new_src_type = atomic_function.get_param(1).to_rvalue().get_type(); + let src = self.context.new_cast(None, src, new_src_type); + let res = self.context.new_call(None, atomic_function, &[dst, src, order]); + self.context.new_cast(None, res, src.get_type()) + } + + fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) { + let name = + match scope { + SynchronizationScope::SingleThread => "__atomic_signal_fence", + SynchronizationScope::CrossThread => "__atomic_thread_fence", + }; + let thread_fence = self.context.get_builtin_function(name); + let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); + self.llbb().add_eval(None, self.context.new_call(None, thread_fence, &[order])); + } + + fn set_invariant_load(&mut self, load: RValue<'gcc>) { + // NOTE: Hack to consider vtable function pointer as non-global-variable function pointer. + self.normal_function_addresses.borrow_mut().insert(load); + // TODO(antoyo) + } + + fn lifetime_start(&mut self, _ptr: RValue<'gcc>, _size: Size) { + // TODO(antoyo) + } + + fn lifetime_end(&mut self, _ptr: RValue<'gcc>, _size: Size) { + // TODO(antoyo) + } + + fn call(&mut self, _typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>) -> RValue<'gcc> { + // FIXME(antoyo): remove when having a proper API. + let gcc_func = unsafe { std::mem::transmute(func) }; + if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() { + self.function_call(func, args, funclet) + } + else { + // If it's a not function that was defined, it's a function pointer. + self.function_ptr_call(func, args, funclet) + } + } + + fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> { + // FIXME(antoyo): this does not zero-extend. + if value.get_type().is_bool() && dest_typ.is_i8(&self.cx) { + // FIXME(antoyo): hack because base::from_immediate converts i1 to i8. + // Fix the code in codegen_ssa::base::from_immediate. + return value; + } + self.context.new_cast(None, value, dest_typ) + } + + fn cx(&self) -> &CodegenCx<'gcc, 'tcx> { + self.cx + } + + fn do_not_inline(&mut self, _llret: RValue<'gcc>) { + unimplemented!(); + } + + fn set_span(&mut self, _span: Span) {} + + fn from_immediate(&mut self, val: Self::Value) -> Self::Value { + if self.cx().val_ty(val) == self.cx().type_i1() { + self.zext(val, self.cx().type_i8()) + } + else { + val + } + } + + fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value { + if scalar.is_bool() { + return self.trunc(val, self.cx().type_i1()); + } + val + } + + fn fptoui_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option> { + None + } + + fn fptosi_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option> { + None + } + + fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) { + unimplemented!(); + } +} + +impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { + pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> { + let return_type = v1.get_type(); + let params = [ + self.context.new_parameter(None, return_type, "v1"), + self.context.new_parameter(None, return_type, "v2"), + self.context.new_parameter(None, mask.get_type(), "mask"), + ]; + let shuffle = self.context.new_function(None, FunctionType::Extern, return_type, ¶ms, "_mm_shuffle_epi8", false); + self.context.new_call(None, shuffle, &[v1, v2, mask]) + } +} + +impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> { + fn get_static(&mut self, def_id: DefId) -> RValue<'gcc> { + // Forward to the `get_static` method of `CodegenCx` + self.cx().get_static(def_id).get_address(None) + } +} + +impl<'tcx> HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + self.cx.param_env() + } +} + +impl<'tcx> HasTargetSpec for Builder<'_, '_, 'tcx> { + fn target_spec(&self) -> &Target { + &self.cx.target_spec() + } +} + +trait ToGccComp { + fn to_gcc_comparison(&self) -> ComparisonOp; +} + +impl ToGccComp for IntPredicate { + fn to_gcc_comparison(&self) -> ComparisonOp { + match *self { + IntPredicate::IntEQ => ComparisonOp::Equals, + IntPredicate::IntNE => ComparisonOp::NotEquals, + IntPredicate::IntUGT => ComparisonOp::GreaterThan, + IntPredicate::IntUGE => ComparisonOp::GreaterThanEquals, + IntPredicate::IntULT => ComparisonOp::LessThan, + IntPredicate::IntULE => ComparisonOp::LessThanEquals, + IntPredicate::IntSGT => ComparisonOp::GreaterThan, + IntPredicate::IntSGE => ComparisonOp::GreaterThanEquals, + IntPredicate::IntSLT => ComparisonOp::LessThan, + IntPredicate::IntSLE => ComparisonOp::LessThanEquals, + } + } +} + +impl ToGccComp for RealPredicate { + fn to_gcc_comparison(&self) -> ComparisonOp { + // TODO(antoyo): check that ordered vs non-ordered is respected. + match *self { + RealPredicate::RealPredicateFalse => unreachable!(), + RealPredicate::RealOEQ => ComparisonOp::Equals, + RealPredicate::RealOGT => ComparisonOp::GreaterThan, + RealPredicate::RealOGE => ComparisonOp::GreaterThanEquals, + RealPredicate::RealOLT => ComparisonOp::LessThan, + RealPredicate::RealOLE => ComparisonOp::LessThanEquals, + RealPredicate::RealONE => ComparisonOp::NotEquals, + RealPredicate::RealORD => unreachable!(), + RealPredicate::RealUNO => unreachable!(), + RealPredicate::RealUEQ => ComparisonOp::Equals, + RealPredicate::RealUGT => ComparisonOp::GreaterThan, + RealPredicate::RealUGE => ComparisonOp::GreaterThan, + RealPredicate::RealULT => ComparisonOp::LessThan, + RealPredicate::RealULE => ComparisonOp::LessThan, + RealPredicate::RealUNE => ComparisonOp::NotEquals, + RealPredicate::RealPredicateTrue => unreachable!(), + } + } +} + +#[repr(C)] +#[allow(non_camel_case_types)] +enum MemOrdering { + __ATOMIC_RELAXED, + __ATOMIC_CONSUME, + __ATOMIC_ACQUIRE, + __ATOMIC_RELEASE, + __ATOMIC_ACQ_REL, + __ATOMIC_SEQ_CST, +} + +trait ToGccOrdering { + fn to_gcc(self) -> i32; +} + +impl ToGccOrdering for AtomicOrdering { + fn to_gcc(self) -> i32 { + use MemOrdering::*; + + let ordering = + match self { + AtomicOrdering::NotAtomic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. + AtomicOrdering::Unordered => __ATOMIC_RELAXED, + AtomicOrdering::Monotonic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same. + AtomicOrdering::Acquire => __ATOMIC_ACQUIRE, + AtomicOrdering::Release => __ATOMIC_RELEASE, + AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL, + AtomicOrdering::SequentiallyConsistent => __ATOMIC_SEQ_CST, + }; + ordering as i32 + } +} diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs new file mode 100644 index 0000000000000..76419b103d049 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -0,0 +1,77 @@ +use gccjit::{FunctionType, RValue}; +use rustc_codegen_ssa::traits::BaseTypeMethods; +use rustc_middle::ty::{self, Instance, TypeFoldable}; +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; + +use crate::abi::FnAbiGccExt; +use crate::context::CodegenCx; + +/// Codegens a reference to a fn/method item, monomorphizing and +/// inlining as it goes. +/// +/// # Parameters +/// +/// - `cx`: the crate context +/// - `instance`: the instance to be instantiated +pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> RValue<'gcc> { + let tcx = cx.tcx(); + + assert!(!instance.substs.needs_infer()); + assert!(!instance.substs.has_escaping_bound_vars()); + + if let Some(&func) = cx.function_instances.borrow().get(&instance) { + return func; + } + + let sym = tcx.symbol_name(instance).name; + + let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); + + let func = + if let Some(func) = cx.get_declared_value(&sym) { + // Create a fn pointer with the new signature. + let ptrty = fn_abi.ptr_to_gcc_type(cx); + + // This is subtle and surprising, but sometimes we have to bitcast + // the resulting fn pointer. The reason has to do with external + // functions. If you have two crates that both bind the same C + // library, they may not use precisely the same types: for + // example, they will probably each declare their own structs, + // which are distinct types from LLVM's point of view (nominal + // types). + // + // Now, if those two crates are linked into an application, and + // they contain inlined code, you can wind up with a situation + // where both of those functions wind up being loaded into this + // application simultaneously. In that case, the same function + // (from LLVM's point of view) requires two types. But of course + // LLVM won't allow one function to have two types. + // + // What we currently do, therefore, is declare the function with + // one of the two types (whichever happens to come first) and then + // bitcast as needed when the function is referenced to make sure + // it has the type we expect. + // + // This can occur on either a crate-local or crate-external + // reference. It also occurs when testing libcore and in some + // other weird situations. Annoying. + if cx.val_ty(func) != ptrty { + // TODO(antoyo): cast the pointer. + func + } + else { + func + } + } + else { + cx.linkage.set(FunctionType::Extern); + let func = cx.declare_fn(&sym, &fn_abi); + + // TODO(antoyo): set linkage and attributes. + func + }; + + cx.function_instances.borrow_mut().insert(instance, func); + + func +} diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs new file mode 100644 index 0000000000000..bda08b653f059 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -0,0 +1,450 @@ +use std::convert::TryFrom; +use std::convert::TryInto; + +use gccjit::LValue; +use gccjit::{Block, CType, RValue, Type, ToRValue}; +use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::traits::{ + BaseTypeMethods, + ConstMethods, + DerivedTypeMethods, + MiscMethods, + StaticMethods, +}; +use rustc_middle::mir::Mutability; +use rustc_middle::ty::ScalarInt; +use rustc_middle::ty::layout::{TyAndLayout, LayoutOf}; +use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar}; +use rustc_span::Symbol; +use rustc_target::abi::{self, HasDataLayout, Pointer, Size}; + +use crate::consts::const_alloc_to_gcc; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn const_bytes(&self, bytes: &[u8]) -> RValue<'gcc> { + bytes_in_context(self, bytes) + } + + fn const_cstr(&self, symbol: Symbol, _null_terminated: bool) -> LValue<'gcc> { + // TODO(antoyo): handle null_terminated. + if let Some(&value) = self.const_cstr_cache.borrow().get(&symbol) { + return value; + } + + let global = self.global_string(&*symbol.as_str()); + + self.const_cstr_cache.borrow_mut().insert(symbol, global); + global + } + + fn global_string(&self, string: &str) -> LValue<'gcc> { + // TODO(antoyo): handle non-null-terminated strings. + let string = self.context.new_string_literal(&*string); + let sym = self.generate_local_symbol_name("str"); + let global = self.declare_private_global(&sym, self.val_ty(string)); + global.global_set_initializer_value(string); + global + // TODO(antoyo): set linkage. + } + + pub fn inttoptr(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + let func = block.get_function(); + let local = func.new_local(None, value.get_type(), "intLocal"); + block.add_assignment(None, local, value); + let value_address = local.get_address(None); + + let ptr = self.context.new_cast(None, value_address, dest_ty.make_pointer()); + ptr.dereference(None).to_rvalue() + } + + pub fn ptrtoint(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): when libgccjit allow casting from pointer to int, remove this. + let func = block.get_function(); + let local = func.new_local(None, value.get_type(), "ptrLocal"); + block.add_assignment(None, local, value); + let ptr_address = local.get_address(None); + + let ptr = self.context.new_cast(None, ptr_address, dest_ty.make_pointer()); + ptr.dereference(None).to_rvalue() + } +} + +pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> { + let context = &cx.context; + let byte_type = context.new_type::(); + let typ = context.new_array_type(None, byte_type, bytes.len() as i32); + let elements: Vec<_> = + bytes.iter() + .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)) + .collect(); + context.new_rvalue_from_array(None, typ, &elements) +} + +pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool { + typ.get_pointee().is_some() +} + +impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { + if type_is_pointer(typ) { + self.context.new_null(typ) + } + else { + self.const_int(typ, 0) + } + } + + fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { + let local = self.current_func.borrow().expect("func") + .new_local(None, typ, "undefined"); + if typ.is_struct().is_some() { + // NOTE: hack to workaround a limitation of the rustc API: see comment on + // CodegenCx.structs_as_pointer + let pointer = local.get_address(None); + self.structs_as_pointer.borrow_mut().insert(pointer); + pointer + } + else { + local.to_rvalue() + } + } + + fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> { + self.context.new_rvalue_from_long(typ, i64::try_from(int).expect("i64::try_from")) + } + + fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> { + self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64) + } + + fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> { + let num64: Result = num.try_into(); + if let Ok(num) = num64 { + // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant. + // The operations >> 64 and | low are making the normal case a non-constant. + return self.context.new_rvalue_from_long(typ, num as i64); + } + + if num >> 64 != 0 { + // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()? + let low = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64); + let high = self.context.new_rvalue_from_long(typ, (num >> 64) as u64 as i64); + + let sixty_four = self.context.new_rvalue_from_long(typ, 64); + (high << sixty_four) | self.context.new_cast(None, low, typ) + } + else if typ.is_i128(self) { + let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64); + self.context.new_cast(None, num, typ) + } + else { + self.context.new_rvalue_from_long(typ, num as u64 as i64) + } + } + + fn const_bool(&self, val: bool) -> RValue<'gcc> { + self.const_uint(self.type_i1(), val as u64) + } + + fn const_i32(&self, i: i32) -> RValue<'gcc> { + self.const_int(self.type_i32(), i as i64) + } + + fn const_u32(&self, i: u32) -> RValue<'gcc> { + self.const_uint(self.type_u32(), i as u64) + } + + fn const_u64(&self, i: u64) -> RValue<'gcc> { + self.const_uint(self.type_u64(), i) + } + + fn const_usize(&self, i: u64) -> RValue<'gcc> { + let bit_size = self.data_layout().pointer_size.bits(); + if bit_size < 64 { + // make sure it doesn't overflow + assert!(i < (1 << bit_size)); + } + + self.const_uint(self.usize_type, i) + } + + fn const_u8(&self, _i: u8) -> RValue<'gcc> { + unimplemented!(); + } + + fn const_real(&self, _t: Type<'gcc>, _val: f64) -> RValue<'gcc> { + unimplemented!(); + } + + fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) { + let len = s.as_str().len(); + let cs = self.const_ptrcast(self.const_cstr(s, false).get_address(None), + self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)), + ); + (cs, self.const_usize(len as u64)) + } + + fn const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc> { + let fields: Vec<_> = values.iter() + .map(|value| value.get_type()) + .collect(); + // TODO(antoyo): cache the type? It's anonymous, so probably not. + let typ = self.type_struct(&fields, packed); + let struct_type = typ.is_struct().expect("struct type"); + self.context.new_rvalue_from_struct(None, struct_type, values) + } + + fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option { + // TODO(antoyo) + None + } + + fn const_to_opt_u128(&self, _v: RValue<'gcc>, _sign_ext: bool) -> Option { + // TODO(antoyo) + None + } + + fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> { + let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() }; + match cv { + Scalar::Int(ScalarInt::ZST) => { + assert_eq!(0, layout.value.size(self).bytes()); + self.const_undef(self.type_ix(0)) + } + Scalar::Int(int) => { + let data = int.assert_bits(layout.value.size(self)); + + // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code + // the paths for floating-point values. + if ty == self.float_type { + return self.context.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64); + } + else if ty == self.double_type { + return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64)); + } + + let value = self.const_uint_big(self.type_ix(bitsize), data); + if layout.value == Pointer { + self.inttoptr(self.current_block.borrow().expect("block"), value, ty) + } else { + self.const_bitcast(value, ty) + } + } + Scalar::Ptr(ptr, _size) => { + let (alloc_id, offset) = ptr.into_parts(); + let base_addr = + match self.tcx.global_alloc(alloc_id) { + GlobalAlloc::Memory(alloc) => { + let init = const_alloc_to_gcc(self, alloc); + let value = + match alloc.mutability { + Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), + _ => self.static_addr_of(init, alloc.align, None), + }; + if !self.sess().fewer_names() { + // TODO(antoyo): set value name. + } + value + }, + GlobalAlloc::Function(fn_instance) => { + self.get_fn_addr(fn_instance) + }, + GlobalAlloc::Static(def_id) => { + assert!(self.tcx.is_static(def_id)); + self.get_static(def_id).get_address(None) + }, + }; + let ptr_type = base_addr.get_type(); + 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.value != Pointer { + self.const_bitcast(ptr.dereference(None).to_rvalue(), ty) + } + else { + self.const_bitcast(ptr, ty) + } + } + } + } + + fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value { + const_alloc_to_gcc(self, alloc) + } + + fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: &Allocation, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> { + assert_eq!(alloc.align, layout.align.abi); + let ty = self.type_ptr_to(layout.gcc_type(self, true)); + let value = + if layout.size == Size::ZERO { + let value = self.const_usize(alloc.align.bytes()); + self.context.new_cast(None, value, ty) + } + else { + let init = const_alloc_to_gcc(self, alloc); + let base_addr = self.static_addr_of(init, alloc.align, None); + + let array = self.const_bitcast(base_addr, self.type_i8p()); + let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None); + self.const_bitcast(value, ty) + }; + PlaceRef::new_sized(value, layout) + } + + fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> { + self.context.new_cast(None, val, ty) + } +} + +pub trait SignType<'gcc, 'tcx> { + fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; + fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; +} + +impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> { + fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.is_i8(cx) || self.is_i16(cx) || self.is_i32(cx) || self.is_i64(cx) || self.is_i128(cx) + } + + fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.is_u8(cx) || self.is_u16(cx) || self.is_u32(cx) || self.is_u64(cx) || self.is_u128(cx) + } + + fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + if self.is_u8(cx) { + cx.i8_type + } + else if self.is_u16(cx) { + cx.i16_type + } + else if self.is_u32(cx) { + cx.i32_type + } + else if self.is_u64(cx) { + cx.i64_type + } + else if self.is_u128(cx) { + cx.i128_type + } + else { + self.clone() + } + } + + fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + if self.is_i8(cx) { + cx.u8_type + } + else if self.is_i16(cx) { + cx.u16_type + } + else if self.is_i32(cx) { + cx.u32_type + } + else if self.is_i64(cx) { + cx.u64_type + } + else if self.is_i128(cx) { + cx.u128_type + } + else { + self.clone() + } + } +} + +pub trait TypeReflection<'gcc, 'tcx> { + fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + + fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + + fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; + fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; +} + +impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> { + fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u8_type + } + + fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u16_type + } + + fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.uint_type + } + + fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.ulong_type + } + + fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.ulonglong_type + } + + fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.i8_type + } + + fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u8_type + } + + fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.i16_type + } + + fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u16_type + } + + fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.i32_type + } + + fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u32_type + } + + fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.i64_type + } + + fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.u64_type + } + + fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.context.new_c_type(CType::Int128t) + } + + fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.context.new_c_type(CType::UInt128t) + } + + fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.context.new_type::() + } + + fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool { + self.unqualified() == cx.context.new_type::() + } +} diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs new file mode 100644 index 0000000000000..205498acc3187 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -0,0 +1,390 @@ +use gccjit::{LValue, RValue, ToRValue, Type}; +use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods}; +use rustc_hir as hir; +use rustc_hir::Node; +use rustc_middle::{bug, span_bug}; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::mir::interpret::{self, Allocation, ErrorHandled, Scalar as InterpScalar, read_target_uint}; +use rustc_span::Span; +use rustc_span::def_id::DefId; +use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange}; + +use crate::base; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { + if value.get_type() == self.bool_type.make_pointer() { + if let Some(pointee) = typ.get_pointee() { + if pointee.is_vector().is_some() { + panic!() + } + } + } + self.context.new_bitcast(None, value, typ) + } +} + +impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { + fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { + if let Some(global_value) = self.const_globals.borrow().get(&cv) { + // TODO(antoyo): upgrade alignment. + return *global_value; + } + let global_value = self.static_addr_of_mut(cv, align, kind); + // TODO(antoyo): set global constant. + self.const_globals.borrow_mut().insert(cv, global_value); + global_value + } + + fn codegen_static(&self, def_id: DefId, is_mutable: bool) { + let attrs = self.tcx.codegen_fn_attrs(def_id); + + let value = + match codegen_static_initializer(&self, def_id) { + Ok((value, _)) => value, + // Error has already been reported + Err(_) => return, + }; + + let global = self.get_static(def_id); + + // boolean SSA values are i1, but they have to be stored in i8 slots, + // otherwise some LLVM optimization passes don't work as expected + let val_llty = self.val_ty(value); + let value = + if val_llty == self.type_i1() { + unimplemented!(); + } + else { + value + }; + + let instance = Instance::mono(self.tcx, def_id); + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let gcc_type = self.layout_of(ty).gcc_type(self, true); + + // TODO(antoyo): set alignment. + + let value = + if value.get_type() != gcc_type { + self.context.new_bitcast(None, value, gcc_type) + } + else { + value + }; + global.global_set_initializer_value(value); + + // As an optimization, all shared statics which do not have interior + // mutability are placed into read-only memory. + if !is_mutable { + if self.type_is_freeze(ty) { + // TODO(antoyo): set global constant. + } + } + + if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + // Do not allow LLVM to change the alignment of a TLS on macOS. + // + // By default a global's alignment can be freely increased. + // This allows LLVM to generate more performant instructions + // e.g., using load-aligned into a SIMD register. + // + // However, on macOS 10.10 or below, the dynamic linker does not + // respect any alignment given on the TLS (radar 24221680). + // This will violate the alignment assumption, and causing segfault at runtime. + // + // This bug is very easy to trigger. In `println!` and `panic!`, + // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS, + // which the values would be `mem::replace`d on initialization. + // The implementation of `mem::replace` will use SIMD + // whenever the size is 32 bytes or higher. LLVM notices SIMD is used + // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary, + // which macOS's dyld disregarded and causing crashes + // (see issues #51794, #51758, #50867, #48866 and #44056). + // + // To workaround the bug, we trick LLVM into not increasing + // the global's alignment by explicitly assigning a section to it + // (equivalent to automatically generating a `#[link_section]` attribute). + // See the comment in the `GlobalValue::canIncreaseAlignment()` function + // of `lib/IR/Globals.cpp` for why this works. + // + // When the alignment is not increased, the optimized `mem::replace` + // will use load-unaligned instructions instead, and thus avoiding the crash. + // + // We could remove this hack whenever we decide to drop macOS 10.10 support. + if self.tcx.sess.target.options.is_like_osx { + // The `inspect` method is okay here because we checked relocations, and + // because we are doing this access to inspect the final interpreter state + // (not as part of the interpreter execution). + // + // FIXME: This check requires that the (arbitrary) value of undefined bytes + // happens to be zero. Instead, we should only check the value of defined bytes + // and set all undefined bytes to zero if this allocation is headed for the + // BSS. + unimplemented!(); + } + } + + // Wasm statics with custom link sections get special treatment as they + // go into custom sections of the wasm executable. + if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") { + if let Some(_section) = attrs.link_section { + unimplemented!(); + } + } else { + // TODO(antoyo): set link section. + } + + if attrs.flags.contains(CodegenFnAttrFlags::USED) { + self.add_used_global(global.to_rvalue()); + } + } + + /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*. + fn add_used_global(&self, _global: RValue<'gcc>) { + // TODO(antoyo) + } + + fn add_compiler_used_global(&self, _global: RValue<'gcc>) { + // TODO(antoyo) + } +} + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn static_addr_of_mut(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { + let global = + match kind { + Some(kind) if !self.tcx.sess.fewer_names() => { + let name = self.generate_local_symbol_name(kind); + // TODO(antoyo): check if it's okay that TLS is off here. + // TODO(antoyo): check if it's okay that link_section is None here. + // TODO(antoyo): set alignment here as well. + let global = self.define_global(&name[..], self.val_ty(cv), false, None); + // TODO(antoyo): set linkage. + global + } + _ => { + let typ = self.val_ty(cv).get_aligned(align.bytes()); + let global = self.declare_unnamed_global(typ); + global + }, + }; + // FIXME(antoyo): I think the name coming from generate_local_symbol_name() above cannot be used + // globally. + global.global_set_initializer_value(cv); + // TODO(antoyo): set unnamed address. + global.get_address(None) + } + + pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> { + let instance = Instance::mono(self.tcx, def_id); + let fn_attrs = self.tcx.codegen_fn_attrs(def_id); + if let Some(&global) = self.instances.borrow().get(&instance) { + return global; + } + + let defined_in_current_codegen_unit = + self.codegen_unit.items().contains_key(&MonoItem::Static(def_id)); + assert!( + !defined_in_current_codegen_unit, + "consts::get_static() should always hit the cache for \ + statics defined in the same CGU, but did not for `{:?}`", + def_id + ); + + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let sym = self.tcx.symbol_name(instance).name; + + let global = + if let Some(def_id) = def_id.as_local() { + let id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let llty = self.layout_of(ty).gcc_type(self, true); + // FIXME: refactor this to work without accessing the HIR + let global = match self.tcx.hir().get(id) { + Node::Item(&hir::Item { span, kind: hir::ItemKind::Static(..), .. }) => { + if let Some(global) = self.get_declared_value(&sym) { + if self.val_ty(global) != self.type_ptr_to(llty) { + span_bug!(span, "Conflicting types for static"); + } + } + + let is_tls = fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); + let global = self.declare_global(&sym, llty, is_tls, fn_attrs.link_section); + + if !self.tcx.is_reachable_non_generic(def_id) { + // TODO(antoyo): set visibility. + } + + global + } + + Node::ForeignItem(&hir::ForeignItem { + span, + kind: hir::ForeignItemKind::Static(..), + .. + }) => { + let fn_attrs = self.tcx.codegen_fn_attrs(def_id); + check_and_apply_linkage(&self, &fn_attrs, ty, sym, span) + } + + item => bug!("get_static: expected static, found {:?}", item), + }; + + global + } + else { + // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? + //debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id)); + + let attrs = self.tcx.codegen_fn_attrs(def_id); + let span = self.tcx.def_span(def_id); + let global = check_and_apply_linkage(&self, &attrs, ty, sym, span); + + let needs_dll_storage_attr = false; // TODO(antoyo) + + // If this assertion triggers, there's something wrong with commandline + // argument validation. + debug_assert!( + !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled() + && self.tcx.sess.target.options.is_like_msvc + && self.tcx.sess.opts.cg.prefer_dynamic) + ); + + if needs_dll_storage_attr { + // This item is external but not foreign, i.e., it originates from an external Rust + // crate. Since we don't know whether this crate will be linked dynamically or + // statically in the final application, we always mark such symbols as 'dllimport'. + // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs + // to make things work. + // + // However, in some scenarios we defer emission of statics to downstream + // crates, so there are cases where a static with an upstream DefId + // is actually present in the current crate. We can find out via the + // is_codegened_item query. + if !self.tcx.is_codegened_item(def_id) { + unimplemented!(); + } + } + global + }; + + // TODO(antoyo): set dll storage class. + + self.instances.borrow_mut().insert(instance, global); + global + } +} + +pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Allocation) -> RValue<'gcc> { + let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); + let dl = cx.data_layout(); + let pointer_size = dl.pointer_size.bytes() as usize; + + let mut next_offset = 0; + for &(offset, alloc_id) in alloc.relocations().iter() { + let offset = offset.bytes(); + assert_eq!(offset as usize as u64, offset); + let offset = offset as usize; + if offset > next_offset { + // This `inspect` is okay since we have checked that it is not within a relocation, it + // is within the bounds of the allocation, and it doesn't affect interpreter execution + // (we inspect the result after interpreter execution). Any undef byte is replaced with + // some arbitrary byte value. + // + // FIXME: relay undef bytes to codegen as undef const bytes + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset); + llvals.push(cx.const_bytes(bytes)); + } + let ptr_offset = + read_target_uint( dl.endian, + // This `inspect` is okay since it is within the bounds of the allocation, it doesn't + // affect interpreter execution (we inspect the result after interpreter execution), + // and we properly interpret the relocation as a relocation pointer offset. + alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)), + ) + .expect("const_alloc_to_llvm: could not read relocation pointer") + as u64; + llvals.push(cx.scalar_to_backend( + InterpScalar::from_pointer( + interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)), + &cx.tcx, + ), + abi::Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } }, + cx.type_i8p(), + )); + next_offset = offset + pointer_size; + } + if alloc.len() >= next_offset { + let range = next_offset..alloc.len(); + // This `inspect` is okay since we have check that it is after all relocations, it is + // within the bounds of the allocation, and it doesn't affect interpreter execution (we + // inspect the result after interpreter execution). Any undef byte is replaced with some + // arbitrary byte value. + // + // FIXME: relay undef bytes to codegen as undef const bytes + let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range); + llvals.push(cx.const_bytes(bytes)); + } + + cx.const_struct(&llvals, true) +} + +pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> { + let alloc = cx.tcx.eval_static_initializer(def_id)?; + Ok((const_alloc_to_gcc(cx, alloc), alloc)) +} + +fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, span: Span) -> LValue<'gcc> { + let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); + let llty = cx.layout_of(ty).gcc_type(cx, true); + if let Some(linkage) = attrs.linkage { + // If this is a static with a linkage specified, then we need to handle + // it a little specially. The typesystem prevents things like &T and + // extern "C" fn() from being non-null, so we can't just declare a + // static and call it a day. Some linkages (like weak) will make it such + // that the static actually has a null value. + let llty2 = + if let ty::RawPtr(ref mt) = ty.kind() { + cx.layout_of(mt.ty).gcc_type(cx, true) + } + else { + cx.sess().span_fatal( + span, + "must have type `*const T` or `*mut T` due to `#[linkage]` attribute", + ) + }; + // Declare a symbol `foo` with the desired linkage. + let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage)); + + // Declare an internal global `extern_with_linkage_foo` which + // is initialized with the address of `foo`. If `foo` is + // discarded during linking (for example, if `foo` has weak + // linkage and there are no definitions), then + // `extern_with_linkage_foo` will instead be initialized to + // zero. + let mut real_name = "_rust_extern_with_linkage_".to_string(); + real_name.push_str(&sym); + let global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section); + // TODO(antoyo): set linkage. + global2.global_set_initializer_value(global1.get_address(None)); + // TODO(antoyo): use global_set_initializer() when it will work. + global2 + } + else { + // Generate an external declaration. + // FIXME(nagisa): investigate whether it can be changed into define_global + + // Thread-local statics in some other crate need to *always* be linked + // against in a thread-local fashion, so we need to be sure to apply the + // thread-local attribute locally if it was present remotely. If we + // don't do this then linker errors can be generated where the linker + // complains that one object files has a thread local version of the + // symbol and another one doesn't. + cx.declare_global(&sym, llty, is_tls, attrs.link_section) + } +} diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs new file mode 100644 index 0000000000000..7677ade7314e5 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -0,0 +1,475 @@ +use std::cell::{Cell, RefCell}; + +use gccjit::{ + Block, + Context, + CType, + Function, + FunctionType, + LValue, + RValue, + Struct, + Type, +}; +use rustc_codegen_ssa::base::wants_msvc_seh; +use rustc_codegen_ssa::traits::{ + BackendTypes, + MiscMethods, +}; +use rustc_data_structures::base_n; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_middle::span_bug; +use rustc_middle::mir::mono::CodegenUnit; +use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; +use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers}; +use rustc_session::Session; +use rustc_span::{Span, Symbol}; +use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; +use rustc_target::spec::{HasTargetSpec, Target, TlsModel}; + +use crate::callee::get_fn; +use crate::declare::mangle_name; + +#[derive(Clone)] +pub struct FuncSig<'gcc> { + pub params: Vec>, + pub return_type: Type<'gcc>, +} + +pub struct CodegenCx<'gcc, 'tcx> { + pub check_overflow: bool, + pub codegen_unit: &'tcx CodegenUnit<'tcx>, + pub context: &'gcc Context<'gcc>, + + // TODO(antoyo): First set it to a dummy block to avoid using Option? + pub current_block: RefCell>>, + pub current_func: RefCell>>, + pub normal_function_addresses: RefCell>>, + + pub functions: RefCell>>, + + pub tls_model: gccjit::TlsModel, + + pub bool_type: Type<'gcc>, + pub i8_type: Type<'gcc>, + pub i16_type: Type<'gcc>, + pub i32_type: Type<'gcc>, + pub i64_type: Type<'gcc>, + pub i128_type: Type<'gcc>, + pub isize_type: Type<'gcc>, + + pub u8_type: Type<'gcc>, + pub u16_type: Type<'gcc>, + pub u32_type: Type<'gcc>, + pub u64_type: Type<'gcc>, + pub u128_type: Type<'gcc>, + pub usize_type: Type<'gcc>, + + pub int_type: Type<'gcc>, + pub uint_type: Type<'gcc>, + pub long_type: Type<'gcc>, + pub ulong_type: Type<'gcc>, + pub ulonglong_type: Type<'gcc>, + pub sizet_type: Type<'gcc>, + + pub float_type: Type<'gcc>, + pub double_type: Type<'gcc>, + + pub linkage: Cell, + pub scalar_types: RefCell, Type<'gcc>>>, + pub types: RefCell, Option), Type<'gcc>>>, + pub tcx: TyCtxt<'tcx>, + + pub struct_types: RefCell>, Type<'gcc>>>, + + pub types_with_fields_to_set: RefCell, (Struct<'gcc>, TyAndLayout<'tcx>)>>, + + /// Cache instances of monomorphic and polymorphic items + pub instances: RefCell, LValue<'gcc>>>, + /// Cache function instances of monomorphic and polymorphic items + pub function_instances: RefCell, RValue<'gcc>>>, + /// Cache generated vtables + pub vtables: RefCell, Option>), RValue<'gcc>>>, + + /// Cache of emitted const globals (value -> global) + pub const_globals: RefCell, RValue<'gcc>>>, + + /// Cache of constant strings, + pub const_cstr_cache: RefCell>>, + + /// Cache of globals. + pub globals: RefCell>>, + + /// A counter that is used for generating local symbol names + local_gen_sym_counter: Cell, + pub global_gen_sym_counter: Cell, + + eh_personality: Cell>>, + + pub pointee_infos: RefCell, Size), Option>>, + + /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such, + /// `const_undef()` returns struct as pointer so that they can later be assigned a value. + /// As such, this set remembers which of these pointers were returned by this function so that + /// they can be deferenced later. + /// FIXME(antoyo): fix the rustc API to avoid having this hack. + pub structs_as_pointer: RefCell>>, +} + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>) -> Self { + let check_overflow = tcx.sess.overflow_checks(); + // TODO(antoyo): fix this mess. libgccjit seems to return random type when using new_int_type(). + let isize_type = context.new_c_type(CType::LongLong); + let usize_type = context.new_c_type(CType::ULongLong); + let bool_type = context.new_type::(); + let i8_type = context.new_type::(); + let i16_type = context.new_type::(); + let i32_type = context.new_type::(); + let i64_type = context.new_c_type(CType::LongLong); + let i128_type = context.new_c_type(CType::Int128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded? + let u8_type = context.new_type::(); + let u16_type = context.new_type::(); + let u32_type = context.new_type::(); + let u64_type = context.new_c_type(CType::ULongLong); + let u128_type = context.new_c_type(CType::UInt128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded? + + let tls_model = to_gcc_tls_mode(tcx.sess.tls_model()); + + let float_type = context.new_type::(); + let double_type = context.new_type::(); + + let int_type = context.new_c_type(CType::Int); + let uint_type = context.new_c_type(CType::UInt); + let long_type = context.new_c_type(CType::Long); + let ulong_type = context.new_c_type(CType::ULong); + let ulonglong_type = context.new_c_type(CType::ULongLong); + let sizet_type = context.new_c_type(CType::SizeT); + + assert_eq!(isize_type, i64_type); + assert_eq!(usize_type, u64_type); + + let mut functions = FxHashMap::default(); + let builtins = [ + "__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow", + "__builtin_saddll_overflow", /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/ + "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow", + "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow", + "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos", + "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf", + "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf", + "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round", + "__builtin_expect_with_probability", + ]; + + for builtin in builtins.iter() { + functions.insert(builtin.to_string(), context.get_builtin_function(builtin)); + } + + Self { + check_overflow, + codegen_unit, + context, + current_block: RefCell::new(None), + current_func: RefCell::new(None), + normal_function_addresses: Default::default(), + functions: RefCell::new(functions), + + tls_model, + + bool_type, + i8_type, + i16_type, + i32_type, + i64_type, + i128_type, + isize_type, + usize_type, + u8_type, + u16_type, + u32_type, + u64_type, + u128_type, + int_type, + uint_type, + long_type, + ulong_type, + ulonglong_type, + sizet_type, + + float_type, + double_type, + + linkage: Cell::new(FunctionType::Internal), + instances: Default::default(), + function_instances: Default::default(), + vtables: Default::default(), + const_globals: Default::default(), + const_cstr_cache: Default::default(), + globals: Default::default(), + scalar_types: Default::default(), + types: Default::default(), + tcx, + struct_types: Default::default(), + types_with_fields_to_set: Default::default(), + local_gen_sym_counter: Cell::new(0), + global_gen_sym_counter: Cell::new(0), + eh_personality: Cell::new(None), + pointee_infos: Default::default(), + structs_as_pointer: Default::default(), + } + } + + pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> { + let function: Function<'gcc> = unsafe { std::mem::transmute(value) }; + debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(), + "{:?} ({:?}) is not a function", value, value.get_type()); + function + } + + pub fn sess(&self) -> &Session { + &self.tcx.sess + } +} + +impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { + type Value = RValue<'gcc>; + type Function = RValue<'gcc>; + + type BasicBlock = Block<'gcc>; + type Type = Type<'gcc>; + type Funclet = (); // TODO(antoyo) + + type DIScope = (); // TODO(antoyo) + type DILocation = (); // TODO(antoyo) + type DIVariable = (); // TODO(antoyo) +} + +impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn vtables(&self) -> &RefCell, Option>), RValue<'gcc>>> { + &self.vtables + } + + fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> { + let func = get_fn(self, instance); + *self.current_func.borrow_mut() = Some(self.rvalue_as_function(func)); + func + } + + fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { + let func = get_fn(self, instance); + let func = self.rvalue_as_function(func); + let ptr = func.get_address(None); + + // TODO(antoyo): don't do this twice: i.e. in declare_fn and here. + // FIXME(antoyo): the rustc API seems to call get_fn_addr() when not needed (e.g. for FFI). + + self.normal_function_addresses.borrow_mut().insert(ptr); + + ptr + } + + fn eh_personality(&self) -> RValue<'gcc> { + // The exception handling personality function. + // + // If our compilation unit has the `eh_personality` lang item somewhere + // within it, then we just need to codegen that. Otherwise, we're + // building an rlib which will depend on some upstream implementation of + // this function, so we just codegen a generic reference to it. We don't + // specify any of the types for the function, we just make it a symbol + // that LLVM can later use. + // + // Note that MSVC is a little special here in that we don't use the + // `eh_personality` lang item at all. Currently LLVM has support for + // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the + // *name of the personality function* to decide what kind of unwind side + // tables/landing pads to emit. It looks like Dwarf is used by default, + // injecting a dependency on the `_Unwind_Resume` symbol for resuming + // an "exception", but for MSVC we want to force SEH. This means that we + // can't actually have the personality function be our standard + // `rust_eh_personality` function, but rather we wired it up to the + // CRT's custom personality function, which forces LLVM to consider + // landing pads as "landing pads for SEH". + if let Some(llpersonality) = self.eh_personality.get() { + return llpersonality; + } + let tcx = self.tcx; + let llfn = match tcx.lang_items().eh_personality() { + Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr( + ty::Instance::resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + tcx.intern_substs(&[]), + ) + .unwrap().unwrap(), + ), + _ => { + let _name = if wants_msvc_seh(self.sess()) { + "__CxxFrameHandler3" + } else { + "rust_eh_personality" + }; + //let func = self.declare_func(name, self.type_i32(), &[], true); + // FIXME(antoyo): this hack should not be needed. That will probably be removed when + // unwinding support is added. + self.context.new_rvalue_from_int(self.int_type, 0) + } + }; + // TODO(antoyo): apply target cpu attributes. + self.eh_personality.set(Some(llfn)); + llfn + } + + fn sess(&self) -> &Session { + &self.tcx.sess + } + + fn check_overflow(&self) -> bool { + self.check_overflow + } + + fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { + self.codegen_unit + } + + fn used_statics(&self) -> &RefCell>> { + unimplemented!(); + } + + fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) { + // TODO(antoyo) + } + + fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) { + // TODO(antoyo) + } + + fn create_used_variable(&self) { + unimplemented!(); + } + + fn declare_c_main(&self, fn_type: Self::Type) -> Option { + if self.get_declared_value("main").is_none() { + Some(self.declare_cfn("main", fn_type)) + } + else { + // If the symbol already exists, it is an error: for example, the user wrote + // #[no_mangle] extern "C" fn main(..) {..} + // instead of #[start] + None + } + } + + fn compiler_used_statics(&self) -> &RefCell>> { + unimplemented!() + } + + fn create_compiler_used_variable(&self) { + unimplemented!() + } +} + +impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} + +impl<'gcc, 'tcx> HasDataLayout for CodegenCx<'gcc, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> { + fn target_spec(&self) -> &Target { + &self.tcx.sess.target + } +} + +impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { + type LayoutOfResult = TyAndLayout<'tcx>; + + #[inline] + fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! { + if let LayoutError::SizeOverflow(_) = err { + self.sess().span_fatal(span, &err.to_string()) + } else { + span_bug!(span, "failed to get layout for `{}`: {}", ty, err) + } + } +} + +impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> { + type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>; + + #[inline] + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + span: Span, + fn_abi_request: FnAbiRequest<'tcx>, + ) -> ! { + if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err { + self.sess().span_fatal(span, &err.to_string()) + } else { + match fn_abi_request { + FnAbiRequest::OfFnPtr { sig, extra_args } => { + span_bug!( + span, + "`fn_abi_of_fn_ptr({}, {:?})` failed: {}", + sig, + extra_args, + err + ); + } + FnAbiRequest::OfInstance { instance, extra_args } => { + span_bug!( + span, + "`fn_abi_of_instance({}, {:?})` failed: {}", + instance, + extra_args, + err + ); + } + } + } + } +} + +impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + ParamEnv::reveal_all() + } +} + +impl<'b, 'tcx> CodegenCx<'b, 'tcx> { + /// Generates a new symbol name with the given prefix. This symbol name must + /// only be used for definitions with `internal` or `private` linkage. + pub fn generate_local_symbol_name(&self, prefix: &str) -> String { + let idx = self.local_gen_sym_counter.get(); + self.local_gen_sym_counter.set(idx + 1); + // Include a '.' character, so there can be no accidental conflicts with + // user defined names + let mut name = String::with_capacity(prefix.len() + 6); + name.push_str(prefix); + name.push_str("."); + base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name); + name + } +} + +pub fn unit_name<'tcx>(codegen_unit: &CodegenUnit<'tcx>) -> String { + let name = &codegen_unit.name().to_string(); + mangle_name(&name.replace('-', "_")) +} + +fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel { + match tls_model { + TlsModel::GeneralDynamic => gccjit::TlsModel::GlobalDynamic, + TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic, + TlsModel::InitialExec => gccjit::TlsModel::InitialExec, + TlsModel::LocalExec => gccjit::TlsModel::LocalExec, + } +} diff --git a/compiler/rustc_codegen_gcc/src/coverageinfo.rs b/compiler/rustc_codegen_gcc/src/coverageinfo.rs new file mode 100644 index 0000000000000..872fc2472e223 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/coverageinfo.rs @@ -0,0 +1,69 @@ +use gccjit::RValue; +use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods}; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::coverage::{ + CodeRegion, + CounterValueReference, + ExpressionOperandId, + InjectedExpressionId, + Op, +}; +use rustc_middle::ty::Instance; + +use crate::builder::Builder; +use crate::context::CodegenCx; + +impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn set_function_source_hash( + &mut self, + _instance: Instance<'tcx>, + _function_source_hash: u64, + ) -> bool { + unimplemented!(); + } + + fn add_coverage_counter(&mut self, _instance: Instance<'tcx>, _id: CounterValueReference, _region: CodeRegion) -> bool { + // TODO(antoyo) + false + } + + fn add_coverage_counter_expression(&mut self, _instance: Instance<'tcx>, _id: InjectedExpressionId, _lhs: ExpressionOperandId, _op: Op, _rhs: ExpressionOperandId, _region: Option) -> bool { + // TODO(antoyo) + false + } + + fn add_coverage_unreachable(&mut self, _instance: Instance<'tcx>, _region: CodeRegion) -> bool { + // TODO(antoyo) + false + } +} + +impl<'gcc, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn coverageinfo_finalize(&self) { + // TODO(antoyo) + } + + fn get_pgo_func_name_var(&self, _instance: Instance<'tcx>) -> RValue<'gcc> { + unimplemented!(); + } + + /// Functions with MIR-based coverage are normally codegenned _only_ if + /// called. LLVM coverage tools typically expect every function to be + /// defined (even if unused), with at least one call to LLVM intrinsic + /// `instrprof.increment`. + /// + /// Codegen a small function that will never be called, with one counter + /// that will never be incremented. + /// + /// For used/called functions, the coverageinfo was already added to the + /// `function_coverage_map` (keyed by function `Instance`) during codegen. + /// But in this case, since the unused function was _not_ previously + /// codegenned, collect the coverage `CodeRegion`s from the MIR and add + /// them. The first `CodeRegion` is used to add a single counter, with the + /// same counter ID used in the injected `instrprof.increment` intrinsic + /// call. Since the function is never called, all other `CodeRegion`s can be + /// added as `unreachable_region`s. + fn define_unused_fn(&self, _def_id: DefId) { + unimplemented!(); + } +} diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs new file mode 100644 index 0000000000000..4d3b4f04badec --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -0,0 +1,62 @@ +use gccjit::RValue; +use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind}; +use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; +use rustc_middle::mir; +use rustc_middle::ty::{Instance, Ty}; +use rustc_span::{SourceFile, Span, Symbol}; +use rustc_target::abi::Size; +use rustc_target::abi::call::FnAbi; + +use crate::builder::Builder; +use crate::context::CodegenCx; + +impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { + // FIXME(eddyb) find a common convention for all of the debuginfo-related + // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). + fn dbg_var_addr(&mut self, _dbg_var: Self::DIVariable, _scope_metadata: Self::DIScope, _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size]) { + unimplemented!(); + } + + fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { + // TODO(antoyo): insert reference to gdb debug scripts section global. + } + + fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) { + unimplemented!(); + } + + fn set_dbg_loc(&mut self, _dbg_loc: Self::DILocation) { + unimplemented!(); + } +} + +impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn create_vtable_metadata(&self, _ty: Ty<'tcx>, _vtable: Self::Value) { + // TODO(antoyo) + } + + fn create_function_debug_context(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>) -> Option> { + // TODO(antoyo) + None + } + + fn extend_scope_to_file(&self, _scope_metadata: Self::DIScope, _file: &SourceFile) -> Self::DIScope { + unimplemented!(); + } + + fn debuginfo_finalize(&self) { + // TODO(antoyo) + } + + fn create_dbg_var(&self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, _variable_kind: VariableKind, _span: Span) -> Self::DIVariable { + unimplemented!(); + } + + fn dbg_scope_fn(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option>) -> Self::DIScope { + unimplemented!(); + } + + fn dbg_loc(&self, _scope: Self::DIScope, _inlined_at: Option, _span: Span) -> Self::DILocation { + unimplemented!(); + } +} diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs new file mode 100644 index 0000000000000..b79a50d1eee2e --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -0,0 +1,144 @@ +use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type}; +use rustc_codegen_ssa::traits::BaseTypeMethods; +use rustc_middle::ty::Ty; +use rustc_span::Symbol; +use rustc_target::abi::call::FnAbi; + +use crate::abi::FnAbiGccExt; +use crate::context::{CodegenCx, unit_name}; +use crate::intrinsic::llvm; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option) -> LValue<'gcc> { + if self.globals.borrow().contains_key(name) { + let typ = self.globals.borrow().get(name).expect("global").get_type(); + let global = self.context.new_global(None, GlobalKind::Imported, typ, name); + if is_tls { + global.set_tls_model(self.tls_model); + } + if let Some(link_section) = link_section { + global.set_link_section(&link_section.as_str()); + } + global + } + else { + self.declare_global(name, ty, is_tls, link_section) + } + } + + pub fn declare_unnamed_global(&self, ty: Type<'gcc>) -> LValue<'gcc> { + let index = self.global_gen_sym_counter.get(); + self.global_gen_sym_counter.set(index + 1); + let name = format!("global_{}_{}", index, unit_name(&self.codegen_unit)); + self.context.new_global(None, GlobalKind::Exported, ty, &name) + } + + pub fn declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> LValue<'gcc> { + let global = self.context.new_global(None, linkage, ty, name); + let global_address = global.get_address(None); + self.globals.borrow_mut().insert(name.to_string(), global_address); + global + } + + /*pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> { + self.linkage.set(FunctionType::Exported); + let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic); + // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. + unsafe { std::mem::transmute(func) } + }*/ + + pub fn declare_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option) -> LValue<'gcc> { + let global = self.context.new_global(None, GlobalKind::Exported, ty, name); + if is_tls { + global.set_tls_model(self.tls_model); + } + if let Some(link_section) = link_section { + global.set_link_section(&link_section.as_str()); + } + let global_address = global.get_address(None); + self.globals.borrow_mut().insert(name.to_string(), global_address); + global + } + + pub fn declare_private_global(&self, name: &str, ty: Type<'gcc>) -> LValue<'gcc> { + let global = self.context.new_global(None, GlobalKind::Internal, ty, name); + let global_address = global.get_address(None); + self.globals.borrow_mut().insert(name.to_string(), global_address); + global + } + + pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use the fn_type parameter. + let const_string = self.context.new_type::().make_pointer().make_pointer(); + let return_type = self.type_i32(); + let variadic = false; + self.linkage.set(FunctionType::Exported); + let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic); + // NOTE: it is needed to set the current_func here as well, because get_fn() is not called + // for the main function. + *self.current_func.borrow_mut() = Some(func); + // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. + unsafe { std::mem::transmute(func) } + } + + pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> RValue<'gcc> { + let (return_type, params, variadic) = fn_abi.gcc_type(self); + let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, ¶ms, variadic); + // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. + unsafe { std::mem::transmute(func) } + } + + pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option) -> LValue<'gcc> { + self.get_or_insert_global(name, ty, is_tls, link_section) + } + + pub fn get_declared_value(&self, name: &str) -> Option> { + // TODO(antoyo): use a different field than globals, because this seems to return a function? + self.globals.borrow().get(name).cloned() + } +} + +/// Declare a function. +/// +/// If there’s a value with the same name already declared, the function will +/// update the declaration and return existing Value instead. +fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*llvm::CallConv*/, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool) -> Function<'gcc> { + if name.starts_with("llvm.") { + return llvm::intrinsic(name, cx); + } + let func = + if cx.functions.borrow().contains_key(name) { + *cx.functions.borrow().get(name).expect("function") + } + else { + let params: Vec<_> = param_types.into_iter().enumerate() + .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name. + .collect(); + let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, mangle_name(name), variadic); + cx.functions.borrow_mut().insert(name.to_string(), func); + func + }; + + // TODO(antoyo): set function calling convention. + // TODO(antoyo): set unnamed address. + // TODO(antoyo): set no red zone function attribute. + // TODO(antoyo): set attributes for optimisation. + // TODO(antoyo): set attributes for non lazy bind. + + // FIXME(antoyo): invalid cast. + func +} + +// FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _. +// Unsupported characters: `$` and `.`. +pub fn mangle_name(name: &str) -> String { + name.replace(|char: char| { + if !char.is_alphanumeric() && char != '_' { + debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char); + true + } + else { + false + } + }, "_") +} diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs new file mode 100644 index 0000000000000..b074febc521eb --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -0,0 +1,22 @@ +use gccjit::Function; + +use crate::context::CodegenCx; + +pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> { + let _gcc_name = + match name { + "llvm.x86.xgetbv" => { + let gcc_name = "__builtin_trap"; + let func = cx.context.get_builtin_function(gcc_name); + cx.functions.borrow_mut().insert(gcc_name.to_string(), func); + return func; + }, + // NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html + "llvm.x86.sse2.cmp.pd" => "__builtin_ia32_cmppd", + "llvm.x86.sse2.movmsk.pd" => "__builtin_ia32_movmskpd", + "llvm.x86.sse2.pmovmskb.128" => "__builtin_ia32_pmovmskb128", + _ => unimplemented!("unsupported LLVM intrinsic {}", name) + }; + + unimplemented!(); +} diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs new file mode 100644 index 0000000000000..375d422cb25c4 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -0,0 +1,1067 @@ +pub mod llvm; +mod simd; + +use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp}; +use rustc_codegen_ssa::MemFlags; +use rustc_codegen_ssa::base::wants_msvc_seh; +use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error}; +use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; +use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods}; +use rustc_middle::bug; +use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_span::{Span, Symbol, symbol::kw, sym}; +use rustc_target::abi::HasDataLayout; +use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; +use rustc_target::spec::PanicStrategy; + +use crate::abi::GccType; +use crate::builder::Builder; +use crate::common::{SignType, TypeReflection}; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; +use crate::intrinsic::simd::generic_simd_intrinsic; + +fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> Option> { + let gcc_name = match name { + sym::sqrtf32 => "sqrtf", + sym::sqrtf64 => "sqrt", + sym::powif32 => "__builtin_powif", + sym::powif64 => "__builtin_powi", + sym::sinf32 => "sinf", + sym::sinf64 => "sin", + sym::cosf32 => "cosf", + sym::cosf64 => "cos", + sym::powf32 => "powf", + sym::powf64 => "pow", + sym::expf32 => "expf", + sym::expf64 => "exp", + sym::exp2f32 => "exp2f", + sym::exp2f64 => "exp2", + sym::logf32 => "logf", + sym::logf64 => "log", + sym::log10f32 => "log10f", + sym::log10f64 => "log10", + sym::log2f32 => "log2f", + sym::log2f64 => "log2", + sym::fmaf32 => "fmaf", + sym::fmaf64 => "fma", + sym::fabsf32 => "fabsf", + sym::fabsf64 => "fabs", + sym::minnumf32 => "fminf", + sym::minnumf64 => "fmin", + sym::maxnumf32 => "fmaxf", + sym::maxnumf64 => "fmax", + sym::copysignf32 => "copysignf", + sym::copysignf64 => "copysign", + sym::floorf32 => "floorf", + sym::floorf64 => "floor", + sym::ceilf32 => "ceilf", + sym::ceilf64 => "ceil", + sym::truncf32 => "truncf", + sym::truncf64 => "trunc", + sym::rintf32 => "rintf", + sym::rintf64 => "rint", + sym::nearbyintf32 => "nearbyintf", + sym::nearbyintf64 => "nearbyint", + sym::roundf32 => "roundf", + sym::roundf64 => "round", + sym::abort => "abort", + _ => return None, + }; + Some(cx.context.get_builtin_function(&gcc_name)) +} + +impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) { + let tcx = self.tcx; + let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + + let (def_id, substs) = match *callee_ty.kind() { + ty::FnDef(def_id, substs) => (def_id, substs), + _ => bug!("expected fn item type, found {}", callee_ty), + }; + + let sig = callee_ty.fn_sig(tcx); + let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); + let arg_tys = sig.inputs(); + let ret_ty = sig.output(); + let name = tcx.item_name(def_id); + let name_str = &*name.as_str(); + + let llret_ty = self.layout_of(ret_ty).gcc_type(self, true); + let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); + + let simple = get_simple_intrinsic(self, name); + let llval = + match name { + _ if simple.is_some() => { + // FIXME(antoyo): remove this cast when the API supports function. + let func = unsafe { std::mem::transmute(simple.expect("simple")) }; + self.call(self.type_void(), func, &args.iter().map(|arg| arg.immediate()).collect::>(), None) + }, + sym::likely => { + self.expect(args[0].immediate(), true) + } + sym::unlikely => { + self.expect(args[0].immediate(), false) + } + kw::Try => { + try_intrinsic( + self, + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + llresult, + ); + return; + } + sym::breakpoint => { + unimplemented!(); + } + sym::va_copy => { + unimplemented!(); + } + sym::va_arg => { + unimplemented!(); + } + + sym::volatile_load | sym::unaligned_volatile_load => { + let tp_ty = substs.type_at(0); + let mut ptr = args[0].immediate(); + if let PassMode::Cast(ty) = fn_abi.ret.mode { + ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self))); + } + let load = self.volatile_load(ptr.get_type(), ptr); + // TODO(antoyo): set alignment. + self.to_immediate(load, self.layout_of(tp_ty)) + } + sym::volatile_store => { + let dst = args[0].deref(self.cx()); + args[1].val.volatile_store(self, dst); + return; + } + sym::unaligned_volatile_store => { + let dst = args[0].deref(self.cx()); + args[1].val.unaligned_volatile_store(self, dst); + return; + } + sym::prefetch_read_data + | sym::prefetch_write_data + | sym::prefetch_read_instruction + | sym::prefetch_write_instruction => { + unimplemented!(); + } + sym::ctlz + | sym::ctlz_nonzero + | sym::cttz + | sym::cttz_nonzero + | sym::ctpop + | sym::bswap + | sym::bitreverse + | sym::rotate_left + | sym::rotate_right + | sym::saturating_add + | sym::saturating_sub => { + let ty = arg_tys[0]; + match int_type_width_signed(ty, self) { + Some((width, signed)) => match name { + sym::ctlz | sym::cttz => { + let func = self.current_func.borrow().expect("func"); + let then_block = func.new_block("then"); + let else_block = func.new_block("else"); + let after_block = func.new_block("after"); + + let arg = args[0].immediate(); + let result = func.new_local(None, arg.get_type(), "zeros"); + let zero = self.cx.context.new_rvalue_zero(arg.get_type()); + let cond = self.cx.context.new_comparison(None, ComparisonOp::Equals, arg, zero); + self.llbb().end_with_conditional(None, cond, then_block, else_block); + + let zero_result = self.cx.context.new_rvalue_from_long(arg.get_type(), width as i64); + then_block.add_assignment(None, result, zero_result); + then_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place + // count_leading_zeroes() does not expect, the current blocks + // in the state need to be updated. + *self.current_block.borrow_mut() = Some(else_block); + self.block = Some(else_block); + + let zeros = + match name { + sym::ctlz => self.count_leading_zeroes(width, arg), + sym::cttz => self.count_trailing_zeroes(width, arg), + _ => unreachable!(), + }; + else_block.add_assignment(None, result, zeros); + else_block.end_with_jump(None, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current blocks in the state need to be updated. + *self.current_block.borrow_mut() = Some(after_block); + self.block = Some(after_block); + + result.to_rvalue() + } + sym::ctlz_nonzero => { + self.count_leading_zeroes(width, args[0].immediate()) + }, + sym::cttz_nonzero => { + self.count_trailing_zeroes(width, args[0].immediate()) + } + sym::ctpop => self.pop_count(args[0].immediate()), + sym::bswap => { + if width == 8 { + args[0].immediate() // byte swap a u8/i8 is just a no-op + } + else { + // TODO(antoyo): check if it's faster to use string literals and a + // match instead of format!. + let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width)); + let mut arg = args[0].immediate(); + // FIXME(antoyo): this cast should not be necessary. Remove + // when having proper sized integer types. + let param_type = bswap.get_param(0).to_rvalue().get_type(); + if param_type != arg.get_type() { + arg = self.bitcast(arg, param_type); + } + self.cx.context.new_call(None, bswap, &[arg]) + } + }, + sym::bitreverse => self.bit_reverse(width, args[0].immediate()), + sym::rotate_left | sym::rotate_right => { + // TODO(antoyo): implement using algorithm from: + // https://blog.regehr.org/archives/1063 + // for other platforms. + let is_left = name == sym::rotate_left; + let val = args[0].immediate(); + let raw_shift = args[1].immediate(); + if is_left { + self.rotate_left(val, raw_shift, width) + } + else { + self.rotate_right(val, raw_shift, width) + } + }, + sym::saturating_add => { + self.saturating_add(args[0].immediate(), args[1].immediate(), signed, width) + }, + sym::saturating_sub => { + self.saturating_sub(args[0].immediate(), args[1].immediate(), signed, width) + }, + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + tcx.sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + return; + } + } + } + + sym::raw_eq => { + use rustc_target::abi::Abi::*; + let tp_ty = substs.type_at(0); + let layout = self.layout_of(tp_ty).layout; + let _use_integer_compare = match layout.abi { + Scalar(_) | ScalarPair(_, _) => true, + Uninhabited | Vector { .. } => false, + Aggregate { .. } => { + // For rusty ABIs, small aggregates are actually passed + // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), + // so we re-use that same threshold here. + layout.size <= self.data_layout().pointer_size * 2 + } + }; + + let a = args[0].immediate(); + let b = args[1].immediate(); + if layout.size.bytes() == 0 { + self.const_bool(true) + } + /*else if use_integer_compare { + let integer_ty = self.type_ix(layout.size.bits()); // FIXME(antoyo): LLVM creates an integer of 96 bits for [i32; 3], but gcc doesn't support this, so it creates an integer of 128 bits. + let ptr_ty = self.type_ptr_to(integer_ty); + let a_ptr = self.bitcast(a, ptr_ty); + let a_val = self.load(integer_ty, a_ptr, layout.align.abi); + let b_ptr = self.bitcast(b, ptr_ty); + let b_val = self.load(integer_ty, b_ptr, layout.align.abi); + self.icmp(IntPredicate::IntEQ, a_val, b_val) + }*/ + else { + let void_ptr_type = self.context.new_type::<*const ()>(); + let a_ptr = self.bitcast(a, void_ptr_type); + let b_ptr = self.bitcast(b, void_ptr_type); + let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type); + let builtin = self.context.get_builtin_function("memcmp"); + let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]); + self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)) + } + } + + sym::black_box => { + args[0].val.store(self, result); + + let block = self.llbb(); + let extended_asm = block.add_extended_asm(None, ""); + extended_asm.add_input_operand(None, "r", result.llval); + extended_asm.add_clobber("memory"); + extended_asm.set_volatile_flag(true); + + // We have copied the value to `result` already. + return; + } + + _ if name_str.starts_with("simd_") => { + match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { + Ok(llval) => llval, + Err(()) => return, + } + } + + _ => bug!("unknown intrinsic '{}'", name), + }; + + if !fn_abi.ret.is_ignore() { + if let PassMode::Cast(ty) = fn_abi.ret.mode { + let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); + let ptr = self.pointercast(result.llval, ptr_llty); + self.store(llval, ptr, result.align); + } + else { + OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) + .val + .store(self, result); + } + } + } + + fn abort(&mut self) { + let func = self.context.get_builtin_function("abort"); + let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; + self.call(self.type_void(), func, &[], None); + } + + fn assume(&mut self, value: Self::Value) { + // TODO(antoyo): switch to asumme when it exists. + // Or use something like this: + // #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0) + self.expect(value, true); + } + + fn expect(&mut self, cond: Self::Value, _expected: bool) -> Self::Value { + // TODO(antoyo) + cond + } + + fn sideeffect(&mut self) { + // TODO(antoyo) + } + + fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } + + fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> { + unimplemented!(); + } +} + +impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { + fn store_fn_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, idx: &mut usize, dst: PlaceRef<'tcx, Self::Value>) { + arg_abi.store_fn_arg(self, idx, dst) + } + + fn store_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) { + arg_abi.store(self, val, dst) + } + + fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { + arg_abi.memory_ty(self) + } +} + +pub trait ArgAbiExt<'gcc, 'tcx> { + fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; + fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>); + fn store_fn_arg(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>); +} + +impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { + /// Gets the LLVM type for a place of the original Rust type of + /// this argument/return, i.e., the result of `type_of::type_of`. + fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + self.layout.gcc_type(cx, true) + } + + /// Stores a direct/indirect value described by this ArgAbi into a + /// place for the original Rust type of this argument/return. + /// Can be used for both storing formal arguments into Rust variables + /// or results of call/invoke instructions into their destinations. + fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) { + if self.is_ignore() { + return; + } + if self.is_sized_indirect() { + OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) + } + else if self.is_unsized_indirect() { + bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); + } + else if let PassMode::Cast(cast) = self.mode { + // FIXME(eddyb): Figure out when the simpler Store is safe, clang + // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. + let can_store_through_cast_ptr = false; + if can_store_through_cast_ptr { + let cast_ptr_llty = bx.type_ptr_to(cast.gcc_type(bx)); + let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty); + bx.store(val, cast_dst, self.layout.align.abi); + } + else { + // The actual return type is a struct, but the ABI + // adaptation code has cast it into some scalar type. The + // code that follows is the only reliable way I have + // found to do a transform like i64 -> {i32,i32}. + // Basically we dump the data onto the stack then memcpy it. + // + // Other approaches I tried: + // - Casting rust ret pointer to the foreign type and using Store + // is (a) unsafe if size of foreign type > size of rust type and + // (b) runs afoul of strict aliasing rules, yielding invalid + // assembly under -O (specifically, the store gets removed). + // - Truncating foreign type to correct integral type and then + // bitcasting to the struct type yields invalid cast errors. + + // We instead thus allocate some scratch space... + let scratch_size = cast.size(bx); + let scratch_align = cast.align(bx); + let llscratch = bx.alloca(cast.gcc_type(bx), scratch_align); + bx.lifetime_start(llscratch, scratch_size); + + // ... where we first store the value... + bx.store(val, llscratch, scratch_align); + + // ... and then memcpy it to the intended destination. + bx.memcpy( + dst.llval, + self.layout.align.abi, + llscratch, + scratch_align, + bx.const_usize(self.layout.size.bytes()), + MemFlags::empty(), + ); + + bx.lifetime_end(llscratch, scratch_size); + } + } + else { + OperandValue::Immediate(val).store(bx, dst); + } + } + + fn store_fn_arg<'a>(&self, bx: &mut Builder<'a, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>) { + let mut next = || { + let val = bx.current_func().get_param(*idx as i32); + *idx += 1; + val.to_rvalue() + }; + match self.mode { + PassMode::Ignore => {} + PassMode::Pair(..) => { + OperandValue::Pair(next(), next()).store(bx, dst); + } + PassMode::Indirect { extra_attrs: Some(_), .. } => { + OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); + } + PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => { + let next_arg = next(); + self.store(bx, next_arg.to_rvalue(), dst); + } + } + } +} + +fn int_type_width_signed<'gcc, 'tcx>(ty: Ty<'tcx>, cx: &CodegenCx<'gcc, 'tcx>) -> Option<(u64, bool)> { + match ty.kind() { + ty::Int(t) => Some(( + match t { + rustc_middle::ty::IntTy::Isize => u64::from(cx.tcx.sess.target.pointer_width), + rustc_middle::ty::IntTy::I8 => 8, + rustc_middle::ty::IntTy::I16 => 16, + rustc_middle::ty::IntTy::I32 => 32, + rustc_middle::ty::IntTy::I64 => 64, + rustc_middle::ty::IntTy::I128 => 128, + }, + true, + )), + ty::Uint(t) => Some(( + match t { + rustc_middle::ty::UintTy::Usize => u64::from(cx.tcx.sess.target.pointer_width), + rustc_middle::ty::UintTy::U8 => 8, + rustc_middle::ty::UintTy::U16 => 16, + rustc_middle::ty::UintTy::U32 => 32, + rustc_middle::ty::UintTy::U64 => 64, + rustc_middle::ty::UintTy::U128 => 128, + }, + false, + )), + _ => None, + } +} + +impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { + fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> { + let result_type = value.get_type(); + let typ = result_type.to_unsigned(self.cx); + + let value = + if result_type.is_signed(self.cx) { + self.context.new_bitcast(None, value, typ) + } + else { + value + }; + + let context = &self.cx.context; + let result = + match width { + 8 => { + // First step. + let left = self.and(value, context.new_rvalue_from_int(typ, 0xF0)); + let left = self.lshr(left, context.new_rvalue_from_int(typ, 4)); + let right = self.and(value, context.new_rvalue_from_int(typ, 0x0F)); + let right = self.shl(right, context.new_rvalue_from_int(typ, 4)); + let step1 = self.or(left, right); + + // Second step. + let left = self.and(step1, context.new_rvalue_from_int(typ, 0xCC)); + let left = self.lshr(left, context.new_rvalue_from_int(typ, 2)); + let right = self.and(step1, context.new_rvalue_from_int(typ, 0x33)); + let right = self.shl(right, context.new_rvalue_from_int(typ, 2)); + let step2 = self.or(left, right); + + // Third step. + let left = self.and(step2, context.new_rvalue_from_int(typ, 0xAA)); + let left = self.lshr(left, context.new_rvalue_from_int(typ, 1)); + let right = self.and(step2, context.new_rvalue_from_int(typ, 0x55)); + let right = self.shl(right, context.new_rvalue_from_int(typ, 1)); + let step3 = self.or(left, right); + + step3 + }, + 16 => { + // First step. + let left = self.and(value, context.new_rvalue_from_int(typ, 0x5555)); + let left = self.shl(left, context.new_rvalue_from_int(typ, 1)); + let right = self.and(value, context.new_rvalue_from_int(typ, 0xAAAA)); + let right = self.lshr(right, context.new_rvalue_from_int(typ, 1)); + let step1 = self.or(left, right); + + // Second step. + let left = self.and(step1, context.new_rvalue_from_int(typ, 0x3333)); + let left = self.shl(left, context.new_rvalue_from_int(typ, 2)); + let right = self.and(step1, context.new_rvalue_from_int(typ, 0xCCCC)); + let right = self.lshr(right, context.new_rvalue_from_int(typ, 2)); + let step2 = self.or(left, right); + + // Third step. + let left = self.and(step2, context.new_rvalue_from_int(typ, 0x0F0F)); + let left = self.shl(left, context.new_rvalue_from_int(typ, 4)); + let right = self.and(step2, context.new_rvalue_from_int(typ, 0xF0F0)); + let right = self.lshr(right, context.new_rvalue_from_int(typ, 4)); + let step3 = self.or(left, right); + + // Fourth step. + let left = self.and(step3, context.new_rvalue_from_int(typ, 0x00FF)); + let left = self.shl(left, context.new_rvalue_from_int(typ, 8)); + let right = self.and(step3, context.new_rvalue_from_int(typ, 0xFF00)); + let right = self.lshr(right, context.new_rvalue_from_int(typ, 8)); + let step4 = self.or(left, right); + + step4 + }, + 32 => { + // TODO(antoyo): Refactor with other implementations. + // First step. + let left = self.and(value, context.new_rvalue_from_long(typ, 0x55555555)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 1)); + let right = self.and(value, context.new_rvalue_from_long(typ, 0xAAAAAAAA)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 1)); + let step1 = self.or(left, right); + + // Second step. + let left = self.and(step1, context.new_rvalue_from_long(typ, 0x33333333)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 2)); + let right = self.and(step1, context.new_rvalue_from_long(typ, 0xCCCCCCCC)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 2)); + let step2 = self.or(left, right); + + // Third step. + let left = self.and(step2, context.new_rvalue_from_long(typ, 0x0F0F0F0F)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 4)); + let right = self.and(step2, context.new_rvalue_from_long(typ, 0xF0F0F0F0)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 4)); + let step3 = self.or(left, right); + + // Fourth step. + let left = self.and(step3, context.new_rvalue_from_long(typ, 0x00FF00FF)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 8)); + let right = self.and(step3, context.new_rvalue_from_long(typ, 0xFF00FF00)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 8)); + let step4 = self.or(left, right); + + // Fifth step. + let left = self.and(step4, context.new_rvalue_from_long(typ, 0x0000FFFF)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 16)); + let right = self.and(step4, context.new_rvalue_from_long(typ, 0xFFFF0000)); + let right = self.lshr(right, context.new_rvalue_from_long(typ, 16)); + let step5 = self.or(left, right); + + step5 + }, + 64 => { + // First step. + let left = self.shl(value, context.new_rvalue_from_long(typ, 32)); + let right = self.lshr(value, context.new_rvalue_from_long(typ, 32)); + let step1 = self.or(left, right); + + // Second step. + let left = self.and(step1, context.new_rvalue_from_long(typ, 0x0001FFFF0001FFFF)); + let left = self.shl(left, context.new_rvalue_from_long(typ, 15)); + let right = self.and(step1, context.new_rvalue_from_long(typ, 0xFFFE0000FFFE0000u64 as i64)); // TODO(antoyo): transmute the number instead? + let right = self.lshr(right, context.new_rvalue_from_long(typ, 17)); + let step2 = self.or(left, right); + + // Third step. + let left = self.lshr(step2, context.new_rvalue_from_long(typ, 10)); + let left = self.xor(step2, left); + let temp = self.and(left, context.new_rvalue_from_long(typ, 0x003F801F003F801F)); + + let left = self.shl(temp, context.new_rvalue_from_long(typ, 10)); + let left = self.or(temp, left); + let step3 = self.xor(left, step2); + + // Fourth step. + let left = self.lshr(step3, context.new_rvalue_from_long(typ, 4)); + let left = self.xor(step3, left); + let temp = self.and(left, context.new_rvalue_from_long(typ, 0x0E0384210E038421)); + + let left = self.shl(temp, context.new_rvalue_from_long(typ, 4)); + let left = self.or(temp, left); + let step4 = self.xor(left, step3); + + // Fifth step. + let left = self.lshr(step4, context.new_rvalue_from_long(typ, 2)); + let left = self.xor(step4, left); + let temp = self.and(left, context.new_rvalue_from_long(typ, 0x2248884222488842)); + + let left = self.shl(temp, context.new_rvalue_from_long(typ, 2)); + let left = self.or(temp, left); + let step5 = self.xor(left, step4); + + step5 + }, + 128 => { + // TODO(antoyo): find a more efficient implementation? + let sixty_four = self.context.new_rvalue_from_long(typ, 64); + let high = self.context.new_cast(None, value >> sixty_four, self.u64_type); + let low = self.context.new_cast(None, value, self.u64_type); + + let reversed_high = self.bit_reverse(64, high); + let reversed_low = self.bit_reverse(64, low); + + let new_low = self.context.new_cast(None, reversed_high, typ); + let new_high = self.context.new_cast(None, reversed_low, typ) << sixty_four; + + new_low | new_high + }, + _ => { + panic!("cannot bit reverse with width = {}", width); + }, + }; + + self.context.new_bitcast(None, result, result_type) + } + + fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use width? + let arg_type = arg.get_type(); + let count_leading_zeroes = + if arg_type.is_uint(&self.cx) { + "__builtin_clz" + } + else if arg_type.is_ulong(&self.cx) { + "__builtin_clzl" + } + else if arg_type.is_ulonglong(&self.cx) { + "__builtin_clzll" + } + else if width == 128 { + // Algorithm from: https://stackoverflow.com/a/28433850/389119 + let array_type = self.context.new_array_type(None, arg_type, 3); + let result = self.current_func() + .new_local(None, array_type, "count_loading_zeroes_results"); + + let sixty_four = self.context.new_rvalue_from_long(arg_type, 64); + let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type); + let low = self.context.new_cast(None, arg, self.u64_type); + + let zero = self.context.new_rvalue_zero(self.usize_type); + let one = self.context.new_rvalue_one(self.usize_type); + let two = self.context.new_rvalue_from_long(self.usize_type, 2); + + let clzll = self.context.get_builtin_function("__builtin_clzll"); + + let first_elem = self.context.new_array_access(None, result, zero); + let first_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[high]), arg_type); + self.llbb() + .add_assignment(None, first_elem, first_value); + + let second_elem = self.context.new_array_access(None, result, one); + let second_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[low]), arg_type) + sixty_four; + self.llbb() + .add_assignment(None, second_elem, second_value); + + let third_elem = self.context.new_array_access(None, result, two); + let third_value = self.context.new_rvalue_from_long(arg_type, 128); + self.llbb() + .add_assignment(None, third_elem, third_value); + + let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); + let not_low_and_not_high = not_low & not_high; + let index = not_high + not_low_and_not_high; + + let res = self.context.new_array_access(None, result, index); + + return self.context.new_cast(None, res, arg_type); + } + else { + let count_leading_zeroes = self.context.get_builtin_function("__builtin_clz"); + let arg = self.context.new_cast(None, arg, self.uint_type); + let diff = self.int_width(self.uint_type) - self.int_width(arg_type); + let diff = self.context.new_rvalue_from_long(self.int_type, diff); + let res = self.context.new_call(None, count_leading_zeroes, &[arg]) - diff; + return self.context.new_cast(None, res, arg_type); + }; + let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes); + let res = self.context.new_call(None, count_leading_zeroes, &[arg]); + self.context.new_cast(None, res, arg_type) + } + + fn count_trailing_zeroes(&self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { + let result_type = arg.get_type(); + let arg = + if result_type.is_signed(self.cx) { + let new_type = result_type.to_unsigned(self.cx); + self.context.new_bitcast(None, arg, new_type) + } + else { + arg + }; + let arg_type = arg.get_type(); + let (count_trailing_zeroes, expected_type) = + if arg_type.is_uchar(&self.cx) || arg_type.is_ushort(&self.cx) || arg_type.is_uint(&self.cx) { + // NOTE: we don't need to & 0xFF for uchar because the result is undefined on zero. + ("__builtin_ctz", self.cx.uint_type) + } + else if arg_type.is_ulong(&self.cx) { + ("__builtin_ctzl", self.cx.ulong_type) + } + else if arg_type.is_ulonglong(&self.cx) { + ("__builtin_ctzll", self.cx.ulonglong_type) + } + else if arg_type.is_u128(&self.cx) { + // Adapted from the algorithm to count leading zeroes from: https://stackoverflow.com/a/28433850/389119 + let array_type = self.context.new_array_type(None, arg_type, 3); + let result = self.current_func() + .new_local(None, array_type, "count_loading_zeroes_results"); + + let sixty_four = self.context.new_rvalue_from_long(arg_type, 64); + let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type); + let low = self.context.new_cast(None, arg, self.u64_type); + + let zero = self.context.new_rvalue_zero(self.usize_type); + let one = self.context.new_rvalue_one(self.usize_type); + let two = self.context.new_rvalue_from_long(self.usize_type, 2); + + let ctzll = self.context.get_builtin_function("__builtin_ctzll"); + + let first_elem = self.context.new_array_access(None, result, zero); + let first_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[low]), arg_type); + self.llbb() + .add_assignment(None, first_elem, first_value); + + let second_elem = self.context.new_array_access(None, result, one); + let second_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[high]), arg_type) + sixty_four; + self.llbb() + .add_assignment(None, second_elem, second_value); + + let third_elem = self.context.new_array_access(None, result, two); + let third_value = self.context.new_rvalue_from_long(arg_type, 128); + self.llbb() + .add_assignment(None, third_elem, third_value); + + let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); + let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); + let not_low_and_not_high = not_low & not_high; + let index = not_low + not_low_and_not_high; + + let res = self.context.new_array_access(None, result, index); + + return self.context.new_bitcast(None, res, result_type); + } + else { + unimplemented!("count_trailing_zeroes for {:?}", arg_type); + }; + let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes); + let arg = + if arg_type != expected_type { + self.context.new_cast(None, arg, expected_type) + } + else { + arg + }; + let res = self.context.new_call(None, count_trailing_zeroes, &[arg]); + self.context.new_bitcast(None, res, result_type) + } + + fn int_width(&self, typ: Type<'gcc>) -> i64 { + self.cx.int_width(typ) as i64 + } + + fn pop_count(&self, value: RValue<'gcc>) -> RValue<'gcc> { + // TODO(antoyo): use the optimized version with fewer operations. + let result_type = value.get_type(); + let value_type = result_type.to_unsigned(self.cx); + + let value = + if result_type.is_signed(self.cx) { + self.context.new_bitcast(None, value, value_type) + } + else { + value + }; + + if value_type.is_u128(&self.cx) { + // TODO(antoyo): implement in the normal algorithm below to have a more efficient + // implementation (that does not require a call to __popcountdi2). + let popcount = self.context.get_builtin_function("__builtin_popcountll"); + let sixty_four = self.context.new_rvalue_from_long(value_type, 64); + let high = self.context.new_cast(None, value >> sixty_four, self.cx.ulonglong_type); + let high = self.context.new_call(None, popcount, &[high]); + let low = self.context.new_cast(None, value, self.cx.ulonglong_type); + let low = self.context.new_call(None, popcount, &[low]); + let res = high + low; + return self.context.new_bitcast(None, res, result_type); + } + + // First step. + let mask = self.context.new_rvalue_from_long(value_type, 0x5555555555555555); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 1); + let right = shifted & mask; + let value = left + right; + + // Second step. + let mask = self.context.new_rvalue_from_long(value_type, 0x3333333333333333); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 2); + let right = shifted & mask; + let value = left + right; + + // Third step. + let mask = self.context.new_rvalue_from_long(value_type, 0x0F0F0F0F0F0F0F0F); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 4); + let right = shifted & mask; + let value = left + right; + + if value_type.is_u8(&self.cx) { + return self.context.new_bitcast(None, value, result_type); + } + + // Fourth step. + let mask = self.context.new_rvalue_from_long(value_type, 0x00FF00FF00FF00FF); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 8); + let right = shifted & mask; + let value = left + right; + + if value_type.is_u16(&self.cx) { + return self.context.new_bitcast(None, value, result_type); + } + + // Fifth step. + let mask = self.context.new_rvalue_from_long(value_type, 0x0000FFFF0000FFFF); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 16); + let right = shifted & mask; + let value = left + right; + + if value_type.is_u32(&self.cx) { + return self.context.new_bitcast(None, value, result_type); + } + + // Sixth step. + let mask = self.context.new_rvalue_from_long(value_type, 0x00000000FFFFFFFF); + let left = value & mask; + let shifted = value >> self.context.new_rvalue_from_int(value_type, 32); + let right = shifted & mask; + let value = left + right; + + self.context.new_bitcast(None, value, result_type) + } + + // Algorithm from: https://blog.regehr.org/archives/1063 + fn rotate_left(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> { + let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64); + let shift = shift % max; + let lhs = self.shl(value, shift); + let result_and = + self.and( + self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift), + self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1), + ); + let rhs = self.lshr(value, result_and); + self.or(lhs, rhs) + } + + // Algorithm from: https://blog.regehr.org/archives/1063 + fn rotate_right(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> { + let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64); + let shift = shift % max; + let lhs = self.lshr(value, shift); + let result_and = + self.and( + self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift), + self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1), + ); + let rhs = self.shl(value, result_and); + self.or(lhs, rhs) + } + + fn saturating_add(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> { + let func = self.current_func.borrow().expect("func"); + + if signed { + // Algorithm from: https://stackoverflow.com/a/56531252/389119 + let after_block = func.new_block("after"); + let func_name = + match width { + 8 => "__builtin_add_overflow", + 16 => "__builtin_add_overflow", + 32 => "__builtin_sadd_overflow", + 64 => "__builtin_saddll_overflow", + 128 => "__builtin_add_overflow", + _ => unreachable!(), + }; + let overflow_func = self.context.get_builtin_function(func_name); + let result_type = lhs.get_type(); + let res = func.new_local(None, result_type, "saturating_sum"); + let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None); + + let then_block = func.new_block("then"); + + let unsigned_type = self.context.new_int_type(width as i32 / 8, false); + let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1); + let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type, + self.context.new_rvalue_from_int(unsigned_type, 0) + ); + let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type); + then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type)); + then_block.end_with_jump(None, after_block); + + self.llbb().end_with_conditional(None, overflow, then_block, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current blocks in the state need to be updated. + *self.current_block.borrow_mut() = Some(after_block); + self.block = Some(after_block); + + res.to_rvalue() + } + else { + // Algorithm from: http://locklessinc.com/articles/sat_arithmetic/ + let res = lhs + rhs; + let res_type = res.get_type(); + let cond = self.context.new_comparison(None, ComparisonOp::LessThan, res, lhs); + let value = self.context.new_unary_op(None, UnaryOp::Minus, res_type, self.context.new_cast(None, cond, res_type)); + res | value + } + } + + // Algorithm from: https://locklessinc.com/articles/sat_arithmetic/ + fn saturating_sub(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> { + if signed { + // Also based on algorithm from: https://stackoverflow.com/a/56531252/389119 + let func_name = + match width { + 8 => "__builtin_sub_overflow", + 16 => "__builtin_sub_overflow", + 32 => "__builtin_ssub_overflow", + 64 => "__builtin_ssubll_overflow", + 128 => "__builtin_sub_overflow", + _ => unreachable!(), + }; + let overflow_func = self.context.get_builtin_function(func_name); + let result_type = lhs.get_type(); + let func = self.current_func.borrow().expect("func"); + let res = func.new_local(None, result_type, "saturating_diff"); + let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None); + + let then_block = func.new_block("then"); + let after_block = func.new_block("after"); + + let unsigned_type = self.context.new_int_type(width as i32 / 8, false); + let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1); + let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type, + self.context.new_rvalue_from_int(unsigned_type, 0) + ); + let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type); + then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type)); + then_block.end_with_jump(None, after_block); + + self.llbb().end_with_conditional(None, overflow, then_block, after_block); + + // NOTE: since jumps were added in a place rustc does not + // expect, the current blocks in the state need to be updated. + *self.current_block.borrow_mut() = Some(after_block); + self.block = Some(after_block); + + res.to_rvalue() + } + else { + let res = lhs - rhs; + let comparison = self.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs); + let comparison = self.context.new_cast(None, comparison, lhs.get_type()); + let unary_op = self.context.new_unary_op(None, UnaryOp::Minus, comparison.get_type(), comparison); + self.and(res, unary_op) + } + } +} + +fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) { + if bx.sess().panic_strategy() == PanicStrategy::Abort { + bx.call(bx.type_void(), try_func, &[data], None); + // Return 0 unconditionally from the intrinsic call; + // we can never unwind. + let ret_align = bx.tcx.data_layout.i32_align.abi; + bx.store(bx.const_i32(0), dest, ret_align); + } + else if wants_msvc_seh(bx.sess()) { + unimplemented!(); + } + else { + unimplemented!(); + } +} diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs new file mode 100644 index 0000000000000..26a42217e4c56 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -0,0 +1,167 @@ +use gccjit::{RValue, Type}; +use rustc_codegen_ssa::base::compare_simd_types; +use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error}; +use rustc_codegen_ssa::mir::operand::OperandRef; +use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; +use rustc_hir as hir; +use rustc_middle::span_bug; +use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::{self, Ty}; +use rustc_span::{Span, Symbol, sym}; + +use crate::builder::Builder; + +pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result, ()> { + // macros for error handling: + macro_rules! emit_error { + ($msg: tt) => { + emit_error!($msg, ) + }; + ($msg: tt, $($fmt: tt)*) => { + span_invalid_monomorphization_error( + bx.sess(), span, + &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg), + name, $($fmt)*)); + } + } + + macro_rules! return_error { + ($($fmt: tt)*) => { + { + emit_error!($($fmt)*); + return Err(()); + } + } + } + + macro_rules! require { + ($cond: expr, $($fmt: tt)*) => { + if !$cond { + return_error!($($fmt)*); + } + }; + } + + macro_rules! require_simd { + ($ty: expr, $position: expr) => { + require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty) + }; + } + + let tcx = bx.tcx(); + let sig = + tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); + let arg_tys = sig.inputs(); + let name_str = &*name.as_str(); + + // every intrinsic below takes a SIMD vector as its first argument + require_simd!(arg_tys[0], "input"); + let in_ty = arg_tys[0]; + + let comparison = match name { + sym::simd_eq => Some(hir::BinOpKind::Eq), + sym::simd_ne => Some(hir::BinOpKind::Ne), + sym::simd_lt => Some(hir::BinOpKind::Lt), + sym::simd_le => Some(hir::BinOpKind::Le), + sym::simd_gt => Some(hir::BinOpKind::Gt), + sym::simd_ge => Some(hir::BinOpKind::Ge), + _ => None, + }; + + let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx()); + if let Some(cmp_op) = comparison { + require_simd!(ret_ty, "return"); + + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + require!( + bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, + "expected return type with integer elements, found `{}` with non-integer `{}`", + ret_ty, + out_ty + ); + + return Ok(compare_simd_types( + bx, + args[0].immediate(), + args[1].immediate(), + in_elem, + llret_ty, + cmp_op, + )); + } + + if let Some(stripped) = name_str.strip_prefix("simd_shuffle") { + let n: u64 = stripped.parse().unwrap_or_else(|_| { + span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?") + }); + + require_simd!(ret_ty, "return"); + + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + out_len == n, + "expected return type of length {}, found `{}` with length {}", + n, + ret_ty, + out_len + ); + require!( + in_elem == out_ty, + "expected return element type `{}` (element of input `{}`), \ + found `{}` with element type `{}`", + in_elem, + in_ty, + ret_ty, + out_ty + ); + + let vector = args[2].immediate(); + + return Ok(bx.shuffle_vector( + args[0].immediate(), + args[1].immediate(), + vector, + )); + } + + macro_rules! arith_binary { + ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { + $(if name == sym::$name { + match in_elem.kind() { + $($(ty::$p(_))|* => { + return Ok(bx.$call(args[0].immediate(), args[1].immediate())) + })* + _ => {}, + } + require!(false, + "unsupported operation on `{}` with element `{}`", + in_ty, + in_elem) + })* + } + } + + arith_binary! { + simd_add: Uint, Int => add, Float => fadd; + simd_sub: Uint, Int => sub, Float => fsub; + simd_mul: Uint, Int => mul, Float => fmul; + simd_div: Uint => udiv, Int => sdiv, Float => fdiv; + simd_rem: Uint => urem, Int => srem, Float => frem; + simd_shl: Uint, Int => shl; + simd_shr: Uint => lshr, Int => ashr; + simd_and: Uint, Int => and; + simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors. + simd_xor: Uint, Int => xor; + } + + unimplemented!("simd {}", name); +} diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs new file mode 100644 index 0000000000000..629003d7982b9 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -0,0 +1,293 @@ +/* + * TODO(antoyo): support #[inline] attributes. + * TODO(antoyo): support LTO. + * + * TODO(antoyo): remove the patches. + */ + +#![feature(rustc_private, decl_macro, associated_type_bounds, never_type, trusted_len)] +#![allow(broken_intra_doc_links)] +#![recursion_limit="256"] +#![warn(rust_2018_idioms)] +#![warn(unused_lifetimes)] + +extern crate rustc_ast; +extern crate rustc_codegen_ssa; +extern crate rustc_data_structures; +extern crate rustc_errors; +extern crate rustc_hir; +extern crate rustc_metadata; +extern crate rustc_middle; +extern crate rustc_session; +extern crate rustc_span; +extern crate rustc_symbol_mangling; +extern crate rustc_target; +extern crate snap; + +// This prevents duplicating functions and statics that are already part of the host rustc process. +#[allow(unused_extern_crates)] +extern crate rustc_driver; + +mod abi; +mod allocator; +mod archive; +mod asm; +mod back; +mod base; +mod builder; +mod callee; +mod common; +mod consts; +mod context; +mod coverageinfo; +mod debuginfo; +mod declare; +mod intrinsic; +mod mono_item; +mod type_; +mod type_of; + +use std::any::Any; +use std::sync::Arc; + +use gccjit::{Context, OptimizationLevel}; +use rustc_ast::expand::allocator::AllocatorKind; +use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; +use rustc_codegen_ssa::base::codegen_crate; +use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn}; +use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use rustc_codegen_ssa::target_features::supported_target_features; +use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{ErrorReported, Handler}; +use rustc_metadata::EncodedMetadata; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::{Lto, OptLevel, OutputFilenames}; +use rustc_session::Session; +use rustc_span::Symbol; +use rustc_span::fatal_error::FatalError; + +pub struct PrintOnPanic String>(pub F); + +impl String> Drop for PrintOnPanic { + fn drop(&mut self) { + if ::std::thread::panicking() { + println!("{}", (self.0)()); + } + } +} + +#[derive(Clone)] +pub struct GccCodegenBackend; + +impl CodegenBackend for GccCodegenBackend { + fn init(&self, sess: &Session) { + if sess.lto() != Lto::No { + sess.warn("LTO is not supported. You may get a linker error."); + } + } + + fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box { + let target_cpu = target_cpu(tcx.sess); + let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module); + + rustc_symbol_mangling::test::report_symbol_names(tcx); + + Box::new(res) + } + + fn join_codegen(&self, ongoing_codegen: Box, sess: &Session) -> Result<(CodegenResults, FxHashMap), ErrorReported> { + let (codegen_results, work_products) = ongoing_codegen + .downcast::>() + .expect("Expected GccCodegenBackend's OngoingCodegen, found Box") + .join(sess); + + Ok((codegen_results, work_products)) + } + + fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorReported> { + use rustc_codegen_ssa::back::link::link_binary; + + link_binary::>( + sess, + &codegen_results, + outputs, + ) + } + + fn target_features(&self, sess: &Session) -> Vec { + target_features(sess) + } +} + +impl ExtraBackendMethods for GccCodegenBackend { + fn new_metadata<'tcx>(&self, _tcx: TyCtxt<'tcx>, _mod_name: &str) -> Self::Module { + GccContext { + context: Context::default(), + } + } + + fn write_compressed_metadata<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut Self::Module) { + base::write_compressed_metadata(tcx, metadata, gcc_module) + } + + fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, mods: &mut Self::Module, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) { + unsafe { allocator::codegen(tcx, mods, module_name, kind, has_alloc_error_handler) } + } + + fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen, u64) { + base::compile_codegen_unit(tcx, cgu_name) + } + + fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel) -> TargetMachineFactoryFn { + // TODO(antoyo): set opt level. + Arc::new(|_| { + Ok(()) + }) + } + + fn target_cpu<'b>(&self, _sess: &'b Session) -> &'b str { + unimplemented!(); + } + + fn tune_cpu<'b>(&self, _sess: &'b Session) -> Option<&'b str> { + None + // TODO(antoyo) + } +} + +pub struct ModuleBuffer; + +impl ModuleBufferMethods for ModuleBuffer { + fn data(&self) -> &[u8] { + unimplemented!(); + } +} + +pub struct ThinBuffer; + +impl ThinBufferMethods for ThinBuffer { + fn data(&self) -> &[u8] { + unimplemented!(); + } +} + +pub struct GccContext { + context: Context<'static>, +} + +unsafe impl Send for GccContext {} +// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". Try to disable it here. +unsafe impl Sync for GccContext {} + +impl WriteBackendMethods for GccCodegenBackend { + type Module = GccContext; + type TargetMachine = (); + type ModuleBuffer = ModuleBuffer; + type Context = (); + type ThinData = (); + type ThinBuffer = ThinBuffer; + + fn run_fat_lto(_cgcx: &CodegenContext, mut modules: Vec>, _cached_modules: Vec<(SerializedModule, WorkProduct)>) -> Result, FatalError> { + // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins. + // NOTE: implemented elsewhere. + // TODO: what is implemented elsewhere ^ ? + let module = + match modules.remove(0) { + FatLTOInput::InMemory(module) => module, + FatLTOInput::Serialized { .. } => { + unimplemented!(); + } + }; + Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: vec![] }) + } + + fn run_thin_lto(_cgcx: &CodegenContext, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule, WorkProduct)>) -> Result<(Vec>, Vec), FatalError> { + unimplemented!(); + } + + fn print_pass_timings(&self) { + unimplemented!(); + } + + unsafe fn optimize(_cgcx: &CodegenContext, _diag_handler: &Handler, module: &ModuleCodegen, config: &ModuleConfig) -> Result<(), FatalError> { + module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); + Ok(()) + } + + unsafe fn optimize_thin(_cgcx: &CodegenContext, _thin: &mut ThinModule) -> Result, FatalError> { + unimplemented!(); + } + + unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &Handler, module: ModuleCodegen, config: &ModuleConfig) -> Result { + back::write::codegen(cgcx, diag_handler, module, config) + } + + fn prepare_thin(_module: ModuleCodegen) -> (String, Self::ThinBuffer) { + unimplemented!(); + } + + fn serialize_module(_module: ModuleCodegen) -> (String, Self::ModuleBuffer) { + unimplemented!(); + } + + fn run_lto_pass_manager(_cgcx: &CodegenContext, _module: &ModuleCodegen, _config: &ModuleConfig, _thin: bool) -> Result<(), FatalError> { + // TODO(antoyo) + Ok(()) + } + + fn run_link(cgcx: &CodegenContext, diag_handler: &Handler, modules: Vec>) -> Result, FatalError> { + back::write::link(cgcx, diag_handler, modules) + } +} + +/// This is the entrypoint for a hot plugged rustc_codegen_gccjit +#[no_mangle] +pub fn __rustc_codegen_backend() -> Box { + Box::new(GccCodegenBackend) +} + +fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { + match optlevel { + None => OptimizationLevel::None, + Some(level) => { + match level { + OptLevel::No => OptimizationLevel::None, + OptLevel::Less => OptimizationLevel::Limited, + OptLevel::Default => OptimizationLevel::Standard, + OptLevel::Aggressive => OptimizationLevel::Aggressive, + OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited, + } + }, + } +} + +fn handle_native(name: &str) -> &str { + if name != "native" { + return name; + } + + unimplemented!(); +} + +pub fn target_cpu(sess: &Session) -> &str { + let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu); + handle_native(name) +} + +pub fn target_features(sess: &Session) -> Vec { + supported_target_features(sess) + .iter() + .filter_map( + |&(feature, gate)| { + if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } + }, + ) + .filter(|_feature| { + // TODO(antoyo): implement a way to get enabled feature in libgccjit. + false + }) + .map(|feature| Symbol::intern(feature)) + .collect() +} diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs new file mode 100644 index 0000000000000..e21d40b6c37e3 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -0,0 +1,38 @@ +use rustc_codegen_ssa::traits::PreDefineMethods; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::ty::{self, Instance, TypeFoldable}; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; +use rustc_span::def_id::DefId; + +use crate::base; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn predefine_static(&self, def_id: DefId, _linkage: Linkage, _visibility: Visibility, symbol_name: &str) { + let attrs = self.tcx.codegen_fn_attrs(def_id); + let instance = Instance::mono(self.tcx, def_id); + let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all()); + let gcc_type = self.layout_of(ty).gcc_type(self, true); + + let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); + let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section); + + // TODO(antoyo): set linkage and visibility. + self.instances.borrow_mut().insert(instance, global); + } + + fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, _visibility: Visibility, symbol_name: &str) { + assert!(!instance.substs.needs_infer()); + + let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); + self.linkage.set(base::linkage_to_gcc(linkage)); + let _decl = self.declare_fn(symbol_name, &fn_abi); + //let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); + + // TODO(antoyo): call set_link_section() to allow initializing argc/argv. + // TODO(antoyo): set unique comdat. + // TODO(antoyo): use inline attribute from there in linkage.set() above. + } +} diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs new file mode 100644 index 0000000000000..3545e1b628105 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -0,0 +1,282 @@ +use std::convert::TryInto; + +use gccjit::{RValue, Struct, Type}; +use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods}; +use rustc_codegen_ssa::common::TypeKind; +use rustc_middle::bug; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_target::abi::{AddressSpace, Align, Integer, Size}; + +use crate::common::TypeReflection; +use crate::context::CodegenCx; +use crate::type_of::LayoutGccExt; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn type_ix(&self, num_bits: u64) -> Type<'gcc> { + // gcc only supports 1, 2, 4 or 8-byte integers. + // FIXME(antoyo): this is misleading to use the next power of two as rustc_codegen_ssa + // sometimes use 96-bit numbers and the following code will give an integer of a different + // size. + let bytes = (num_bits / 8).next_power_of_two() as i32; + match bytes { + 1 => self.i8_type, + 2 => self.i16_type, + 4 => self.i32_type, + 8 => self.i64_type, + 16 => self.i128_type, + _ => panic!("unexpected num_bits: {}", num_bits), + } + } + + pub fn type_void(&self) -> Type<'gcc> { + self.context.new_type::<()>() + } + + pub fn type_size_t(&self) -> Type<'gcc> { + self.context.new_type::() + } + + pub fn type_u8(&self) -> Type<'gcc> { + self.u8_type + } + + pub fn type_u16(&self) -> Type<'gcc> { + self.u16_type + } + + pub fn type_u32(&self) -> Type<'gcc> { + self.u32_type + } + + pub fn type_u64(&self) -> Type<'gcc> { + self.u64_type + } + + pub fn type_u128(&self) -> Type<'gcc> { + self.u128_type + } + + pub fn type_pointee_for_align(&self, align: Align) -> Type<'gcc> { + // FIXME(eddyb) We could find a better approximation if ity.align < align. + let ity = Integer::approximate_align(self, align); + self.type_from_integer(ity) + } +} + +impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn type_i1(&self) -> Type<'gcc> { + self.bool_type + } + + fn type_i8(&self) -> Type<'gcc> { + self.i8_type + } + + fn type_i16(&self) -> Type<'gcc> { + self.i16_type + } + + fn type_i32(&self) -> Type<'gcc> { + self.i32_type + } + + fn type_i64(&self) -> Type<'gcc> { + self.i64_type + } + + fn type_i128(&self) -> Type<'gcc> { + self.i128_type + } + + fn type_isize(&self) -> Type<'gcc> { + self.isize_type + } + + fn type_f32(&self) -> Type<'gcc> { + self.context.new_type::() + } + + fn type_f64(&self) -> Type<'gcc> { + self.context.new_type::() + } + + fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> { + self.context.new_function_pointer_type(None, return_type, params, false) + } + + fn type_struct(&self, fields: &[Type<'gcc>], _packed: bool) -> Type<'gcc> { + let types = fields.to_vec(); + if let Some(typ) = self.struct_types.borrow().get(fields) { + return typ.clone(); + } + let fields: Vec<_> = fields.iter().enumerate() + .map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index))) + .collect(); + // TODO(antoyo): use packed. + let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); + self.struct_types.borrow_mut().insert(types, typ); + typ + } + + fn type_kind(&self, typ: Type<'gcc>) -> TypeKind { + if typ.is_integral() { + TypeKind::Integer + } + else if typ.is_vector().is_some() { + TypeKind::Vector + } + else { + // TODO(antoyo): support other types. + TypeKind::Void + } + } + + fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> { + ty.make_pointer() + } + + fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> { + // TODO(antoyo): use address_space + ty.make_pointer() + } + + fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> { + if let Some(typ) = ty.is_array() { + typ + } + else if let Some(vector_type) = ty.is_vector() { + vector_type.get_element_type() + } + else if let Some(typ) = ty.get_pointee() { + typ + } + else { + unreachable!() + } + } + + fn vector_length(&self, _ty: Type<'gcc>) -> usize { + unimplemented!(); + } + + fn float_width(&self, typ: Type<'gcc>) -> usize { + let f32 = self.context.new_type::(); + let f64 = self.context.new_type::(); + if typ == f32 { + 32 + } + else if typ == f64 { + 64 + } + else { + panic!("Cannot get width of float type {:?}", typ); + } + // TODO(antoyo): support other sizes. + } + + fn int_width(&self, typ: Type<'gcc>) -> u64 { + if typ.is_i8(self) || typ.is_u8(self) { + 8 + } + else if typ.is_i16(self) || typ.is_u16(self) { + 16 + } + else if typ.is_i32(self) || typ.is_u32(self) { + 32 + } + else if typ.is_i64(self) || typ.is_u64(self) { + 64 + } + else if typ.is_i128(self) || typ.is_u128(self) { + 128 + } + else { + panic!("Cannot get width of int type {:?}", typ); + } + } + + fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> { + value.get_type() + } +} + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + pub fn type_padding_filler(&self, size: Size, align: Align) -> Type<'gcc> { + let unit = Integer::approximate_align(self, align); + let size = size.bytes(); + let unit_size = unit.size().bytes(); + assert_eq!(size % unit_size, 0); + self.type_array(self.type_from_integer(unit), size / unit_size) + } + + pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], _packed: bool) { + // TODO(antoyo): use packed. + let fields: Vec<_> = fields.iter().enumerate() + .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index))) + .collect(); + typ.set_fields(None, &fields); + } + + pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> { + self.context.new_opaque_struct_type(None, name) + } + + pub fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> { + if let Some(struct_type) = ty.is_struct() { + if struct_type.get_field_count() == 0 { + // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a + // size of usize::MAX in test_binary_search, we workaround this by setting the size to + // zero for ZSTs. + // FIXME(antoyo): fix gccjit API. + len = 0; + } + } + + // NOTE: see note above. Some other test uses usize::MAX. + if len == u64::MAX { + len = 0; + } + + let len: i32 = len.try_into().expect("array len"); + + self.context.new_array_type(None, ty, len) + } +} + +pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec>, bool) { + let field_count = layout.fields.count(); + + let mut packed = false; + let mut offset = Size::ZERO; + let mut prev_effective_align = layout.align.abi; + let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2); + for i in layout.fields.index_by_increasing_offset() { + let target_offset = layout.fields.offset(i as usize); + let field = layout.field(cx, i); + let effective_field_align = + layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset); + packed |= effective_field_align < field.align.abi; + + assert!(target_offset >= offset); + let padding = target_offset - offset; + let padding_align = prev_effective_align.min(effective_field_align); + assert_eq!(offset.align_to(padding_align) + padding, target_offset); + result.push(cx.type_padding_filler(padding, padding_align)); + + result.push(field.gcc_type(cx, !field.ty.is_any_ptr())); // FIXME(antoyo): might need to check if the type is inside another, like Box. + offset = target_offset + field.size; + prev_effective_align = effective_field_align; + } + if !layout.is_unsized() && field_count > 0 { + if offset > layout.size { + bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset); + } + let padding = layout.size - offset; + let padding_align = prev_effective_align; + assert_eq!(offset.align_to(padding_align) + padding, layout.size); + result.push(cx.type_padding_filler(padding, padding_align)); + assert_eq!(result.len(), 1 + field_count * 2); + } + + (result, packed) +} diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs new file mode 100644 index 0000000000000..9c39c8f91a1ff --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -0,0 +1,359 @@ +use std::fmt::Write; + +use gccjit::{Struct, Type}; +use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; +use rustc_middle::bug; +use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; +use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; + +use crate::abi::{FnAbiGccExt, GccType}; +use crate::context::CodegenCx; +use crate::type_::struct_fields; + +impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { + fn type_from_unsigned_integer(&self, i: Integer) -> Type<'gcc> { + use Integer::*; + match i { + I8 => self.type_u8(), + I16 => self.type_u16(), + I32 => self.type_u32(), + I64 => self.type_u64(), + I128 => self.type_u128(), + } + } +} + +pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> { + match layout.abi { + Abi::Scalar(_) => bug!("handled elsewhere"), + Abi::Vector { ref element, count } => { + let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO); + return cx.context.new_vector_type(element, count); + }, + Abi::ScalarPair(..) => { + return cx.type_struct( + &[ + layout.scalar_pair_element_gcc_type(cx, 0, false), + layout.scalar_pair_element_gcc_type(cx, 1, false), + ], + false, + ); + } + Abi::Uninhabited | Abi::Aggregate { .. } => {} + } + + let name = match layout.ty.kind() { + // FIXME(eddyb) producing readable type names for trait objects can result + // in problematically distinct types due to HRTB and subtyping (see #47638). + // ty::Dynamic(..) | + ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str + if !cx.sess().fewer_names() => + { + let mut name = with_no_trimmed_paths(|| layout.ty.to_string()); + if let (&ty::Adt(def, _), &Variants::Single { index }) = + (layout.ty.kind(), &layout.variants) + { + if def.is_enum() && !def.variants.is_empty() { + write!(&mut name, "::{}", def.variants[index].ident).unwrap(); + } + } + if let (&ty::Generator(_, _, _), &Variants::Single { index }) = + (layout.ty.kind(), &layout.variants) + { + write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap(); + } + Some(name) + } + ty::Adt(..) => { + // If `Some` is returned then a named struct is created in LLVM. Name collisions are + // avoided by LLVM (with increasing suffixes). If rustc doesn't generate names then that + // can improve perf. + // FIXME(antoyo): I don't think that's true for libgccjit. + Some(String::new()) + } + _ => None, + }; + + match layout.fields { + FieldsShape::Primitive | FieldsShape::Union(_) => { + let fill = cx.type_padding_filler(layout.size, layout.align.abi); + let packed = false; + match name { + None => cx.type_struct(&[fill], packed), + Some(ref name) => { + let gcc_type = cx.type_named_struct(name); + cx.set_struct_body(gcc_type, &[fill], packed); + gcc_type.as_type() + }, + } + } + FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx, true), count), + FieldsShape::Arbitrary { .. } => + match name { + None => { + let (gcc_fields, packed) = struct_fields(cx, layout); + cx.type_struct(&gcc_fields, packed) + }, + Some(ref name) => { + let gcc_type = cx.type_named_struct(name); + *defer = Some((gcc_type, layout)); + gcc_type.as_type() + }, + }, + } +} + +pub trait LayoutGccExt<'tcx> { + fn is_gcc_immediate(&self) -> bool; + fn is_gcc_scalar_pair(&self) -> bool; + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc>; + fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; + fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>; + fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc>; + fn gcc_field_index(&self, index: usize) -> u64; + fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option; +} + +impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { + fn is_gcc_immediate(&self) -> bool { + match self.abi { + Abi::Scalar(_) | Abi::Vector { .. } => true, + Abi::ScalarPair(..) => false, + Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(), + } + } + + fn is_gcc_scalar_pair(&self) -> bool { + match self.abi { + Abi::ScalarPair(..) => true, + Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, + } + } + + /// Gets the GCC type corresponding to a Rust type, i.e., `rustc_middle::ty::Ty`. + /// The pointee type of the pointer in `PlaceRef` is always this type. + /// For sized types, it is also the right LLVM type for an `alloca` + /// containing a value of that type, and most immediates (except `bool`). + /// Unsized types, however, are represented by a "minimal unit", e.g. + /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this + /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`. + /// If the type is an unsized struct, the regular layout is generated, + /// with the inner-most trailing unsized field using the "minimal unit" + /// of that field's type - this is useful for taking the address of + /// that field and ensuring the struct has the right alignment. + //TODO(antoyo): do we still need the set_fields parameter? + fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc> { + if let Abi::Scalar(ref scalar) = self.abi { + // Use a different cache for scalars because pointers to DSTs + // can be either fat or thin (data pointers of fat pointers). + if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { + return ty; + } + let ty = + match *self.ty.kind() { + ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { + cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx, set_fields)) + } + ty::Adt(def, _) if def.is_box() => { + cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx, true)) + } + ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())), + _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO), + }; + cx.scalar_types.borrow_mut().insert(self.ty, ty); + return ty; + } + + // Check the cache. + let variant_index = + match self.variants { + Variants::Single { index } => Some(index), + _ => None, + }; + let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned(); + if let Some(ty) = cached_type { + let type_to_set_fields = cx.types_with_fields_to_set.borrow_mut().remove(&ty); + if let Some((struct_type, layout)) = type_to_set_fields { + // Since we might be trying to generate a type containing another type which is not + // completely generated yet, we deferred setting the fields until now. + let (fields, packed) = struct_fields(cx, layout); + cx.set_struct_body(struct_type, &fields, packed); + } + return ty; + } + + assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty); + + // Make sure lifetimes are erased, to avoid generating distinct LLVM + // types for Rust types that only differ in the choice of lifetimes. + let normal_ty = cx.tcx.erase_regions(self.ty); + + let mut defer = None; + let ty = + if self.ty != normal_ty { + let mut layout = cx.layout_of(normal_ty); + if let Some(v) = variant_index { + layout = layout.for_variant(cx, v); + } + layout.gcc_type(cx, true) + } + else { + uncached_gcc_type(cx, *self, &mut defer) + }; + + cx.types.borrow_mut().insert((self.ty, variant_index), ty); + + if let Some((ty, layout)) = defer { + let (fields, packed) = struct_fields(cx, layout); + cx.set_struct_body(ty, &fields, packed); + } + + ty + } + + fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + if let Abi::Scalar(ref scalar) = self.abi { + if scalar.is_bool() { + return cx.type_i1(); + } + } + self.gcc_type(cx, true) + } + + fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> { + match scalar.value { + Int(i, true) => cx.type_from_integer(i), + Int(i, false) => cx.type_from_unsigned_integer(i), + F32 => cx.type_f32(), + F64 => cx.type_f64(), + Pointer => { + // If we know the alignment, pick something better than i8. + 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(pointee) + } + } + } + + fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc> { + // TODO(antoyo): remove llvm hack: + // HACK(eddyb) special-case fat pointers until LLVM removes + // pointee types, to avoid bitcasting every `OperandRef::deref`. + match self.ty.kind() { + ty::Ref(..) | ty::RawPtr(_) => { + return self.field(cx, index).gcc_type(cx, true); + } + ty::Adt(def, _) if def.is_box() => { + let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); + return cx.layout_of(ptr_ty).scalar_pair_element_gcc_type(cx, index, immediate); + } + _ => {} + } + + let (a, b) = match self.abi { + Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self), + }; + let scalar = [a, b][index]; + + // Make sure to return the same type `immediate_gcc_type` would when + // dealing with an immediate pair. This means that `(bool, bool)` is + // effectively represented as `{i8, i8}` in memory and two `i1`s as an + // immediate, just like `bool` is typically `i8` in memory and only `i1` + // when immediate. We need to load/store `bool` as `i8` to avoid + // crippling LLVM optimizations or triggering other LLVM bugs with `i1`. + // TODO(antoyo): this bugs certainly don't happen in this case since the bool type is used instead of i1. + if scalar.is_bool() { + return cx.type_i1(); + } + + let offset = + if index == 0 { + Size::ZERO + } + else { + a.value.size(cx).align_to(b.value.align(cx).abi) + }; + self.scalar_gcc_type_at(cx, scalar, offset) + } + + fn gcc_field_index(&self, index: usize) -> u64 { + match self.abi { + Abi::Scalar(_) | Abi::ScalarPair(..) => { + bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self) + } + _ => {} + } + match self.fields { + FieldsShape::Primitive | FieldsShape::Union(_) => { + bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self) + } + + FieldsShape::Array { .. } => index as u64, + + FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2, + } + } + + fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option { + if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) { + return pointee; + } + + let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset); + + cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); + result + } +} + +impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> { + layout.gcc_type(self, true) + } + + fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> { + layout.immediate_gcc_type(self) + } + + fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool { + layout.is_gcc_immediate() + } + + fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool { + layout.is_gcc_scalar_pair() + } + + fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 { + layout.gcc_field_index(index) + } + + fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, immediate: bool) -> Type<'gcc> { + layout.scalar_pair_element_gcc_type(self, index, immediate) + } + + fn cast_backend_type(&self, ty: &CastTarget) -> Type<'gcc> { + ty.gcc_type(self) + } + + fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { + fn_abi.ptr_to_gcc_type(self) + } + + fn reg_backend_type(&self, _ty: &Reg) -> Type<'gcc> { + unimplemented!(); + } + + fn fn_decl_backend_type(&self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> { + // FIXME(antoyo): return correct type. + self.type_void() + } +} diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh new file mode 100755 index 0000000000000..944d0ce516e0f --- /dev/null +++ b/compiler/rustc_codegen_gcc/test.sh @@ -0,0 +1,217 @@ +#!/bin/bash + +# TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed? + +set -e + +if [ -f ./gcc_path ]; then + export GCC_PATH=$(cat gcc_path) +else + echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details' + exit 1 +fi + +export LD_LIBRARY_PATH="$GCC_PATH" +export LIBRARY_PATH="$GCC_PATH" + +if [[ "$1" == "--release" ]]; then + export CHANNEL='release' + CARGO_INCREMENTAL=1 cargo rustc --release + shift +else + echo $LD_LIBRARY_PATH + export CHANNEL='debug' + cargo rustc +fi + +source config.sh + +function clean() { + rm -r target/out || true + mkdir -p target/out/gccjit +} + +function mini_tests() { + echo "[BUILD] mini_core" + $RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target $TARGET_TRIPLE + + echo "[BUILD] example" + $RUSTC example/example.rs --crate-type lib --target $TARGET_TRIPLE + + echo "[AOT] mini_core_hello_world" + $RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd +} + +function build_sysroot() { + echo "[BUILD] sysroot" + time ./build_sysroot/build_sysroot.sh +} + +function std_tests() { + echo "[AOT] arbitrary_self_types_pointers_and_wrappers" + $RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers + + echo "[AOT] alloc_system" + $RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE" + + echo "[AOT] alloc_example" + $RUSTC example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/alloc_example + + echo "[AOT] dst_field_align" + # FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed. + $RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false) + + echo "[AOT] std_example" + $RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE + + echo "[AOT] subslice-patterns-const-eval" + $RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/subslice-patterns-const-eval + + echo "[AOT] track-caller-attribute" + $RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUN_WRAPPER ./target/out/track-caller-attribute + + echo "[BUILD] mod_bench" + $RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE +} + +# FIXME(antoyo): linker gives multiple definitions error on Linux +#echo "[BUILD] sysroot in release mode" +#./build_sysroot/build_sysroot.sh --release + +# TODO(antoyo): uncomment when it works. +#pushd simple-raytracer +#if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then + #echo "[BENCH COMPILE] ebobby/simple-raytracer" + #hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "rm -r target/*/debug || true" \ + #"RUSTFLAGS='' cargo build --target $TARGET_TRIPLE" \ + #"../cargo.sh build" + + #echo "[BENCH RUN] ebobby/simple-raytracer" + #cp ./target/*/debug/main ./raytracer_cg_gccjit + #hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_gccjit +#else + #echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)" + #echo "[COMPILE] ebobby/simple-raytracer" + #../cargo.sh build + #echo "[BENCH RUN] ebobby/simple-raytracer (skipped)" +#fi +#popd + +function test_libcore() { + pushd build_sysroot/sysroot_src/library/core/tests + echo "[TEST] libcore" + rm -r ./target || true + ../../../../../cargo.sh test + popd +} + +# TODO(antoyo): uncomment when it works. +#pushd regex +#echo "[TEST] rust-lang/regex example shootout-regex-dna" +#../cargo.sh clean +## Make sure `[codegen mono items] start` doesn't poison the diff +#../cargo.sh build --example shootout-regex-dna +#cat examples/regexdna-input.txt | ../cargo.sh run --example shootout-regex-dna | grep -v "Spawned thread" > res.txt +#diff -u res.txt examples/regexdna-output.txt + +#echo "[TEST] rust-lang/regex tests" +#../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options +#popd + +#echo +#echo "[BENCH COMPILE] mod_bench" + +#COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline" +#COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o target/out/mod_bench_llvm_0 -Cpanic=abort" +#COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o target/out/mod_bench_llvm_1 -Cpanic=abort" +#COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o target/out/mod_bench_llvm_2 -Cpanic=abort" +#COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o target/out/mod_bench_llvm_3 -Cpanic=abort" + +## Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow +#hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3" + +#echo +#echo "[BENCH RUN] mod_bench" +#hyperfine --runs ${RUN_RUNS:-10} ./target/out/mod_bench{,_inline} ./target/out/mod_bench_llvm_* + +function test_rustc() { + echo + echo "[TEST] rust-lang/rust" + + rust_toolchain=$(cat rust-toolchain) + + git clone https://github.com/rust-lang/rust.git || true + cd rust + git fetch + git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') + export RUSTFLAGS= + + rm config.toml || true + + cat > config.toml <>() + .join("\n"); + Some(lines) + }) + .test_cmds(move |path| { + // Test command 1: Compile `x.rs` into `tempdir/x`. + let mut exe = PathBuf::new(); + exe.push(&tempdir); + exe.push(path.file_stem().expect("file_stem")); + let mut compiler = Command::new("rustc"); + compiler.args(&[ + &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir), + "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir), + "-Zno-parallel-llvm", + "-C", "panic=abort", + "-C", "link-arg=-lc", + "-o", exe.to_str().expect("to_str"), + path.to_str().expect("to_str"), + ]); + // Test command 2: run `tempdir/x`. + let runtime = Command::new(exe); + vec![("Compiler", compiler), ("Run-time", runtime)] + }) + .run(); +} diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs new file mode 100644 index 0000000000000..291af5993aa25 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs @@ -0,0 +1,51 @@ +// Compiler: +// +// Run-time: +// status: signal + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod intrinsics { + use super::Sized; + + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +/* + * Code + */ + +fn test_fail() -> ! { + unsafe { intrinsics::abort() }; +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + test_fail(); +} diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs new file mode 100644 index 0000000000000..3c87c567892b5 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs @@ -0,0 +1,53 @@ +// Compiler: +// +// Run-time: +// status: signal + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod intrinsics { + use super::Sized; + + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +/* + * Code + */ + +fn fail() -> i32 { + unsafe { intrinsics::abort() }; + 0 +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + fail(); + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs new file mode 100644 index 0000000000000..8b621d8a3530f --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/array.rs @@ -0,0 +1,229 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 42 +// 7 +// 5 +// 10 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i16 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + + +/* + * Code + */ + +static mut ONE: usize = 1; + +fn make_array() -> [u8; 3] { + [42, 10, 5] +} + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + let array = [42, 7, 5]; + let array2 = make_array(); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE - 1]); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE]); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE + 1]); + + libc::printf(b"%d\n\0" as *const u8 as *const i8, array2[argc as usize] as u32); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs new file mode 100644 index 0000000000000..9c0055b0b6b5e --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs @@ -0,0 +1,153 @@ +// Compiler: +// +// Run-time: +// status: 0 + +#![feature(asm, global_asm)] + +global_asm!(" + .global add_asm +add_asm: + mov rax, rdi + add rax, rsi + ret" +); + +extern "C" { + fn add_asm(a: i64, b: i64) -> i64; +} + +fn main() { + unsafe { + asm!("nop"); + } + + let x: u64; + unsafe { + asm!("mov $5, {}", + out(reg) x, + options(att_syntax) + ); + } + assert_eq!(x, 5); + + let x: u64; + let input: u64 = 42; + unsafe { + asm!("mov {input}, {output}", + "add $1, {output}", + input = in(reg) input, + output = out(reg) x, + options(att_syntax) + ); + } + assert_eq!(x, 43); + + let x: u64; + unsafe { + asm!("mov {}, 6", + out(reg) x, + ); + } + assert_eq!(x, 6); + + let x: u64; + let input: u64 = 42; + unsafe { + asm!("mov {output}, {input}", + "add {output}, 1", + input = in(reg) input, + output = out(reg) x, + ); + } + assert_eq!(x, 43); + + // check inout(reg_class) x + let mut x: u64 = 42; + unsafe { + asm!("add {0}, {0}", + inout(reg) x + ); + } + assert_eq!(x, 84); + + // check inout("reg") x + let mut x: u64 = 42; + unsafe { + asm!("add r11, r11", + inout("r11") x + ); + } + assert_eq!(x, 84); + + // check a mix of + // in("reg") + // inout(class) x => y + // inout (class) x + let x: u64 = 702; + let y: u64 = 100; + let res: u64; + let mut rem: u64 = 0; + unsafe { + asm!("div r11", + in("r11") y, + inout("eax") x => res, + inout("edx") rem, + ); + } + assert_eq!(res, 7); + assert_eq!(rem, 2); + + // check const + let mut x: u64 = 42; + unsafe { + asm!("add {}, {}", + inout(reg) x, + const 1 + ); + } + assert_eq!(x, 43); + + // check const (ATT syntax) + let mut x: u64 = 42; + unsafe { + asm!("add {}, {}", + const 1, + inout(reg) x, + options(att_syntax) + ); + } + assert_eq!(x, 43); + + // check sym fn + extern "C" fn foo() -> u64 { 42 } + let x: u64; + unsafe { + asm!("call {}", sym foo, lateout("rax") x); + } + assert_eq!(x, 42); + + // check sym fn (ATT syntax) + let x: u64; + unsafe { + asm!("call {}", sym foo, lateout("rax") x, options(att_syntax)); + } + assert_eq!(x, 42); + + // check sym static + static FOO: u64 = 42; + let x: u64; + unsafe { + asm!("mov {1}, qword ptr [rip + {0}]", sym FOO, lateout(reg) x); + } + assert_eq!(x, 42); + + // check sym static (ATT syntax) + let x: u64; + unsafe { + asm!("movq {0}(%rip), {1}", sym FOO, lateout(reg) x, options(att_syntax)); + } + assert_eq!(x, 42); + + assert_eq!(unsafe { add_asm(40, 2) }, 42); +} diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs new file mode 100644 index 0000000000000..cc8647006ca63 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs @@ -0,0 +1,153 @@ +// Compiler: +// +// Run-time: +// stdout: 2 +// 7 8 +// 10 + +#![allow(unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for *mut i32 {} +impl Copy for usize {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i32 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn fflush(stream: *mut i32) -> i32; + pub fn printf(format: *const i8, ...) -> i32; + + pub static STDOUT: *mut i32; + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + libc::fflush(libc::STDOUT); + intrinsics::abort(); + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +/* + * Code + */ + +fn inc_ref(num: &mut isize) -> isize { + *num = *num + 5; + *num + 1 +} + +fn inc(num: isize) -> isize { + num + 1 +} + + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + argc = inc(argc); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); + } + + let b = inc_ref(&mut argc); + unsafe { + libc::printf(b"%ld %ld\n\0" as *const u8 as *const i8, argc, b); + } + + argc = 10; + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs new file mode 100644 index 0000000000000..7121a5f0d5221 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs @@ -0,0 +1,230 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: Arg: 1 +// Argument: 1 +// String arg: 1 +// Int argument: 2 +// Both args: 11 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, + unboxed_closures)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u32 {} +impl Copy for u8 {} +impl Copy for i8 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn printf(format: *const i8, ...) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "unsize"] +pub trait Unsize {} + +#[lang = "coerce_unsized"] +pub trait CoerceUnsized {} + +impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + +#[lang = "fn_once"] +#[rustc_paren_sugar] +pub trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +#[lang = "fn_mut"] +#[rustc_paren_sugar] +pub trait FnMut: FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let string = "Arg: %d\n\0"; + let mut closure = || { + unsafe { + libc::printf(string as *const str as *const i8, argc); + } + }; + closure(); + + let mut closure = || { + unsafe { + libc::printf("Argument: %d\n\0" as *const str as *const i8, argc); + } + }; + closure(); + + let mut closure = |string| { + unsafe { + libc::printf(string as *const str as *const i8, argc); + } + }; + closure("String arg: %d\n\0"); + + let mut closure = |arg: isize| { + unsafe { + libc::printf("Int argument: %d\n\0" as *const str as *const i8, arg); + } + }; + closure(argc + 1); + + let mut closure = |string, arg: isize| { + unsafe { + libc::printf(string as *const str as *const i8, arg); + } + }; + closure("Both args: %d\n\0", argc + 10); + + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs new file mode 100644 index 0000000000000..6a2e2d5bb11a9 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs @@ -0,0 +1,320 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: true +// 1 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for u64 {} +impl Copy for i32 {} +impl Copy for u32 {} +impl Copy for bool {} +impl Copy for u16 {} +impl Copy for i16 {} +impl Copy for char {} +impl Copy for i8 {} +impl Copy for u8 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +#[lang = "eq"] +pub trait PartialEq { + fn eq(&self, other: &Rhs) -> bool; + fn ne(&self, other: &Rhs) -> bool; +} + +impl PartialEq for u8 { + fn eq(&self, other: &u8) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u8) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for u16 { + fn eq(&self, other: &u16) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u16) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for u32 { + fn eq(&self, other: &u32) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u32) -> bool { + (*self) != (*other) + } +} + + +impl PartialEq for u64 { + fn eq(&self, other: &u64) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &u64) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for usize { + fn eq(&self, other: &usize) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &usize) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for i8 { + fn eq(&self, other: &i8) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &i8) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for i32 { + fn eq(&self, other: &i32) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &i32) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for isize { + fn eq(&self, other: &isize) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &isize) -> bool { + (*self) != (*other) + } +} + +impl PartialEq for char { + fn eq(&self, other: &char) -> bool { + (*self) == (*other) + } + fn ne(&self, other: &char) -> bool { + (*self) != (*other) + } +} + +/* + * Code + */ + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + unsafe { + if argc == 1 { + libc::printf(b"true\n\0" as *const u8 as *const i8); + } + + let string = + match argc { + 1 => b"1\n\0", + 2 => b"2\n\0", + 3 => b"3\n\0", + 4 => b"4\n\0", + 5 => b"5\n\0", + _ => b"_\n\0", + }; + libc::printf(string as *const u8 as *const i8); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs new file mode 100644 index 0000000000000..c02cfd2a85f03 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs @@ -0,0 +1,39 @@ +// Compiler: +// +// Run-time: +// status: 0 + +#![feature(auto_traits, lang_items, no_core, start)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs new file mode 100644 index 0000000000000..956e53dd4aa65 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs @@ -0,0 +1,49 @@ +// Compiler: +// +// Run-time: +// status: 2 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn exit(status: i32); + } +} + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + unsafe { + libc::exit(2); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs new file mode 100644 index 0000000000000..eeab352095123 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs @@ -0,0 +1,39 @@ +// Compiler: +// +// Run-time: +// status: 1 + +#![feature(auto_traits, lang_items, no_core, start)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + 1 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs new file mode 100644 index 0000000000000..a226fff79e51b --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs @@ -0,0 +1,223 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 1 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i16 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + + +/* + * Code + */ + +fn i16_as_i8(a: i16) -> i8 { + a as i8 +} + +fn call_func(func: fn(i16) -> i8, param: i16) -> i8 { + func(param) +} + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let result = call_func(i16_as_i8, argc as i16) as isize; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, result); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs new file mode 100644 index 0000000000000..7111703ca2532 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs @@ -0,0 +1,129 @@ +// Compiler: +// +// Run-time: +// stdout: Panicking +// status: signal + +#![allow(unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for *mut i32 {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u8 {} +impl Copy for i8 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn fflush(stream: *mut i32) -> i32; + + pub static STDOUT: *mut i32; + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + libc::fflush(libc::STDOUT); + intrinsics::abort(); + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let int = 9223372036854775807isize; + let int = int + argc; + int +} diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs new file mode 100644 index 0000000000000..e8876009cc610 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs @@ -0,0 +1,165 @@ + +// Compiler: +// +// Run-time: +// stdout: 2 +// 7 +// 6 +// 11 + +#![allow(unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for *mut i32 {} +impl Copy for usize {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i32 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn puts(s: *const u8) -> i32; + pub fn fflush(stream: *mut i32) -> i32; + pub fn printf(format: *const i8, ...) -> i32; + + pub static STDOUT: *mut i32; + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + libc::fflush(libc::STDOUT); + intrinsics::abort(); + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +/* + * Code + */ + +struct Test { + field: isize, +} + +fn test(num: isize) -> Test { + Test { + field: num + 1, + } +} + +fn update_num(num: &mut isize) { + *num = *num + 5; +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let mut test = test(argc); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); + } + update_num(&mut test.field); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); + } + + update_num(&mut argc); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); + } + + let refe = &mut argc; + *refe = *refe + 5; + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); + } + + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs new file mode 100644 index 0000000000000..4dc375309e426 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs @@ -0,0 +1,221 @@ +// Compiler: +// +// Run-time: +// stdout: 41 +// 39 +// 10 + +#![allow(unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for *mut i32 {} +impl Copy for usize {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} + +#[lang = "deref"] +pub trait Deref { + type Target: ?Sized; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + pub fn fflush(stream: *mut i32) -> i32; + + pub static STDOUT: *mut i32; + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + libc::fflush(libc::STDOUT); + intrinsics::abort(); + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +#[lang = "mul"] +pub trait Mul { + type Output; + + #[must_use] + fn mul(self, rhs: RHS) -> Self::Output; +} + +impl Mul for u8 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +impl Mul for usize { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +impl Mul for isize { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + self * rhs + } +} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, 10 * argc); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs new file mode 100644 index 0000000000000..6ac099ea145c2 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs @@ -0,0 +1,222 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 1 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u8 {} +impl Copy for i8 {} +impl Copy for i16 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + pub fn puts(s: *const u8) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic"] +#[track_caller] +#[no_mangle] +pub fn panic(_msg: &str) -> ! { + unsafe { + libc::puts("Panicking\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +#[lang = "add"] +trait Add { + type Output; + + fn add(self, rhs: RHS) -> Self::Output; +} + +impl Add for u8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i8 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for i32 { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for usize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +impl Add for isize { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + self + rhs + } +} + +#[lang = "sub"] +pub trait Sub { + type Output; + + fn sub(self, rhs: RHS) -> Self::Output; +} + +impl Sub for usize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for isize { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for u8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i8 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + +impl Sub for i16 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + self - rhs + } +} + + +/* + * Code + */ + +static mut ONE: usize = 1; + +fn make_array() -> [u8; 3] { + [42, 10, 5] +} + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + unsafe { + let ptr = ONE as *mut usize; + let value = ptr as usize; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, value); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs new file mode 100644 index 0000000000000..6fa10dca06f67 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs @@ -0,0 +1,72 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 10 +// 10 +// 42 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +#[lang = "copy"] +pub unsafe trait Copy {} + +unsafe impl Copy for bool {} +unsafe impl Copy for u8 {} +unsafe impl Copy for u16 {} +unsafe impl Copy for u32 {} +unsafe impl Copy for u64 {} +unsafe impl Copy for usize {} +unsafe impl Copy for i8 {} +unsafe impl Copy for i16 {} +unsafe impl Copy for i32 {} +unsafe impl Copy for isize {} +unsafe impl Copy for f32 {} +unsafe impl Copy for char {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +/* + * Code + */ + +fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) { + ( + a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8, + b as u32, + ) +} + +#[start] +fn main(argc: isize, _argv: *const *const u8) -> isize { + let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42); + unsafe { + libc::printf(b"%d\n\0" as *const u8 as *const i8, c); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, d); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, j); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs new file mode 100644 index 0000000000000..ad9258ed0bdeb --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs @@ -0,0 +1,128 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 5 + +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} +impl Copy for usize {} +impl Copy for i32 {} +impl Copy for u32 {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +#[lang = "index"] +pub trait Index { + type Output: ?Sized; + fn index(&self, index: Idx) -> &Self::Output; +} + +impl Index for [T; 3] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +impl Index for [T] { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self[index] + } +} + +#[lang = "unsize"] +pub trait Unsize {} + +#[lang = "coerce_unsized"] +pub trait CoerceUnsized {} + +impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +#[lang = "panic_location"] +struct PanicLocation { + file: &'static str, + line: u32, + column: u32, +} + +#[lang = "panic_bounds_check"] +#[track_caller] +#[no_mangle] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); + intrinsics::abort(); + } +} + +mod intrinsics { + use super::Sized; + + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +/* + * Code + */ + +static mut TWO: usize = 2; + +fn index_slice(s: &[u32]) -> u32 { + unsafe { + s[TWO] + } +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let array = [42, 7, 5]; + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array)); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs new file mode 100644 index 0000000000000..ab89f6aff4b50 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/static.rs @@ -0,0 +1,106 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 10 +// 14 +// 1 +// 12 +// 12 +// 1 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod intrinsics { + use super::Sized; + + extern "rust-intrinsic" { + pub fn abort() -> !; + } +} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +#[lang = "structural_peq"] +pub trait StructuralPartialEq {} + +#[lang = "structural_teq"] +pub trait StructuralEq {} + +#[lang = "drop_in_place"] +#[allow(unconditional_recursion)] +pub unsafe fn drop_in_place(to_drop: *mut T) { + // Code here does not matter - this is replaced by the + // real drop glue by the compiler. + drop_in_place(to_drop); +} + +/* + * Code + */ + +struct Test { + field: isize, +} + +struct WithRef { + refe: &'static Test, +} + +static mut CONSTANT: isize = 10; + +static mut TEST: Test = Test { + field: 12, +}; + +static mut TEST2: Test = Test { + field: 14, +}; + +static mut WITH_REF: WithRef = WithRef { + refe: unsafe { &TEST }, +}; + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field); + TEST2.field = argc; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field); + WITH_REF.refe = &TEST2; + libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST.field); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs new file mode 100644 index 0000000000000..6c8884855ac35 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs @@ -0,0 +1,70 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 1 +// 2 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +/* + * Code + */ + +struct Test { + field: isize, +} + +struct Two { + two: isize, +} + +fn one() -> isize { + 1 +} + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let test = Test { + field: one(), + }; + let two = Two { + two: 2, + }; + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); + libc::printf(b"%ld\n\0" as *const u8 as *const i8, two.two); + } + 0 +} diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs new file mode 100644 index 0000000000000..0b670bf267424 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs @@ -0,0 +1,51 @@ +// Compiler: +// +// Run-time: +// status: 0 +// stdout: 3 + +#![feature(auto_traits, lang_items, no_core, start, intrinsics)] + +#![no_std] +#![no_core] + +/* + * Core + */ + +// Because we don't have core yet. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +trait Copy { +} + +impl Copy for isize {} + +#[lang = "receiver"] +trait Receiver { +} + +#[lang = "freeze"] +pub(crate) unsafe auto trait Freeze {} + +mod libc { + #[link(name = "c")] + extern "C" { + pub fn printf(format: *const i8, ...) -> i32; + } +} + +/* + * Code + */ + +#[start] +fn main(mut argc: isize, _argv: *const *const u8) -> isize { + let test: (isize, isize, isize) = (3, 1, 4); + unsafe { + libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0); + } + 0 +} diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 3f02443458188..a6a553b31a326 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -26,6 +26,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_llvm = { path = "../rustc_llvm" } rustc_metadata = { path = "../rustc_metadata" } +rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_serialize = { path = "../rustc_serialize" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 1a0a3a0c340fa..dca9c1f04d3c0 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -526,7 +526,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> { }; match self.ret.mode { PassMode::Direct(ref attrs) => { - attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, &bx.cx, callsite); + attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite); } PassMode::Indirect { ref attrs, extra_attrs: _, on_stack } => { assert!(!on_stack); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 9690ad8b24603..341a888241698 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -105,7 +105,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { let r = r.unwrap(); // Again, based on how many outputs we have - let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect); + let outputs = ia.outputs.iter().zip(&outputs).filter(|&(o, _)| !o.is_indirect); for (i, (_, &place)) in outputs.enumerate() { let v = if num_outputs == 1 { r } else { self.extract_value(r, i as u64) }; OperandValue::Immediate(v).store(self, place); @@ -331,7 +331,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { let output_type = match &output_types[..] { [] => self.type_void(), [ty] => ty, - tys => self.type_struct(&tys, false), + tys => self.type_struct(tys, false), }; let dialect = match asm_arch { InlineAsmArch::X86 | InlineAsmArch::X86_64 diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 4e86946219fb1..ebc3b70415854 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -11,7 +11,7 @@ use crate::llvm::archive_ro::{ArchiveRO, Child}; use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport}; use rustc_codegen_ssa::back::archive::ArchiveBuilder; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_middle::middle::cstore::{DllCallingConvention, DllImport}; +use rustc_session::cstore::{DllCallingConvention, DllImport}; use rustc_session::Session; struct ArchiveConfig<'a> { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 99b30264d0958..e2b33509b408d 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -109,7 +109,7 @@ fn prepare_lto( .extend(exported_symbols[&cnum].iter().filter_map(symbol_filter)); } - let archive = ArchiveRO::open(&path).expect("wanted an rlib"); + let archive = ArchiveRO::open(path).expect("wanted an rlib"); let obj_files = archive .iter() .filter_map(|child| child.ok().and_then(|c| c.name().map(|name| (name, c)))) @@ -316,14 +316,14 @@ fn fat_lto( .generic_activity_with_arg("LLVM_fat_lto_link_module", format!("{:?}", name)); info!("linking {:?}", name); let data = bc_decoded.data(); - linker.add(&data).map_err(|()| { + linker.add(data).map_err(|()| { let msg = format!("failed to load bc of {:?}", name); - write::llvm_err(&diag_handler, &msg) + write::llvm_err(diag_handler, &msg) })?; serialized_bitcode.push(bc_decoded); } drop(linker); - save_temp_bitcode(&cgcx, &module, "lto.input"); + save_temp_bitcode(cgcx, &module, "lto.input"); // Fat LTO also suffers from the invalid DWARF issue similar to Thin LTO. // Here we rewrite all `DICompileUnit` pointers if there is only one `DICompileUnit`. @@ -347,14 +347,14 @@ fn fat_lto( ptr as *const *const libc::c_char, symbols_below_threshold.len() as libc::size_t, ); - save_temp_bitcode(&cgcx, &module, "lto.after-restriction"); + save_temp_bitcode(cgcx, &module, "lto.after-restriction"); } if cgcx.no_landing_pads { unsafe { llvm::LLVMRustMarkAllFunctionsNounwind(llmod); } - save_temp_bitcode(&cgcx, &module, "lto.after-nounwind"); + save_temp_bitcode(cgcx, &module, "lto.after-nounwind"); } } @@ -498,7 +498,7 @@ fn thin_lto( symbols_below_threshold.as_ptr(), symbols_below_threshold.len() as u32, ) - .ok_or_else(|| write::llvm_err(&diag_handler, "failed to prepare thin LTO context"))?; + .ok_or_else(|| write::llvm_err(diag_handler, "failed to prepare thin LTO context"))?; let data = ThinData(data); @@ -572,7 +572,7 @@ fn thin_lto( if let Some(path) = key_map_path { if let Err(err) = curr_key_map.save_to_file(&path) { let msg = format!("Error while writing ThinLTO key data: {}", err); - return Err(write::llvm_err(&diag_handler, &msg)); + return Err(write::llvm_err(diag_handler, &msg)); } } @@ -744,8 +744,7 @@ pub unsafe fn optimize_thin_module( // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = - parse_module(llcx, &module_name, thin_module.data(), &diag_handler)? as *const _; + let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _; let module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, llcx, tm }, name: thin_module.name().to_string(), @@ -754,7 +753,7 @@ pub unsafe fn optimize_thin_module( { let target = &*module.module_llvm.tm; let llmod = module.module_llvm.llmod(); - save_temp_bitcode(&cgcx, &module, "thin-lto-input"); + save_temp_bitcode(cgcx, &module, "thin-lto-input"); // Before we do much else find the "main" `DICompileUnit` that we'll be // using below. If we find more than one though then rustc has changed @@ -775,7 +774,7 @@ pub unsafe fn optimize_thin_module( .prof .generic_activity_with_arg("LLVM_thin_lto_remove_landing_pads", thin_module.name()); llvm::LLVMRustMarkAllFunctionsNounwind(llmod); - save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind"); + save_temp_bitcode(cgcx, &module, "thin-lto-after-nounwind"); } // Up next comes the per-module local analyses that we do for Thin LTO. @@ -947,7 +946,7 @@ pub fn parse_module<'a>( llvm::LLVMRustParseBitcodeForLTO(cx, data.as_ptr(), data.len(), name.as_ptr()).ok_or_else( || { let msg = "failed to parse bitcode for LTO module"; - write::llvm_err(&diag_handler, msg) + write::llvm_err(diag_handler, msg) }, ) } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 791604a18273d..ab48c56a62663 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -41,7 +41,7 @@ use std::sync::Arc; pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError { match llvm::last_error() { Some(err) => handler.fatal(&format!("{}: {}", msg, err)), - None => handler.fatal(&msg), + None => handler.fatal(msg), } } @@ -96,7 +96,7 @@ pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut ll None }; let config = TargetMachineFactoryConfig { split_dwarf_file }; - target_machine_factory(&tcx.sess, tcx.backend_optimization_level(()))(config) + target_machine_factory(tcx.sess, tcx.backend_optimization_level(()))(config) .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise()) } @@ -129,7 +129,8 @@ fn to_pass_builder_opt_level(cfg: config::OptLevel) -> llvm::PassBuilderOptLevel fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel { match relocation_model { RelocModel::Static => llvm::RelocModel::Static, - RelocModel::Pic => llvm::RelocModel::PIC, + // LLVM doesn't have a PIE relocation model, it represents PIE as PIC with an extra attribute. + RelocModel::Pic | RelocModel::Pie => llvm::RelocModel::PIC, RelocModel::DynamicNoPic => llvm::RelocModel::DynamicNoPic, RelocModel::Ropi => llvm::RelocModel::ROPI, RelocModel::Rwpi => llvm::RelocModel::RWPI, @@ -370,8 +371,9 @@ fn get_pgo_use_path(config: &ModuleConfig) -> Option { } pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool { - // The new pass manager is disabled by default. - config.new_llvm_pass_manager.unwrap_or(false) + // The new pass manager is enabled by default for LLVM >= 13. + // This matches Clang, which also enables it since Clang 13. + config.new_llvm_pass_manager.unwrap_or_else(|| llvm_util::get_version() >= (13, 0, 0)) } pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( @@ -404,13 +406,15 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( None }; - let llvm_selfprofiler = if cgcx.prof.llvm_recording_enabled() { - let mut llvm_profiler = LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap()); - &mut llvm_profiler as *mut _ as *mut c_void + let mut llvm_profiler = if cgcx.prof.llvm_recording_enabled() { + Some(LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap())) } else { - std::ptr::null_mut() + None }; + let llvm_selfprofiler = + llvm_profiler.as_mut().map(|s| s as *mut _ as *mut c_void).unwrap_or(std::ptr::null_mut()); + let extra_passes = config.passes.join(","); // FIXME: NewPM doesn't provide a facility to pass custom InlineParams. @@ -554,7 +558,7 @@ pub(crate) unsafe fn optimize( let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal || (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled()); - with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| { + with_llvm_pmb(llmod, config, opt_level, prepare_for_thin_lto, &mut |b| { llvm::LLVMRustAddLastExtensionPasses( b, extra_passes.as_ptr(), @@ -656,9 +660,9 @@ pub(crate) fn link( let _timer = cgcx.prof.generic_activity_with_arg("LLVM_link_module", format!("{:?}", module.name)); let buffer = ModuleBuffer::new(module.module_llvm.llmod()); - linker.add(&buffer.data()).map_err(|()| { + linker.add(buffer.data()).map_err(|()| { let msg = format!("failed to serialize module {:?}", module.name); - llvm_err(&diag_handler, &msg) + llvm_err(diag_handler, &msg) })?; } drop(linker); diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index a6bdbd11899de..3026c2fa0309a 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -25,9 +25,9 @@ use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_data_structures::small_c_str::SmallCStr; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::exported_symbols; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::TyCtxt; @@ -64,7 +64,7 @@ pub fn write_compressed_metadata<'tcx>( let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod()); let mut compressed = rustc_metadata::METADATA_HEADER.to_vec(); - FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap(); + FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap(); let llmeta = common::bytes_in_context(metadata_llcx, &compressed); let llconst = common::struct_in_context(metadata_llcx, &[llmeta], false); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index dab7d3eaa8cfd..9f7b8616d7817 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -86,7 +86,7 @@ impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { impl HasTargetSpec for Builder<'_, '_, 'tcx> { #[inline] fn target_spec(&self) -> &Target { - &self.cx.target_spec() + self.cx.target_spec() } } diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index a96ba148a6ce3..5d68d2b77d42e 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -44,7 +44,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); - let llfn = if let Some(llfn) = cx.get_declared_value(&sym) { + let llfn = if let Some(llfn) = cx.get_declared_value(sym) { // Create a fn pointer with the new signature. let llptrty = fn_abi.ptr_to_llvm_type(cx); @@ -79,7 +79,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value llfn } } else { - let llfn = cx.declare_fn(&sym, &fn_abi); + let llfn = cx.declare_fn(sym, fn_abi); debug!("get_fn: not casting pointer!"); attributes::from_fn_attrs(cx, llfn, instance); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index ef3a90fdecaaa..1afa6f0283670 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -178,7 +178,7 @@ fn check_and_apply_linkage( }; unsafe { // Declare a symbol `foo` with the desired linkage. - let g1 = cx.declare_global(&sym, llty2); + let g1 = cx.declare_global(sym, llty2); llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); // Declare an internal global `extern_with_linkage_foo` which @@ -188,7 +188,7 @@ fn check_and_apply_linkage( // `extern_with_linkage_foo` will instead be initialized to // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); - real_name.push_str(&sym); + real_name.push_str(sym); let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| { cx.sess().span_fatal( cx.tcx.def_span(span_def_id), @@ -202,7 +202,7 @@ fn check_and_apply_linkage( } else { // Generate an external declaration. // FIXME(nagisa): investigate whether it can be changed into define_global - cx.declare_global(&sym, llty) + cx.declare_global(sym, llty) } } @@ -234,7 +234,7 @@ impl CodegenCx<'ll, 'tcx> { _ => self.define_private_global(self.val_ty(cv)), }; llvm::LLVMSetInitializer(gv, cv); - set_global_alignment(&self, gv, align); + set_global_alignment(self, gv, align); llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); gv } @@ -279,7 +279,7 @@ impl CodegenCx<'ll, 'tcx> { g } else { - check_and_apply_linkage(&self, &fn_attrs, ty, sym, def_id) + check_and_apply_linkage(self, fn_attrs, ty, sym, def_id) }; // Thread-local statics in some other crate need to *always* be linked @@ -369,7 +369,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { unsafe { let attrs = self.tcx.codegen_fn_attrs(def_id); - let (v, alloc) = match codegen_static_initializer(&self, def_id) { + let (v, alloc) = match codegen_static_initializer(self, def_id) { Ok(v) => v, // Error has already been reported Err(_) => return, @@ -417,7 +417,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { self.statics_to_rauw.borrow_mut().push((g, new_g)); new_g }; - set_global_alignment(&self, g, self.align_of(ty)); + set_global_alignment(self, g, self.align_of(ty)); llvm::LLVMSetInitializer(g, v); if self.should_assume_dso_local(g, true) { @@ -430,7 +430,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { llvm::LLVMSetGlobalConstant(g, llvm::True); } - debuginfo::create_global_var_metadata(&self, def_id, g); + debuginfo::create_global_var_metadata(self, def_id, g); if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { llvm::set_thread_local_mode(g, self.tls_model); @@ -518,7 +518,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { ); } } else { - base::set_link_section(g, &attrs); + base::set_link_section(g, attrs); } if attrs.flags.contains(CodegenFnAttrFlags::USED) { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 52a12b2fd81d8..257a0ac89d86f 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -195,11 +195,14 @@ pub unsafe fn create_module( let llvm_target = SmallCStr::new(&sess.target.llvm_target); llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); - if sess.relocation_model() == RelocModel::Pic { + let reloc_model = sess.relocation_model(); + if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) { llvm::LLVMRustSetModulePICLevel(llmod); // PIE is potentially more effective than PIC, but can only be used in executables. // If all our outputs are executables, then we can relax PIC to PIE. - if sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) { + if reloc_model == RelocModel::Pie + || sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) + { llvm::LLVMRustSetModulePIELevel(llmod); } } @@ -360,7 +363,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) { let section = cstr!("llvm.metadata"); - let array = self.const_array(&self.type_ptr_to(self.type_i8()), values); + let array = self.const_array(self.type_ptr_to(self.type_i8()), values); unsafe { let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); @@ -444,7 +447,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn sess(&self) -> &Session { - &self.tcx.sess + self.tcx.sess } fn check_overflow(&self) -> bool { diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index d2a2e739ff31e..6830864ba04b4 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -73,7 +73,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer); }); debug_assert!( - coverage_mapping_buffer.len() > 0, + !coverage_mapping_buffer.is_empty(), "Every `FunctionCoverage` should have at least one counter" ); @@ -311,8 +311,7 @@ fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) { // for each region in it's MIR. // Convert the `HashSet` of `codegenned_def_ids` to a sortable vector, and sort them. - let mut sorted_codegenned_def_ids: Vec = - codegenned_def_ids.iter().map(|def_id| *def_id).collect(); + let mut sorted_codegenned_def_ids: Vec = codegenned_def_ids.iter().copied().collect(); sorted_codegenned_def_ids.sort_unstable(); let mut first_covered_def_id_by_file: FxHashMap = FxHashMap::default(); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 093aceda2b741..ef11e2972ea3b 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -199,8 +199,8 @@ fn declare_unused_fn(cx: &CodegenCx<'ll, 'tcx>, def_id: &DefId) -> Instance<'tcx ); let llfn = cx.declare_fn( - &tcx.symbol_name(instance).name, - &cx.fn_abi_of_fn_ptr( + tcx.symbol_name(instance).name, + cx.fn_abi_of_fn_ptr( ty::Binder::dummy(tcx.mk_fn_sig( iter::once(tcx.mk_unit()), tcx.mk_unit(), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 1612922d43953..58f8573a2acbf 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -41,7 +41,7 @@ pub fn compute_mir_scopes( // Instantiate all scopes. for idx in 0..mir.source_scopes.len() { let scope = SourceScope::new(idx); - make_mir_scope(cx, instance, &mir, fn_dbg_scope, &has_variables, debug_context, scope); + make_mir_scope(cx, instance, mir, fn_dbg_scope, &has_variables, debug_context, scope); } } @@ -94,7 +94,7 @@ fn make_mir_scope( callee, ); let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); - cx.dbg_scope_fn(callee, &callee_fn_abi, None) + cx.dbg_scope_fn(callee, callee_fn_abi, None) } None => unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlock( diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index c33d35cc285d3..ae1f83d944f59 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -59,10 +59,8 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) - } pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { - let omit_gdb_pretty_printer_section = cx - .tcx - .sess - .contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); + let omit_gdb_pretty_printer_section = + cx.tcx.sess.contains_name(cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); !omit_gdb_pretty_printer_section && cx.sess().opts.debuginfo != DebugInfo::None diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9272435a330a5..8e6a66a617546 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -26,13 +26,13 @@ use rustc_fs_util::path_to_c_string; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::ich::NodeIdHashingMode; use rustc_middle::mir::{self, GeneratorLayout}; use rustc_middle::ty::layout::{self, IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::Instance; use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; +use rustc_query_system::ich::NodeIdHashingMode; use rustc_session::config::{self, DebugInfo}; use rustc_span::symbol::Symbol; use rustc_span::FileNameDisplayPreference; @@ -477,7 +477,7 @@ fn subroutine_type_metadata( let signature_metadata: Vec<_> = iter::once( // return type match signature.output().kind() { - ty::Tuple(ref tys) if tys.is_empty() => None, + ty::Tuple(tys) if tys.is_empty() => None, _ => Some(type_metadata(cx, signature.output(), span)), }, ) @@ -647,7 +647,7 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } - ty::Tuple(ref elements) if elements.is_empty() => { + ty::Tuple(elements) if elements.is_empty() => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } ty::Array(typ, _) | ty::Slice(typ) => { @@ -746,7 +746,7 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp .finalize(cx) } }, - ty::Tuple(ref elements) => { + ty::Tuple(elements) => { let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect(); prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA) .finalize(cx) @@ -932,7 +932,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { let (name, encoding) = match t.kind() { ty::Never => ("!", DW_ATE_unsigned), - ty::Tuple(ref elements) if elements.is_empty() => ("()", DW_ATE_unsigned), + ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned), ty::Bool => ("bool", DW_ATE_boolean), ty::Char => ("char", DW_ATE_unsigned_char), ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed), @@ -1123,7 +1123,7 @@ pub fn compile_unit_metadata( let gcov_cu_info = [ path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")), - path_to_mdstring(debug_context.llcontext, &gcda_path), + path_to_mdstring(debug_context.llcontext, gcda_path), cu_desc_metadata, ]; let gcov_metadata = llvm::LLVMMDNodeInContext( @@ -1963,17 +1963,13 @@ impl<'tcx> VariantInfo<'_, 'tcx> { } fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option> { - match self { - VariantInfo::Generator { def_id, variant_index, .. } => { - let span = cx.tcx.generator_layout(*def_id).unwrap().variant_source_info - [*variant_index] - .span; - if !span.is_dummy() { - let loc = cx.lookup_debug_loc(span.lo()); - return Some(SourceInfo { file: file_metadata(cx, &loc.file), line: loc.line }); - } + if let VariantInfo::Generator { def_id, variant_index, .. } = self { + let span = + cx.tcx.generator_layout(*def_id).unwrap().variant_source_info[*variant_index].span; + if !span.is_dummy() { + let loc = cx.lookup_debug_loc(span.lo()); + return Some(SourceInfo { file: file_metadata(cx, &loc.file), line: loc.line }); } - _ => {} } None } @@ -1994,11 +1990,11 @@ fn describe_enum_variant( let unique_type_id = debug_context(cx) .type_map .borrow_mut() - .get_unique_type_id_of_enum_variant(cx, layout.ty, &variant_name); + .get_unique_type_id_of_enum_variant(cx, layout.ty, variant_name); create_struct_stub( cx, layout.ty, - &variant_name, + variant_name, unique_type_id, Some(containing_scope), DIFlags::FlagZero, @@ -2385,7 +2381,7 @@ fn set_members_of_composite_type( { let mut composite_types_completed = debug_context(cx).composite_types_completed.borrow_mut(); - if !composite_types_completed.insert(&composite_type_metadata) { + if !composite_types_completed.insert(composite_type_metadata) { bug!( "debuginfo::set_members_of_composite_type() - \ Already completed forward declaration re-encountered." diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index fbaf8c8bdf63d..894320a798285 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -328,7 +328,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // name if necessary. let generics = self.tcx().generics_of(enclosing_fn_def_id); let substs = instance.substs.truncate_to(self.tcx(), generics); - let template_parameters = get_template_parameters(self, &generics, substs, &mut name); + let template_parameters = get_template_parameters(self, generics, substs, &mut name); let linkage_name = &mangled_name_of_instance(self, instance).name; // Omit the linkage_name if it is the same as subprogram name. @@ -559,7 +559,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { scope_metadata: &'ll DIScope, file: &rustc_span::SourceFile, ) -> &'ll DILexicalBlock { - metadata::extend_scope_to_file(&self, scope_metadata, file) + metadata::extend_scope_to_file(self, scope_metadata, file) } fn debuginfo_finalize(&self) { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 37b3279fb8096..c43141c769519 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{sym, symbol::kw, Span, Symbol}; use rustc_target::abi::{self, HasDataLayout, Primitive}; -use rustc_target::spec::PanicStrategy; +use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use std::cmp::Ordering; use std::iter; @@ -71,7 +71,7 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<(&'ll T sym::roundf64 => "llvm.round.f64", _ => return None, }; - Some(cx.get_intrinsic(&llvm_name)) + Some(cx.get_intrinsic(llvm_name)) } impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { @@ -96,7 +96,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let arg_tys = sig.inputs(); let ret_ty = sig.output(); let name = tcx.item_name(def_id); - let name_str = &*name.as_str(); let llret_ty = self.layout_of(ret_ty).llvm_type(self); let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); @@ -230,9 +229,14 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &[args[0].immediate(), y], ) } - sym::ctlz_nonzero | sym::cttz_nonzero => { + sym::ctlz_nonzero => { let y = self.const_bool(true); - let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width); + let llvm_name = &format!("llvm.ctlz.i{}", width); + self.call_intrinsic(llvm_name, &[args[0].immediate(), y]) + } + sym::cttz_nonzero => { + let y = self.const_bool(true); + let llvm_name = &format!("llvm.cttz.i{}", width); self.call_intrinsic(llvm_name, &[args[0].immediate(), y]) } sym::ctpop => self.call_intrinsic( @@ -353,7 +357,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { return; } - _ if name_str.starts_with("simd_") => { + _ if name.as_str().starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { Ok(llval) => llval, Err(()) => return, @@ -739,7 +743,7 @@ fn gen_fn<'ll, 'tcx>( ) -> (&'ll Type, &'ll Value) { let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty()); let llty = fn_abi.llvm_type(cx); - let llfn = cx.declare_fn(name, &fn_abi); + let llfn = cx.declare_fn(name, fn_abi); cx.set_frame_pointer_type(llfn); cx.apply_target_cpu_attr(llfn); // FIXME(eddyb) find a nicer way to do this. @@ -843,7 +847,6 @@ fn generic_simd_intrinsic( let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); - let name_str = &*name.as_str(); if name == sym::simd_select_bitmask { let in_ty = arg_tys[0]; @@ -917,7 +920,7 @@ fn generic_simd_intrinsic( )); } - if let Some(stripped) = name_str.strip_prefix("simd_shuffle") { + if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") { // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer. // If there is no suffix, use the index array length. let n: u64 = if stripped.is_empty() { @@ -1156,7 +1159,7 @@ fn generic_simd_intrinsic( _ => return_error!("unrecognized intrinsic `{}`", name), }; let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str); - let f = bx.declare_cfn(&llvm_name, llvm::UnnamedAddr::No, fn_ty); + let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty); let c = bx.call(fn_ty, f, &args.iter().map(|arg| arg.immediate()).collect::>(), None); Ok(c) @@ -1187,11 +1190,28 @@ fn generic_simd_intrinsic( // FIXME: use: // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 - fn llvm_vector_str(elem_ty: Ty<'_>, vec_len: u64, no_pointers: usize) -> String { + fn llvm_vector_str( + elem_ty: Ty<'_>, + vec_len: u64, + no_pointers: usize, + bx: &Builder<'a, 'll, 'tcx>, + ) -> String { let p0s: String = "p0".repeat(no_pointers); match *elem_ty.kind() { - ty::Int(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), - ty::Uint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), + ty::Int(v) => format!( + "v{}{}i{}", + vec_len, + p0s, + // Normalize to prevent crash if v: IntTy::Isize + v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() + ), + ty::Uint(v) => format!( + "v{}{}i{}", + vec_len, + p0s, + // Normalize to prevent crash if v: UIntTy::Usize + v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() + ), ty::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), _ => unreachable!(), } @@ -1327,11 +1347,11 @@ fn generic_simd_intrinsic( // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count); - let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1); - let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx); let llvm_intrinsic = format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str); @@ -1455,11 +1475,11 @@ fn generic_simd_intrinsic( // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count); - let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1); - let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx); let llvm_intrinsic = format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str); @@ -1790,7 +1810,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64); let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty); - let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); + let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty); let v = bx.call(fn_ty, f, &[lhs, rhs], None); return Ok(v); } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1da14344b1d26..8f4d79e7147d3 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -27,8 +27,8 @@ use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ErrorReported, FatalError, Handler}; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::ty::TyCtxt; use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest}; use rustc_session::Session; @@ -211,9 +211,16 @@ impl CodegenBackend for LlvmCodegenBackend { match req { PrintRequest::RelocationModels => { println!("Available relocation models:"); - for name in - &["static", "pic", "dynamic-no-pic", "ropi", "rwpi", "ropi-rwpi", "default"] - { + for name in &[ + "static", + "pic", + "pie", + "dynamic-no-pic", + "ropi", + "rwpi", + "ropi-rwpi", + "default", + ] { println!(" {}", name); } println!(); @@ -332,7 +339,7 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?; - let tm_factory_config = TargetMachineFactoryConfig::new(&cgcx, name.to_str().unwrap()); + let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap()); let tm = match (cgcx.tm_factory)(tm_factory_config) { Ok(m) => m, Err(e) => { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d8c2a345fb03c..436d906827b5b 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -789,7 +789,7 @@ pub mod coverageinfo { start_line, start_col, end_line, - end_col: ((1 as u32) << 31) | end_col, + end_col: (1_u32 << 31) | end_col, kind: RegionKind::GapRegion, } } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index f9172e437733f..b15efcd0dc2b1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -298,7 +298,7 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) { for (feature, desc) in &target_features { println!(" {1:0$} - {2}.", max_feature_len, feature, desc); } - if target_features.len() == 0 { + if target_features.is_empty() { println!(" Target features listing is not supported by this LLVM version."); } println!("\nUse +feature to enable a feature, or -feature to disable it."); @@ -416,6 +416,11 @@ pub fn llvm_global_features(sess: &Session) -> Vec { // -Ctarget-features features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter)); + // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12. + if get_version() >= (12, 0, 0) && sess.target.llvm_target.contains("aarch64-unknown-linux") { + features.push("+outline-atomics".to_string()); + } + features } diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 34982f769d03a..88498cf47d8b0 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -53,10 +53,10 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { assert!(!instance.substs.needs_infer()); let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); - let lldecl = self.declare_fn(symbol_name, &fn_abi); + let lldecl = self.declare_fn(symbol_name, fn_abi); unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); - base::set_link_section(lldecl, &attrs); + base::set_link_section(lldecl, attrs); if linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR { llvm::SetUniqueComdat(self.llmod, lldecl); } @@ -143,6 +143,8 @@ impl CodegenCx<'ll, 'tcx> { return true; } - return false; + // With pie relocation model calls of functions defined in the translation + // unit can use copy relocations. + self.tcx.sess.relocation_model() == RelocModel::Pie && !is_declaration } } diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index c7f4287e28e4a..2ae0a08f192d0 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -248,7 +248,7 @@ impl Type { } fn ptr_to(&self, address_space: AddressSpace) -> &Type { - unsafe { llvm::LLVMPointerType(&self, address_space.0) } + unsafe { llvm::LLVMPointerType(self, address_space.0) } } } diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 757ccbddbeedf..f8c919ec2aa33 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -4,7 +4,7 @@ use crate::type_::Type; use rustc_codegen_ssa::traits::*; use rustc_middle::bug; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; @@ -43,7 +43,8 @@ fn uncached_llvm_type<'a, 'tcx>( // in problematically distinct types due to HRTB and subtyping (see #47638). // ty::Dynamic(..) | ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str => { - let mut name = with_no_trimmed_paths(|| layout.ty.to_string()); + let mut name = + with_no_visible_paths(|| with_no_trimmed_paths(|| layout.ty.to_string())); if let (&ty::Adt(def, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) { @@ -231,7 +232,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx)) } ty::FnPtr(sig) => { - cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())) + cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty())) } _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO), }; @@ -244,7 +245,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { Variants::Single { index } => Some(index), _ => None, }; - if let Some(ref llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) { + if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) { return llty.lltype; } @@ -269,10 +270,9 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { }; debug!("--> mapped {:#?} to llty={:?}", self, llty); - cx.type_lowering.borrow_mut().insert( - (self.ty, variant_index), - TypeLowering { lltype: llty, field_remapping: field_remapping }, - ); + cx.type_lowering + .borrow_mut() + .insert((self.ty, variant_index), TypeLowering { lltype: llty, field_remapping }); if let Some((llty, layout)) = defer { let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout); diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index caafae6c26750..591f659f11bf4 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -125,7 +125,7 @@ fn emit_aapcs_va_arg( // if the offset >= 0 then the value will be on the stack let mut reg_off_v = bx.load(bx.type_i32(), reg_off, offset_align); let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero); - bx.cond_br(use_stack, &on_stack.llbb(), &maybe_reg.llbb()); + bx.cond_br(use_stack, on_stack.llbb(), maybe_reg.llbb()); // The value at this point might be in a register, but there is a chance that // it could be on the stack so we have to update the offset and then check @@ -142,7 +142,7 @@ fn emit_aapcs_va_arg( // Check to see if we have overflowed the registers as a result of this. // If we have then we need to use the stack for this value let use_stack = maybe_reg.icmp(IntPredicate::IntSGT, new_reg_off_v, zero); - maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb()); + maybe_reg.cond_br(use_stack, on_stack.llbb(), in_reg.llbb()); let top_type = bx.type_i8p(); let top = in_reg.struct_gep(va_list_ty, va_list_addr, reg_top_index); @@ -158,17 +158,17 @@ fn emit_aapcs_va_arg( let reg_type = layout.llvm_type(bx); let reg_addr = in_reg.bitcast(reg_addr, bx.cx.type_ptr_to(reg_type)); let reg_value = in_reg.load(reg_type, reg_addr, layout.align.abi); - in_reg.br(&end.llbb()); + in_reg.br(end.llbb()); // On Stack block let stack_value = emit_ptr_va_arg(&mut on_stack, list, target_ty, false, Align::from_bytes(8).unwrap(), true); - on_stack.br(&end.llbb()); + on_stack.br(end.llbb()); let val = end.phi( layout.immediate_llvm_type(bx), &[reg_value, stack_value], - &[&in_reg.llbb(), &on_stack.llbb()], + &[in_reg.llbb(), on_stack.llbb()], ); *bx = end; diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 0713e167c53b8..83dd625611057 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -32,6 +32,8 @@ rustc_hir = { path = "../rustc_hir" } rustc_incremental = { path = "../rustc_incremental" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_query_system = { path = "../rustc_query_system" } rustc_target = { path = "../rustc_target" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 5188abdbe6286..3db948a16fc73 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,5 +1,5 @@ use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_middle::middle::cstore::DllImport; +use rustc_session::cstore::DllImport; use rustc_session::Session; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 826c09cd948f6..ed15b46487240 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3,10 +3,10 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorReported, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::DllImport; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; +use rustc_session::cstore::DllImport; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; @@ -327,7 +327,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( // metadata in rlib files is wrapped in a "dummy" object file for // the target platform so the rlib can be processed entirely by // normal linkers for the platform. - let metadata = create_metadata_file(sess, &codegen_results.metadata.raw_data); + let metadata = create_metadata_file(sess, codegen_results.metadata.raw_data()); ab.add_file(&emit_metadata(sess, &metadata, tmpdir)); // After adding all files to the archive, we need to update the @@ -1490,9 +1490,13 @@ fn exec_linker( fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { let kind = match (crate_type, sess.crt_static(Some(crate_type)), sess.relocation_model()) { (CrateType::Executable, _, _) if sess.is_wasi_reactor() => LinkOutputKind::WasiReactorExe, - (CrateType::Executable, false, RelocModel::Pic) => LinkOutputKind::DynamicPicExe, + (CrateType::Executable, false, RelocModel::Pic | RelocModel::Pie) => { + LinkOutputKind::DynamicPicExe + } (CrateType::Executable, false, _) => LinkOutputKind::DynamicNoPicExe, - (CrateType::Executable, true, RelocModel::Pic) => LinkOutputKind::StaticPicExe, + (CrateType::Executable, true, RelocModel::Pic | RelocModel::Pie) => { + LinkOutputKind::StaticPicExe + } (CrateType::Executable, true, _) => LinkOutputKind::StaticNoPicExe, (_, true, _) => LinkOutputKind::StaticDylib, (_, false, _) => LinkOutputKind::DynamicDylib, diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 0fff319580883..ffeb926e648e5 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -8,7 +8,7 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::rustc_erase_owner; use rustc_data_structures::sync::MetadataRef; -use rustc_middle::middle::cstore::MetadataLoader; +use rustc_session::cstore::MetadataLoader; use rustc_target::spec::Target; use crate::METADATA_FILENAME; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 41823f7d80d69..31722d07414d0 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -21,8 +21,8 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_incremental::{ copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess, }; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::exported_symbols::SymbolExportLevel; use rustc_middle::ty::TyCtxt; use rustc_session::cgu_reuse_tracker::CguReuseTracker; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a6bf1d8d1e51a..9bb4982754c20 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -18,8 +18,8 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; +use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::lang_items; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index e842f5e9391c8..6e7b296859740 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -16,10 +16,10 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; -use rustc_middle::ich::NodeIdHashingMode; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, AdtDef, ExistentialProjection, Ty, TyCtxt}; +use rustc_query_system::ich::NodeIdHashingMode; use rustc_target::abi::{Integer, TagEncoding, Variants}; use smallvec::SmallVec; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 634286770d1f9..b759e3a7a7a33 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -25,10 +25,10 @@ use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; -use rustc_middle::middle::cstore::{self, CrateSource}; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::ty::query::Providers; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; +use rustc_session::cstore::{self, CrateSource}; use rustc_session::utils::NativeLibKind; use rustc_span::symbol::Symbol; use std::path::{Path, PathBuf}; @@ -158,7 +158,7 @@ pub struct CodegenResults { pub modules: Vec, pub allocator_module: Option, pub metadata_module: Option, - pub metadata: rustc_middle::middle::cstore::EncodedMetadata, + pub metadata: rustc_metadata::EncodedMetadata, pub crate_info: CrateInfo, } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 4be050fb88c2d..b0a5631549df8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -15,7 +15,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::AssertKind; use rustc_middle::mir::{self, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; @@ -476,15 +476,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false), }; if do_panic { - let msg_str = with_no_trimmed_paths(|| { - if layout.abi.is_uninhabited() { - // Use this error even for the other intrinsics as it is more precise. - format!("attempted to instantiate uninhabited type `{}`", ty) - } else if intrinsic == ZeroValid { - format!("attempted to zero-initialize type `{}`, which is invalid", ty) - } else { - format!("attempted to leave type `{}` uninitialized, which is invalid", ty) - } + let msg_str = with_no_visible_paths(|| { + with_no_trimmed_paths(|| { + if layout.abi.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{}`", ty) + } else if intrinsic == ZeroValid { + format!("attempted to zero-initialize type `{}`, which is invalid", ty) + } else { + format!( + "attempted to leave type `{}` uninitialized, which is invalid", + ty + ) + } + }) }); let msg = bx.const_str(Symbol::intern(&msg_str)); let location = self.get_caller_location(bx, source_info).immediate(); @@ -777,22 +782,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_argument(&mut bx, op, &mut llargs, &fn_abi.args[i]); } - if let Some(tup) = untuple { + let num_untupled = untuple.map(|tup| { self.codegen_arguments_untupled( &mut bx, tup, &mut llargs, &fn_abi.args[first_args.len()..], ) - } + }); let needs_location = instance.map_or(false, |i| i.def.requires_caller_location(self.cx.tcx())); if needs_location { + let mir_args = if let Some(num_untupled) = num_untupled { + first_args.len() + num_untupled + } else { + args.len() + }; assert_eq!( fn_abi.args.len(), - args.len() + 1, - "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", + mir_args + 1, + "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {:?} {:?} {:?}", + instance, + fn_span, + fn_abi, ); let location = self.get_caller_location(&mut bx, mir::SourceInfo { span: fn_span, ..source_info }); @@ -1122,7 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { operand: &mir::Operand<'tcx>, llargs: &mut Vec, args: &[ArgAbi<'tcx, Ty<'tcx>>], - ) { + ) -> usize { let tuple = self.codegen_operand(bx, operand); // Handle both by-ref and immediate tuples. @@ -1142,6 +1155,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_argument(bx, op, llargs, &args[i]); } } + tuple.layout.fields.count() } fn get_caller_location( diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 37f5de309baff..476ddbd93980c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -258,6 +258,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut idx = 0; let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize; + let mut num_untupled = None; + let args = mir .args_iter() .enumerate() @@ -286,6 +288,11 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let pr_field = place.project_field(bx, i); bx.store_fn_arg(arg, &mut llarg_idx, pr_field); } + assert_eq!( + None, + num_untupled.replace(tupled_arg_tys.len()), + "Replaced existing num_tupled" + ); return LocalRef::Place(place); } @@ -362,10 +369,17 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( .collect::>(); if fx.instance.def.requires_caller_location(bx.tcx()) { + let mir_args = if let Some(num_untupled) = num_untupled { + // Subtract off the tupled argument that gets 'expanded' + args.len() - 1 + num_untupled + } else { + args.len() + }; assert_eq!( fx.fn_abi.args.len(), - args.len() + 1, - "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", + mir_args + 1, + "#[track_caller] instance {:?} must have 1 more argument in their ABI than in their MIR", + fx.instance ); let arg = fx.fn_abi.args.last().unwrap(); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 7403c21a9060e..f087b9f7815da 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -550,6 +550,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty))); (bx, operand) } + mir::Rvalue::ShallowInitBox(ref operand, content_ty) => { + let operand = self.codegen_operand(&mut bx, operand); + let lloperand = operand.immediate(); + + let content_ty = self.monomorphize(content_ty); + let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty)); + let llty_ptr = bx.cx().backend_type(box_layout); + + let val = bx.pointercast(lloperand, llty_ptr); + let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout }; + (bx, operand) + } } } @@ -763,6 +775,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::AddressOf(..) | mir::Rvalue::Len(..) | mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::ShallowInitBox(..) | // (*) mir::Rvalue::BinaryOp(..) | mir::Rvalue::CheckedBinaryOp(..) | mir::Rvalue::UnaryOp(..) | diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 82b79fd0b2ac3..8129a14fcfdc9 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -6,13 +6,14 @@ use crate::{CodegenResults, ModuleCodegen}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorReported; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_session::{ config::{self, OutputFilenames, PrintRequest}, + cstore::MetadataLoaderDyn, Session, }; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index a51273732ae6f..5f659dd977a85 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -21,6 +21,7 @@ rustc_infer = { path = "../rustc_infer" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } +rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } 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 10afd9560fa95..df4cc295fac5f 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -6,23 +6,6 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; use rustc_target::spec::abi::Abi; -/// Whether the `def_id` counts as const fn in your current crate, considering all active -/// feature gates -pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - tcx.is_const_fn_raw(def_id) - && match is_unstable_const_fn(tcx, def_id) { - Some(feature_name) => { - // has a `rustc_const_unstable` attribute, check whether the user enabled the - // corresponding feature gate. - tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name) - } - // functions without const stability are either stable user written - // const fn or the user is using feature gates and we thus don't - // care what they do - None => true, - } -} - /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option { if tcx.is_const_fn_raw(def_id) { @@ -77,7 +60,7 @@ fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - is_const_fn(tcx, def_id) + tcx.is_const_fn(def_id) && match tcx.lookup_const_stability(def_id) { Some(stab) => { if cfg!(debug_assertions) && stab.promotable { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 0521443533b78..cf084faade8cc 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -6,13 +6,13 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; -use rustc_middle::ich::StableHashingContext; use rustc_middle::mir; use rustc_middle::ty::layout::{self, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{ self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, }; use rustc_mir_dataflow::storage::AlwaysLiveLocals; +use rustc_query_system::ich::StableHashingContext; use rustc_session::Limit; use rustc_span::{Pos, Span}; use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 6e35b33188cd2..e6037d561dedc 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -197,12 +197,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Aggregate(ref kind, ref operands) => { + // active_field_index is for union initialization. let (dest, active_field_index) = match **kind { mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { self.write_discriminant(variant_index, &dest)?; if adt_def.is_enum() { - (self.place_downcast(&dest, variant_index)?, active_field_index) + assert!(active_field_index.is_none()); + (self.place_downcast(&dest, variant_index)?, None) } else { + if active_field_index.is_some() { + assert_eq!(operands.len(), 1); + } (dest, active_field_index) } } @@ -211,12 +216,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { for (i, operand) in operands.iter().enumerate() { let op = self.eval_operand(operand, None)?; - // Ignore zero-sized fields. - if !op.layout.is_zst() { - let field_index = active_field_index.unwrap_or(i); - let field_dest = self.place_field(&dest, field_index)?; - self.copy_op(&op, &field_dest)?; - } + let field_index = active_field_index.unwrap_or(i); + let field_dest = self.place_field(&dest, field_index)?; + self.copy_op(&op, &field_dest)?; } } @@ -253,7 +255,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Len(place) => { - // FIXME(CTFE): don't allow computing the length of arrays in const eval let src = self.eval_place(place)?; let mplace = self.force_allocation(&src)?; let len = mplace.len(self)?; @@ -289,6 +290,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?; } + ShallowInitBox(ref operand, _) => { + let src = self.eval_operand(operand, None)?; + let v = self.read_immediate(&src)?; + self.write_immediate(*v, &dest)?; + } + Cast(cast_kind, ref operand, cast_ty) => { let src = self.eval_operand(operand, None)?; let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty); 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 9eec930f59e52..fd5cd269a3a9e 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -650,6 +650,7 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), + Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(_, ref operand) => { let ty = operand.ty(self.body, self.tcx); @@ -886,8 +887,6 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { // At this point, we are calling a function, `callee`, whose `DefId` is known... if is_lang_panic_fn(tcx, callee) { - self.check_op(ops::Panic); - // `begin_panic` and `panic_display` are generic functions that accept // types other than str. Check to enforce that only str can be used in // const-eval. @@ -912,6 +911,11 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> { return; } + if Some(callee) == tcx.lang_items().exchange_malloc_fn() { + self.check_op(ops::HeapAllocation); + return; + } + // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`. let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn(); if is_async_block { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 1d0ee949a221b..230d023efb9fb 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -102,7 +102,7 @@ impl NonConstOp for FnCallUnstable { ); if ccx.is_const_stable_const_fn() { - err.help("Const-stable functions can only call other const-stable functions"); + err.help("const-stable functions can only call other const-stable functions"); } else if ccx.tcx.sess.is_nightly_build() { if let Some(feature) = feature { err.help(&format!( @@ -368,23 +368,6 @@ impl NonConstOp for MutDeref { } } -#[derive(Debug)] -pub struct Panic; -impl NonConstOp for Panic { - fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { - Status::Unstable(sym::const_panic) - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_panic, - span, - &format!("panicking in {}s is unstable", ccx.const_kind()), - ) - } -} - /// A call to a `panic()` lang item where the first argument is _not_ a `&str`. #[derive(Debug)] pub struct PanicNonStr; @@ -407,7 +390,7 @@ impl NonConstOp for RawPtrComparison { let mut err = ccx .tcx .sess - .struct_span_err(span, "pointers cannot be reliably compared during const eval."); + .struct_span_err(span, "pointers cannot be reliably compared during const eval"); err.note( "see issue #53020 \ for more information", @@ -443,7 +426,7 @@ impl NonConstOp for RawPtrToIntCast { let mut err = ccx .tcx .sess - .struct_span_err(span, "pointers cannot be cast to integers during const eval."); + .struct_span_err(span, "pointers cannot be cast to integers during const eval"); err.note("at compile-time, pointers do not have an integer value"); err.note( "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior", diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index cb9b4bcb77a85..5eb7d7a91cc76 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -206,7 +206,8 @@ where Rvalue::Use(operand) | Rvalue::Repeat(operand, _) | Rvalue::UnaryOp(_, operand) - | Rvalue::Cast(_, operand, _) => in_operand::(cx, in_local, operand), + | Rvalue::Cast(_, operand, _) + | Rvalue::ShallowInitBox(operand, _) => in_operand::(cx, in_local, operand), Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { in_operand::(cx, in_local, lhs) || in_operand::(cx, in_local, rhs) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 52d04cb4ff1e0..be1b827f2356f 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -26,7 +26,6 @@ use rustc_index::vec::{Idx, IndexVec}; use std::cell::Cell; use std::{cmp, iter, mem}; -use crate::const_eval::{is_const_fn, is_unstable_const_fn}; use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx}; use crate::transform::MirPass; @@ -523,6 +522,8 @@ impl<'tcx> Validator<'_, 'tcx> { NullOp::AlignOf => {} }, + Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), + Rvalue::UnaryOp(op, operand) => { match op { // These operations can never fail. @@ -656,9 +657,7 @@ impl<'tcx> Validator<'_, 'tcx> { let is_const_fn = match *fn_ty.kind() { ty::FnDef(def_id, _) => { - is_const_fn(self.tcx, def_id) - || is_unstable_const_fn(self.tcx, def_id).is_some() - || is_lang_panic_fn(self.tcx, def_id) + self.tcx.is_const_fn_raw(def_id) || is_lang_panic_fn(self.tcx, def_id) } _ => false, }; @@ -1079,7 +1078,7 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>( if let ty::FnDef(def_id, _) = *literal.ty().kind() { if let Some((destination_place, _)) = destination { if destination_place == place { - if is_const_fn(ccx.tcx, def_id) { + if ccx.tcx.is_const_fn(def_id) { return true; } } diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index e2cbb09ce5e6d..b84f28b6a9edf 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -3,7 +3,7 @@ //! Also computes as the resulting DAG if each SCC is replaced with a //! node in the graph. This uses [Tarjan's algorithm]( //! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm) -//! that completes in *O(n)* time. +//! that completes in *O*(*n*) time. use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; @@ -405,6 +405,7 @@ where /// Call this method when `inspect_node` has returned `None`. Having the /// caller decide avoids mutual recursion between the two methods and allows /// us to maintain an allocated stack for nodes on the path between calls. + #[instrument(skip(self, initial), level = "debug")] fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { struct VisitingNodeFrame { node: G::Node, @@ -451,7 +452,7 @@ where Some(iter) => iter, None => { // This None marks that we still have the initialize this node's frame. - debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node); + debug!(?depth, ?node); debug_assert!(matches!(self.node_states[node], NodeState::NotVisited)); @@ -478,10 +479,7 @@ where return_value.take().into_iter().map(|walk| (*successor_node, Some(walk))); let successor_walk = successors.by_ref().map(|successor_node| { - debug!( - "walk_unvisited_node: node = {:?} successor_ode = {:?}", - node, successor_node - ); + debug!(?node, ?successor_node); (successor_node, self.inspect_node(successor_node)) }); @@ -491,10 +489,7 @@ where // Track the minimum depth we can reach. assert!(successor_min_depth <= depth); if successor_min_depth < *min_depth { - debug!( - "walk_unvisited_node: node = {:?} successor_min_depth = {:?}", - node, successor_min_depth - ); + debug!(?node, ?successor_min_depth); *min_depth = successor_min_depth; *min_cycle_root = successor_node; } @@ -503,16 +498,13 @@ where Some(WalkReturn::Complete { scc_index: successor_scc_index }) => { // Push the completed SCC indices onto // the `successors_stack` for later. - debug!( - "walk_unvisited_node: node = {:?} successor_scc_index = {:?}", - node, successor_scc_index - ); + debug!(?node, ?successor_scc_index); successors_stack.push(successor_scc_index); } None => { let depth = depth + 1; - debug!("walk_node(depth = {:?}, node = {:?})", depth, successor_node); + debug!(?depth, ?successor_node); // Remember which node the return value will come from. frame.successor_node = successor_node; // Start a new stack frame the step into it. diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index b1f04bfbf0a84..94e115ed49856 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -7,12 +7,11 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(allow_internal_unstable)] #![feature(array_windows)] #![feature(associated_type_bounds)] #![feature(auto_traits)] #![feature(bool_to_option)] -#![feature(const_panic)] +#![cfg_attr(bootstrap, feature(const_panic))] #![feature(control_flow_enum)] #![feature(core_intrinsics)] #![feature(extend_one)] diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 9a28f8f4e2106..20e2a3b9696e8 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -9,7 +9,7 @@ mod index_map; pub use index_map::SortedIndexMultiMap; /// `SortedMap` is a data structure with similar characteristics as BTreeMap but -/// slightly different trade-offs: lookup, insertion, and removal are O(log(N)) +/// slightly different trade-offs: lookup, insertion, and removal are *O*(log(*n*)) /// and elements can be iterated in order cheaply. /// /// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index e249886e9bc01..2de05cd4e5679 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -31,7 +31,7 @@ const SSO_ARRAY_SIZE: usize = 8; // // Missing HashMap API: // all hasher-related -// try_reserve (unstable) +// try_reserve // shrink_to (unstable) // drain_filter (unstable) // into_keys/into_values (unstable) diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index 23cff0206c530..29baf4e1ddb66 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -13,7 +13,7 @@ use super::map::SsoHashMap; // // Missing HashSet API: // all hasher-related -// try_reserve (unstable) +// try_reserve // shrink_to (unstable) // drain_filter (unstable) // replace diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs index 30f659c2f71bd..a1ffbae8b15f6 100644 --- a/compiler/rustc_data_structures/src/steal.rs +++ b/compiler/rustc_data_structures/src/steal.rs @@ -33,10 +33,11 @@ impl Steal { #[track_caller] pub fn borrow(&self) -> MappedReadGuard<'_, T> { - ReadGuard::map(self.value.borrow(), |opt| match *opt { - None => panic!("attempted to read from stolen value"), - Some(ref v) => v, - }) + let borrow = self.value.borrow(); + if let None = &*borrow { + panic!("attempted to read from stolen value: {}", std::any::type_name::()); + } + ReadGuard::map(borrow, |opt| opt.as_ref().unwrap()) } #[track_caller] diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 6721e00027d42..ce3a3f5a3a212 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["dylib"] [dependencies] libc = "0.2" atty = "0.2" -tracing = { version = "0.1.25" } +tracing = { version = "0.1.28" } tracing-subscriber = { version = "0.2.16", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } tracing-tree = "0.1.9" rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 4c6a2baaef1e5..ab7ee03b643f8 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -25,12 +25,12 @@ use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::LintStore; use rustc_metadata::locator; -use rustc_middle::middle::cstore::MetadataLoader; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; use rustc_serialize::json::{self, ToJson}; use rustc_session::config::{nightly_options, CG_OPTIONS, DB_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}; +use rustc_session::cstore::MetadataLoader; use rustc_session::getopts; use rustc_session::lint::{Lint, LintId}; use rustc_session::{config, DiagnosticOutput, Session}; @@ -128,7 +128,7 @@ impl Callbacks for TimePassesCallbacks { } pub fn diagnostics_registry() -> Registry { - Registry::new(&rustc_error_codes::DIAGNOSTICS) + Registry::new(rustc_error_codes::DIAGNOSTICS) } /// This is the primary entry point for rustc. @@ -265,8 +265,8 @@ fn run_compiler( &***compiler.codegen_backend(), compiler.session(), None, - &compiler.output_dir(), - &compiler.output_file(), + compiler.output_dir(), + compiler.output_file(), ); if should_stop == Compilation::Stop { @@ -330,7 +330,7 @@ fn run_compiler( let krate = queries.parse()?.take(); pretty::print_after_parsing( sess, - &compiler.input(), + compiler.input(), &krate, *ppm, compiler.output_file().as_ref().map(|p| &**p), @@ -356,7 +356,7 @@ fn run_compiler( // Lint plugins are registered; now we can process command line flags. if sess.opts.describe_lints { - describe_lints(&sess, &lint_store, true); + describe_lints(sess, lint_store, true); return early_exit(); } } @@ -388,7 +388,7 @@ fn run_compiler( save::process_crate( tcx, &crate_name, - &compiler.input(), + compiler.input(), None, DumpHandler::new( compiler.output_dir().as_ref().map(|p| &**p), @@ -598,7 +598,7 @@ impl RustcDefaultCalls { if let Input::File(file) = compiler.input() { // FIXME: #![crate_type] and #![crate_name] support not implemented yet sess.init_crate_types(collect_crate_types(sess, &[])); - let outputs = compiler.build_output_filenames(&sess, &[]); + let outputs = compiler.build_output_filenames(sess, &[]); let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| { sess.fatal(&format!("failed to read rlink file: {}", err)); }); @@ -606,7 +606,7 @@ impl RustcDefaultCalls { json::decode(&rlink_data).unwrap_or_else(|err| { sess.fatal(&format!("failed to decode rlink: {}", err)); }); - let result = compiler.codegen_backend().link(&sess, codegen_results, &outputs); + let result = compiler.codegen_backend().link(sess, codegen_results, &outputs); abort_on_err(result, sess); } else { sess.fatal("rlink must be a file") @@ -894,9 +894,9 @@ Available lint options: }; println!("Lint groups provided by rustc:\n"); - println!(" {} {}", padded("name"), "sub-lints"); - println!(" {} {}", padded("----"), "---------"); - println!(" {} {}", padded("warnings"), "all lints that are set to issue warnings"); + println!(" {} sub-lints", padded("name")); + println!(" {} ---------", padded("----")); + println!(" {} all lints that are set to issue warnings", padded("warnings")); let print_lint_groups = |lints: Vec<(&'static str, Vec)>| { for (name, to) in lints { @@ -1217,7 +1217,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { } for note in &xs { - handler.note_without_error(¬e); + handler.note_without_error(note); } // If backtraces are enabled, also print the query stack @@ -1326,7 +1326,7 @@ mod signal_handler { std::alloc::alloc(std::alloc::Layout::from_size_align(ALT_STACK_SIZE, 1).unwrap()) as *mut libc::c_void; alt_stack.ss_size = ALT_STACK_SIZE; - libc::sigaltstack(&mut alt_stack, std::ptr::null_mut()); + libc::sigaltstack(&alt_stack, std::ptr::null_mut()); let mut sa: libc::sigaction = std::mem::zeroed(); sa.sa_sigaction = print_stack_trace as libc::sighandler_t; diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index a25cc000443c7..8e8bea9525dc9 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -88,7 +88,7 @@ trait PrinterSupport: pprust::PpAnn { /// Produces the pretty-print annotation object. /// /// (Rust does not yet support upcasting from a trait object to - /// an object for one of its super-traits.) + /// an object for one of its supertraits.) fn pp_ann(&self) -> &dyn pprust::PpAnn; } @@ -104,7 +104,7 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { /// Produces the pretty-print annotation object. /// /// (Rust does not yet support upcasting from a trait object to - /// an object for one of its super-traits.) + /// an object for one of its supertraits.) fn pp_ann(&self) -> &dyn pprust_hir::PpAnn; } @@ -296,7 +296,7 @@ struct TypedAnnotation<'tcx> { impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> { fn sess(&self) -> &Session { - &self.tcx.sess + self.tcx.sess } fn hir_map(&self) -> Option> { @@ -347,8 +347,7 @@ impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> { fn get_source(input: &Input, sess: &Session) -> (String, FileName) { let src_name = input.source_name(); let src = String::clone( - &sess - .source_map() + sess.source_map() .get_source_file(&src_name) .expect("get_source_file") .src @@ -489,7 +488,7 @@ fn print_with_analysis( let mut out = String::new(); abort_on_err(rustc_typeck::check_crate(tcx), tcx.sess); debug!("pretty printing THIR tree"); - for did in tcx.body_owners() { + for did in tcx.hir().body_owners() { let _ = writeln!( out, "{:?}:\n{}\n", diff --git a/compiler/rustc_error_codes/src/error_codes/E0222.md b/compiler/rustc_error_codes/src/error_codes/E0222.md index fbf1b8d703314..f929f219af4aa 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0222.md +++ b/compiler/rustc_error_codes/src/error_codes/E0222.md @@ -16,9 +16,9 @@ pub trait BoxCar : Box + Vehicle {} fn dent_object(c: dyn BoxCar) {} // Invalid constraint ``` -In this example, `BoxCar` has two super-traits: `Vehicle` and `Box`. Both of +In this example, `BoxCar` has two supertraits: `Vehicle` and `Box`. Both of these traits define an associated type `Color`. `BoxCar` inherits two types -with that name from both super-traits. Because of this, we need to use the +with that name from both supertraits. Because of this, we need to use the fully qualified path syntax to refer to the appropriate `Color` associated type, either `::Color` or `::Color`, but this syntax is not allowed to be used in a function signature. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index d32593f34adef..1d6703077acff 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -633,14 +633,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn error_recursion_limit_reached(&mut self) { let expn_data = self.cx.current_expansion.id.expn_data(); - let suggested_limit = self.cx.ecfg.recursion_limit * 2; + let suggested_limit = match self.cx.ecfg.recursion_limit { + Limit(0) => Limit(2), + limit => limit * 2, + }; self.cx .struct_span_err( expn_data.call_site, &format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()), ) .help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", suggested_limit, self.cx.ecfg.crate_name, )) .emit(); diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 60d653ac8b6f9..1c0b2a9b48761 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -3,6 +3,7 @@ use rustc_ast::ptr::P; use rustc_ast::{token, Attribute, Inline, Item}; use rustc_errors::{struct_span_err, DiagnosticBuilder}; use rustc_parse::new_parser_from_file; +use rustc_parse::validate_attr; use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; @@ -168,7 +169,25 @@ fn mod_file_path_from_attr( dir_path: &Path, ) -> Option { // Extract path string from first `#[path = "path_string"]` attribute. - let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?.as_str(); + let first_path = attrs.iter().find(|at| at.has_name(sym::path))?; + let path_string = match first_path.value_str() { + Some(s) => s.as_str(), + None => { + // This check is here mainly to catch attempting to use a macro, + // such as #[path = concat!(...)]. This isn't currently supported + // because otherwise the InvocationCollector would need to defer + // loading a module until the #[path] attribute was expanded, and + // it doesn't support that (and would likely add a bit of + // complexity). Usually bad forms are checked in AstValidator (via + // `check_builtin_attribute`), but by the time that runs the macro + // is expanded, and it doesn't give an error. + validate_attr::emit_fatal_malformed_builtin_attribute( + &sess.parse_sess, + first_path, + sym::path, + ); + } + }; // On windows, the base path might have the form // `\\?\foo\bar` in which case it does not tolerate diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 52b60c3047e1c..5cb97198765fe 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -577,7 +577,7 @@ impl server::Literal for Rustc<'_> { } // Synthesize a new symbol that includes the minus sign. - let symbol = Symbol::intern(&s[..1 + lit.symbol.len()]); + let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]); lit = token::Lit::new(lit.kind, symbol, lit.suffix); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 61e27d2e4cd41..2ef0e0f6b1e56 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -295,6 +295,10 @@ declare_features! ( (accepted, const_fn_union, "1.56.0", Some(51909), None), /// Allows explicit discriminants on non-unit enum variants. (accepted, arbitrary_enum_discriminant, "1.56.0", Some(60553), None), + /// Allows macro attributes to observe output of `#[derive]`. + (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None), + /// Allows panicking during const eval (producing compile-time errors). + (accepted, const_panic, "1.57.0", Some(51999), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 2baf70197dc1a..ec2c703ad495d 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -425,9 +425,6 @@ declare_features! ( /// Allows using the `amdgpu-kernel` ABI. (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), - /// Allows panicking during const eval (producing compile-time errors). - (active, const_panic, "1.30.0", Some(51999), None), - /// Allows `#[marker]` on certain traits allowing overlapping implementations. (active, marker_trait_attr, "1.30.0", Some(29864), None), @@ -592,9 +589,6 @@ declare_features! ( /// Lessens the requirements for structs to implement `Unsize`. (active, relaxed_struct_unsize, "1.51.0", Some(81793), None), - /// Allows macro attributes to observe output of `#[derive]`. - (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None), - /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995), None), @@ -678,6 +672,11 @@ declare_features! ( /// Allows the `#[must_not_suspend]` attribute. (active, must_not_suspend, "1.57.0", Some(83310), None), + /// Allows `#[track_caller]` on closures and generators. + (active, closure_track_caller, "1.57.0", Some(87417), None), + + /// Allows `#[doc(cfg_hide(...))]`. + (active, doc_cfg_hide, "1.57.0", Some(43781), None), // ------------------------------------------------------------------------- // feature-group-end: actual feature gates diff --git a/compiler/rustc_hir/src/diagnostic_items.rs b/compiler/rustc_hir/src/diagnostic_items.rs new file mode 100644 index 0000000000000..243014b002703 --- /dev/null +++ b/compiler/rustc_hir/src/diagnostic_items.rs @@ -0,0 +1,17 @@ +use crate::def_id::DefId; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_span::Symbol; + +#[derive(Debug, Default)] +pub struct DiagnosticItems { + pub id_to_name: FxHashMap, + pub name_to_id: FxHashMap, +} + +impl HashStable for DiagnosticItems { + #[inline] + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.name_to_id.hash_stable(ctx, hasher); + } +} diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 05b652fd5af2c..fdd52bd74952f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,7 +1,7 @@ use crate::def::{CtorKind, DefKind, Res}; use crate::def_id::{DefId, CRATE_DEF_ID}; crate use crate::hir_id::{HirId, ItemLocalId}; -use crate::{itemlikevisit, LangItem}; +use crate::LangItem; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect}; @@ -10,7 +10,6 @@ pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto}; pub use rustc_ast::{CaptureBy, Movability, Mutability}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_index::vec::IndexVec; use rustc_macros::HashStable_Generic; use rustc_span::source_map::Spanned; @@ -384,6 +383,16 @@ impl GenericArgs<'_> { self.args.iter().any(|arg| matches!(arg, GenericArg::Type(_))) } + pub fn has_err(&self) -> bool { + self.args.iter().any(|arg| match arg { + GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err), + _ => false, + }) || self.bindings.iter().any(|arg| match arg.kind { + TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err), + _ => false, + }) + } + #[inline] pub fn num_type_params(&self) -> usize { self.args.iter().filter(|arg| matches!(arg, GenericArg::Type(_))).count() @@ -698,52 +707,6 @@ impl Crate<'hir> { } } -impl Crate<'_> { - /// Visits all items in the crate in some deterministic (but - /// unspecified) order. If you just need to process every item, - /// but don't care about nesting, this method is the best choice. - /// - /// If you do care about nesting -- usually because your algorithm - /// follows lexical scoping rules -- then you want a different - /// approach. You should override `visit_nested_item` in your - /// visitor and then call `intravisit::walk_crate` instead. - pub fn visit_all_item_likes<'hir, V>(&'hir self, visitor: &mut V) - where - V: itemlikevisit::ItemLikeVisitor<'hir>, - { - for owner in self.owners.iter().filter_map(Option::as_ref) { - match owner { - OwnerNode::Item(item) => visitor.visit_item(item), - OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), - OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), - OwnerNode::TraitItem(item) => visitor.visit_trait_item(item), - OwnerNode::Crate(_) => {} - } - } - } - - /// A parallel version of `visit_all_item_likes`. - pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V) - where - V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send, - { - par_for_each_in(&self.owners.raw, |owner| match owner { - Some(OwnerNode::Item(item)) => visitor.visit_item(item), - Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), - Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), - Some(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item), - Some(OwnerNode::Crate(_)) | None => {} - }) - } - - pub fn items<'hir>(&'hir self) -> impl Iterator> + 'hir { - self.owners.iter().filter_map(|owner| match owner { - Some(OwnerNode::Item(item)) => Some(*item), - _ => None, - }) - } -} - /// A block of statements `{ .. }`, which may have a label (in this case the /// `targeted_by_break` field will be `true`) and may be `unsafe` by means of /// the `rules` being anything but `DefaultBlock`. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index d69a247054026..814054c551878 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -300,7 +300,7 @@ language_item_table! { Oom, sym::oom, oom, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; - Start, sym::start, start_fn, Target::Fn, GenericRequirement::None; + Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); EhPersonality, sym::eh_personality, eh_personality, Target::Fn, GenericRequirement::None; EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None; diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index ce36648d6df11..f5ea044e24865 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -18,6 +18,7 @@ mod arena; pub mod def; pub mod def_path_hash_map; pub mod definitions; +pub mod diagnostic_items; pub use rustc_span::def_id; mod hir; pub mod hir_id; diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 422a1064874c5..9d5ef279dd784 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -33,6 +33,25 @@ impl ToStableHashKey for HirId { } } +impl ToStableHashKey for ItemLocalId { + type KeyType = ItemLocalId; + + #[inline] + fn to_stable_hash_key(&self, _: &HirCtx) -> ItemLocalId { + *self + } +} + +impl ToStableHashKey for BodyId { + type KeyType = (DefPathHash, ItemLocalId); + + #[inline] + fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) { + let BodyId { hir_id } = *self; + hir_id.to_stable_hash_key(hcx) + } +} + impl ToStableHashKey for ItemId { type KeyType = DefPathHash; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 67f92bc0a51a7..9196344cb3ffd 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -51,19 +51,6 @@ pub struct NoAnn; impl PpAnn for NoAnn {} pub const NO_ANN: &dyn PpAnn = &NoAnn; -impl PpAnn for hir::Crate<'_> { - fn nested(&self, state: &mut State<'_>, nested: Nested) { - match nested { - Nested::Item(id) => state.print_item(self.item(id)), - Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)), - Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)), - Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)), - Nested::Body(id) => state.print_expr(&self.body(id).value), - Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat), - } - } -} - /// Identical to the `PpAnn` implementation for `hir::Crate`, /// except it avoids creating a dependency on the whole crate. impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> { diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 0a558eb0555de..d42e2f7a99c8a 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -74,7 +74,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) { let mut visitor = IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] }; visitor.process_attrs(hir::CRATE_HIR_ID); - tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); + tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor()); (visitor.if_this_changed, visitor.then_this_would_need) }; diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index c190391d21180..55286384de359 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -137,9 +137,8 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { } tcx.dep_graph.with_ignore(|| { - let krate = tcx.hir().krate(); let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() }; - krate.visit_all_item_likes(&mut dirty_clean_visitor); + tcx.hir().visit_all_item_likes(&mut dirty_clean_visitor); let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] }; tcx.hir().walk_attributes(&mut all_attrs); diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 0093fa5e562af..a72a27e07bd77 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -2,9 +2,8 @@ #![feature(bench_black_box)] #![feature(extend_one)] #![feature(iter_zip)] -#![feature(unboxed_closures)] +#![feature(min_specialization)] #![feature(test)] -#![feature(fn_traits)] pub mod bit_set; pub mod vec; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 8535a7c866d96..8831524683432 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -3,9 +3,9 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; use std::fmt::Debug; use std::hash::Hash; -use std::iter::{self, FromIterator}; +use std::iter::FromIterator; use std::marker::PhantomData; -use std::ops::{Index, IndexMut, Range, RangeBounds}; +use std::ops::{Index, IndexMut, RangeBounds}; use std::slice; use std::vec; @@ -124,7 +124,9 @@ macro_rules! newtype_index { #[inline] $v const fn from_usize(value: usize) -> Self { - // FIXME: replace with `assert!(value <= ($max as usize));` once `const_panic` is stable + #[cfg(not(bootstrap))] + assert!(value <= ($max as usize)); + #[cfg(bootstrap)] [()][(value > ($max as usize)) as usize]; unsafe { Self::from_u32_unchecked(value as u32) @@ -133,7 +135,9 @@ macro_rules! newtype_index { #[inline] $v const fn from_u32(value: u32) -> Self { - // FIXME: replace with `assert!(value <= $max);` once `const_panic` is stable + #[cfg(not(bootstrap))] + assert!(value <= $max); + #[cfg(bootstrap)] [()][(value > $max) as usize]; unsafe { Self::from_u32_unchecked(value) @@ -518,8 +522,6 @@ impl fmt::Debug for IndexVec { } } -pub type Enumerated = iter::Map, IntoIdx>; - impl IndexVec { #[inline] pub fn new() -> Self { @@ -596,8 +598,10 @@ impl IndexVec { } #[inline] - pub fn into_iter_enumerated(self) -> Enumerated> { - self.raw.into_iter().enumerate().map(IntoIdx { _marker: PhantomData }) + pub fn into_iter_enumerated( + self, + ) -> impl DoubleEndedIterator + ExactSizeIterator { + self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] @@ -606,13 +610,15 @@ impl IndexVec { } #[inline] - pub fn iter_enumerated(&self) -> Enumerated> { - self.raw.iter().enumerate().map(IntoIdx { _marker: PhantomData }) + pub fn iter_enumerated( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator + '_ { + self.raw.iter().enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] - pub fn indices(&self) -> iter::Map, IntoIdx> { - (0..self.len()).map(IntoIdx { _marker: PhantomData }) + pub fn indices(&self) -> impl DoubleEndedIterator + ExactSizeIterator + 'static { + (0..self.len()).map(|n| I::new(n)) } #[inline] @@ -621,8 +627,10 @@ impl IndexVec { } #[inline] - pub fn iter_enumerated_mut(&mut self) -> Enumerated> { - self.raw.iter_mut().enumerate().map(IntoIdx { _marker: PhantomData }) + pub fn iter_enumerated_mut( + &mut self, + ) -> impl DoubleEndedIterator + ExactSizeIterator + '_ { + self.raw.iter_mut().enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] @@ -638,7 +646,7 @@ impl IndexVec { &'a mut self, range: R, ) -> impl Iterator + 'a { - self.raw.drain(range).enumerate().map(IntoIdx { _marker: PhantomData }) + self.raw.drain(range).enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] @@ -832,36 +840,5 @@ impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec { } } -pub struct IntoIdx { - _marker: PhantomData, -} -impl FnOnce<((usize, T),)> for IntoIdx { - type Output = (I, T); - - extern "rust-call" fn call_once(self, ((n, t),): ((usize, T),)) -> Self::Output { - (I::new(n), t) - } -} - -impl FnMut<((usize, T),)> for IntoIdx { - extern "rust-call" fn call_mut(&mut self, ((n, t),): ((usize, T),)) -> Self::Output { - (I::new(n), t) - } -} - -impl FnOnce<(usize,)> for IntoIdx { - type Output = I; - - extern "rust-call" fn call_once(self, (n,): (usize,)) -> Self::Output { - I::new(n) - } -} - -impl FnMut<(usize,)> for IntoIdx { - extern "rust-call" fn call_mut(&mut self, (n,): (usize,)) -> Self::Output { - I::new(n) - } -} - #[cfg(test)] mod tests; diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 11ee8fb17ad1b..cff848eeb6a0f 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -187,11 +187,11 @@ impl<'a, 'tcx> At<'a, 'tcx> { impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a <: b` where `a` may or may not be expected (if /// `a_is_expected` is true, then `a` is expected). + #[instrument(skip(self), level = "debug")] pub fn sub(self, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { - debug!("sub({:?} <: {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); @@ -204,11 +204,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a == b`; the expectation is set by the call to /// `trace()`. + #[instrument(skip(self), level = "debug")] pub fn eq(self, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { - debug!("eq({:?} == {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); @@ -219,11 +219,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { }) } + #[instrument(skip(self), level = "debug")] pub fn lub(self, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { - debug!("lub({:?} \\/ {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); @@ -234,11 +234,11 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { }) } + #[instrument(skip(self), level = "debug")] pub fn glb(self, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { - debug!("glb({:?} /\\ {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { let mut fields = at.infcx.combine_fields(trace, at.param_env); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 6a97a6c43c11e..2296cc6129ae8 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -49,6 +49,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// the same thing happens, but the resulting query is marked as ambiguous. /// - Finally, if any of the obligations result in a hard error, /// then `Err(NoSolution)` is returned. + #[instrument(skip(self, inference_vars, answer, fulfill_cx), level = "trace")] pub fn make_canonicalized_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, @@ -62,7 +63,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?; let canonical_result = self.canonicalize_response(query_response); - debug!("make_canonicalized_query_response: canonical_result = {:#?}", canonical_result); + debug!("canonical_result = {:#?}", canonical_result); Ok(self.tcx.arena.alloc(canonical_result)) } @@ -94,6 +95,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Helper for `make_canonicalized_query_response` that does /// everything up until the final canonicalization. + #[instrument(skip(self, fulfill_cx), level = "debug")] fn make_query_response( &self, inference_vars: CanonicalVarValues<'tcx>, @@ -105,13 +107,6 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { { let tcx = self.tcx; - debug!( - "make_query_response(\ - inference_vars={:?}, \ - answer={:?})", - inference_vars, answer, - ); - // Select everything, returning errors. let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new); debug!("true_errors = {:#?}", true_errors); @@ -669,8 +664,10 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> { self.obligations.push(Obligation { cause: self.cause.clone(), param_env: self.param_env, - predicate: ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(sup, sub)) - .to_predicate(self.infcx.tcx), + predicate: ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( + sup, sub, + ))) + .to_predicate(self.infcx.tcx), recursion_depth: 0, }); } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index a0ee212bed0cd..3f54247ecef21 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -22,6 +22,7 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. +use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; @@ -29,7 +30,6 @@ use super::type_variable::TypeVariableValue; use super::unify_key::replace_if_possible; use super::unify_key::{ConstVarValue, ConstVariableValue}; use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use super::{equate::Equate, type_variable::Diverging}; use super::{InferCtxt, MiscVariable, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; @@ -360,7 +360,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(b_ty.into())) + .to_predicate(self.infcx.tcx), )); } @@ -463,7 +464,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - predicate.to_predicate(self.tcx()), + ty::Binder::dummy(predicate).to_predicate(self.tcx()), )); } } @@ -645,7 +646,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { .inner .borrow_mut() .type_variables() - .new_var(self.for_universe, Diverging::NotDiverging, origin); + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); // Record that we replaced `vid` with `new_var_id` as part of a generalization @@ -885,11 +886,12 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { let origin = *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var( - self.for_universe, - Diverging::NotDiverging, - origin, - ); + let new_var_id = self + .infcx + .inner + .borrow_mut() + .type_variables() + .new_var(self.for_universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!( "ConstInferUnifier: replacing original vid={:?} with new={:?}", diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index b8089b2499b66..c44d4361f037a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -7,7 +7,7 @@ //! inference graph arose so that we can explain to the user what gave //! rise to a particular error. //! -//! The basis of the system are the "origin" types. An "origin" is the +//! The system is based around a set of "origin" types. An "origin" is the //! reason that a constraint or inference variable arose. There are //! different "origin" enums for different kinds of constraints/variables //! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has @@ -609,6 +609,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>, exp_found: Option>>, + terr: &TypeError<'tcx>, ) { match cause.code { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { @@ -785,7 +786,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.help("try adding a diverging expression, such as `return` or `panic!(..)`"); err.help("...or use `match` instead of `let...else`"); } - _ => (), + _ => { + if let ObligationCauseCode::BindingObligation(_, binding_span) = + cause.code.peel_derives() + { + if matches!(terr, TypeError::RegionsPlaceholderMismatch) { + err.span_note(*binding_span, "the lifetime requirement is introduced here"); + } + } + } } } @@ -1724,7 +1733,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // It reads better to have the error origin as the final // thing. - self.note_error_origin(diag, cause, exp_found); + self.note_error_origin(diag, cause, exp_found, terr); } pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { @@ -2524,7 +2533,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// within `?` desugaring. pub fn is_try_conversion(&self, span: Span, trait_def_id: DefId) -> bool { span.is_desugaring(DesugaringKind::QuestionMark) - && self.tcx.is_diagnostic_item(sym::from_trait, trait_def_id) + && self.tcx.is_diagnostic_item(sym::From, trait_def_id) } } diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 35ebe92c59246..773753a036326 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -94,13 +94,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// the actual types (`?T`, `Option`) -- and remember that /// after the snapshot is popped, the variable `?T` is no longer /// unified. + #[instrument(skip(self, f), level = "debug")] pub fn fudge_inference_if_ok(&self, f: F) -> Result where F: FnOnce() -> Result, T: TypeFoldable<'tcx>, { - debug!("fudge_inference_if_ok()"); - let variable_lengths = self.variable_lengths(); let (mut fudger, value) = self.probe(|_| { match f() { diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index d460222df8ad0..ae85e55da6ae3 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -9,6 +9,7 @@ use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Binder, TypeFoldable}; impl<'a, 'tcx> CombineFields<'a, 'tcx> { + #[instrument(skip(self), level = "debug")] pub fn higher_ranked_sub( &mut self, a: Binder<'tcx, T>, @@ -18,8 +19,6 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { where T: Relate<'tcx>, { - debug!("higher_ranked_sub(a={:?}, b={:?})", a, b); - // Rather than checking the subtype relationship between `a` and `b` // as-is, we need to do some extra work here in order to make sure // that function subtyping works correctly with respect to regions diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 43d3730c04931..18836d5a68e26 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -46,7 +46,7 @@ use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, Veri use self::region_constraints::{ RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, }; -use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind}; +use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; pub mod canonical; @@ -702,17 +702,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { t.fold_with(&mut self.freshener()) } - /// Returns whether `ty` is a diverging type variable or not. - /// (If `ty` is not a type variable at all, returns not diverging.) - /// - /// No attempt is made to resolve `ty`. - pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging { - match *ty.kind() { - ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid), - _ => Diverging::NotDiverging, - } - } - /// Returns the origin of the type variable identified by `vid`, or `None` /// if this is not a type variable. /// @@ -818,8 +807,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } + #[instrument(skip(self, snapshot), level = "debug")] fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { - debug!("rollback_to(cause={})", cause); let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, @@ -836,8 +825,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); } + #[instrument(skip(self, snapshot), level = "debug")] fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { - debug!("commit_from()"); let CombinedSnapshot { undo_snapshot, region_constraints_snapshot: _, @@ -852,11 +841,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Executes `f` and commit the bindings. + #[instrument(skip(self, f), level = "debug")] pub fn commit_unconditionally(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("commit_unconditionally()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); self.commit_from(snapshot); @@ -864,11 +853,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`. + #[instrument(skip(self, f), level = "debug")] pub fn commit_if_ok(&self, f: F) -> Result where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result, { - debug!("commit_if_ok()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); @@ -884,11 +873,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Execute `f` then unroll any bindings it creates. + #[instrument(skip(self, f), level = "debug")] pub fn probe(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("probe()"); let snapshot = self.start_snapshot(); let r = f(&snapshot); self.rollback_to("probe", snapshot); @@ -896,11 +885,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// If `should_skip` is true, then execute `f` then unroll any bindings it creates. + #[instrument(skip(self, f), level = "debug")] pub fn probe_maybe_skip_leak_check(&self, should_skip: bool, f: F) -> R where F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { - debug!("probe()"); let snapshot = self.start_snapshot(); let was_skip_leak_check = self.skip_leak_check.get(); if should_skip { @@ -957,18 +946,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } + #[instrument(skip(self), level = "debug")] pub fn sub_regions( &self, origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) { - debug!("sub_regions({:?} <: {:?})", a, b); self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b); } /// Require that the region `r` be equal to one of the regions in /// the set `regions`. + #[instrument(skip(self), level = "debug")] pub fn member_constraint( &self, opaque_type_def_id: DefId, @@ -977,7 +967,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { region: ty::Region<'tcx>, in_regions: &Lrc>>, ) { - debug!("member_constraint({:?} <: {:?})", region, in_regions); self.inner.borrow_mut().unwrap_region_constraints().member_constraint( opaque_type_def_id, definition_span, @@ -1071,12 +1060,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) } - pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid { - self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin) + /// Number of type variables created so far. + pub fn num_ty_vars(&self) -> usize { + self.inner.borrow_mut().type_variables().num_vars() + } + + pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid { + self.inner.borrow_mut().type_variables().new_var(self.universe(), origin) } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin)) + self.tcx.mk_ty_var(self.next_ty_var_id(origin)) } pub fn next_ty_var_in_universe( @@ -1084,18 +1078,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeVariableOrigin, universe: ty::UniverseIndex, ) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().type_variables().new_var( - universe, - Diverging::NotDiverging, - origin, - ); + let vid = self.inner.borrow_mut().type_variables().new_var(universe, origin); self.tcx.mk_ty_var(vid) } - pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin)) - } - pub fn next_const_var( &self, ty: Ty<'tcx>, @@ -1207,7 +1193,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // as the substitutions for the default, `(T, U)`. let ty_var_id = self.inner.borrow_mut().type_variables().new_var( self.universe(), - Diverging::NotDiverging, TypeVariableOrigin { kind: TypeVariableOriginKind::TypeParameterDefinition( param.name, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index e88c6608aca33..29a9cbc7a99c3 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -22,7 +22,6 @@ //! constituents) use crate::infer::combine::ConstEquateRelation; -use crate::infer::type_variable::Diverging; use crate::infer::InferCtxt; use crate::infer::{ConstVarValue, ConstVariableValue}; use rustc_data_structures::fx::FxHashMap; @@ -508,6 +507,7 @@ where true } + #[instrument(skip(self, info), level = "trace")] fn relate_with_variance>( &mut self, variance: ty::Variance, @@ -515,23 +515,22 @@ where a: T, b: T, ) -> RelateResult<'tcx, T> { - debug!("relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b); - let old_ambient_variance = self.ambient_variance; self.ambient_variance = self.ambient_variance.xform(variance); self.ambient_variance_info = self.ambient_variance_info.xform(info); - debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance); + debug!(?self.ambient_variance); let r = self.relate(a, b)?; self.ambient_variance = old_ambient_variance; - debug!("relate_with_variance: r={:?}", r); + debug!(?r); Ok(r) } + #[instrument(skip(self), level = "debug")] fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { let a = self.infcx.shallow_resolve(a); @@ -574,7 +573,7 @@ where } _ => { - debug!("tys(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance); + debug!(?a, ?b, ?self.ambient_variance); // Will also handle unification of `IntVar` and `FloatVar`. self.infcx.super_combine_tys(self, a, b) @@ -582,18 +581,19 @@ where } } + #[instrument(skip(self), level = "trace")] fn regions( &mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("regions(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance); + debug!(?self.ambient_variance); let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes); let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes); - debug!("regions: v_a = {:?}", v_a); - debug!("regions: v_b = {:?}", v_b); + debug!(?v_a); + debug!(?v_b); if self.ambient_covariance() { // Covariance: a <= b. Hence, `b: a`. @@ -629,6 +629,7 @@ where } } + #[instrument(skip(self), level = "trace")] fn binders( &mut self, a: ty::Binder<'tcx, T>, @@ -656,7 +657,7 @@ where // - Instantiate binders on `b` universally, yielding a universe U1. // - Instantiate binders on `a` existentially in U1. - debug!("binders({:?}: {:?}, ambient_variance={:?})", a, b, self.ambient_variance); + debug!(?self.ambient_variance); if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) { // Fast path for the common case. @@ -674,8 +675,8 @@ where let b_scope = self.create_scope(b, UniversallyQuantified(true)); let a_scope = self.create_scope(a, UniversallyQuantified(false)); - debug!("binders: a_scope = {:?} (existential)", a_scope); - debug!("binders: b_scope = {:?} (universal)", b_scope); + debug!(?a_scope, "(existential)"); + debug!(?b_scope, "(universal)"); self.b_scopes.push(b_scope); self.a_scopes.push(a_scope); @@ -718,8 +719,8 @@ where let a_scope = self.create_scope(a, UniversallyQuantified(true)); let b_scope = self.create_scope(b, UniversallyQuantified(false)); - debug!("binders: a_scope = {:?} (universal)", a_scope); - debug!("binders: b_scope = {:?} (existential)", b_scope); + debug!(?a_scope, "(universal)"); + debug!(?b_scope, "(existential)"); self.a_scopes.push(a_scope); self.b_scopes.push(b_scope); @@ -927,8 +928,7 @@ where // Replacing with a new variable in the universe `self.universe`, // it will be unified later with the original type variable in // the universe `_universe`. - let new_var_id = - variables.new_var(self.universe, Diverging::NotDiverging, origin); + let new_var_id = variables.new_var(self.universe, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index af31ab0923dec..df4fdb3a982ec 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -540,6 +540,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { }); } + #[instrument(skip(self, origin), level = "debug")] pub fn make_subregion( &mut self, origin: SubregionOrigin<'tcx>, @@ -547,10 +548,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { sup: Region<'tcx>, ) { // cannot add constraints once regions are resolved - debug!( - "RegionConstraintCollector: make_subregion({:?}, {:?}) due to {:?}", - sub, sup, origin - ); + debug!("origin = {:#?}", origin); match (sub, sup) { (&ReLateBound(..), _) | (_, &ReLateBound(..)) => { diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 1692d8ee526d0..8ef0d132cf09f 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -97,11 +97,11 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { self.fields.obligations.push(Obligation::new( self.fields.trace.cause.clone(), self.fields.param_env, - ty::PredicateKind::Subtype(ty::SubtypePredicate { + ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: self.a_is_expected, a, b, - }) + })) .to_predicate(self.tcx()), )); diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index f15268f6895ef..82970f214fa66 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -129,19 +129,16 @@ pub enum TypeVariableOriginKind { SubstitutionPlaceholder, AutoDeref, AdjustmentType, - DivergingFn, + + /// In type check, when we are type checking a function that + /// returns `-> dyn Foo`, we substitute a type variable for the + /// return type for diagnostic purposes. + DynReturnFn, LatticeVariable, } pub(crate) struct TypeVariableData { origin: TypeVariableOrigin, - diverging: Diverging, -} - -#[derive(Copy, Clone, Debug)] -pub enum Diverging { - NotDiverging, - Diverges, } #[derive(Copy, Clone, Debug)] @@ -191,14 +188,6 @@ impl<'tcx> TypeVariableStorage<'tcx> { } impl<'tcx> TypeVariableTable<'_, 'tcx> { - /// Returns the diverges flag given when `vid` was created. - /// - /// Note that this function does not return care whether - /// `vid` has been unified with something else or not. - pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging { - self.storage.values.get(vid.index()).diverging - } - /// Returns the origin that was given when `vid` was created. /// /// Note that this function does not return care whether @@ -260,7 +249,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { pub fn new_var( &mut self, universe: ty::UniverseIndex, - diverging: Diverging, origin: TypeVariableOrigin, ) -> ty::TyVid { let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); @@ -268,13 +256,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { let sub_key = self.sub_relations().new_key(()); assert_eq!(eq_key.vid, sub_key); - let index = self.values().push(TypeVariableData { origin, diverging }); + let index = self.values().push(TypeVariableData { origin }); assert_eq!(eq_key.vid.as_u32(), index as u32); - debug!( - "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}", - eq_key.vid, universe, diverging, origin, - ); + debug!("new_var(index={:?}, universe={:?}, origin={:?}", eq_key.vid, universe, origin,); eq_key.vid } @@ -415,6 +400,7 @@ pub(crate) struct TyVidEqKey<'tcx> { } impl<'tcx> From for TyVidEqKey<'tcx> { + #[inline] // make this function eligible for inlining - it is quite hot. fn from(vid: ty::TyVid) -> Self { TyVidEqKey { vid, phantom: PhantomData } } diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 42333dc29bc7c..dce4a87b04118 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -1,5 +1,6 @@ use crate::infer::InferCtxt; use crate::traits::Obligation; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness}; @@ -34,7 +35,7 @@ pub trait TraitEngine<'tcx>: 'tcx { cause, recursion_depth: 0, param_env, - predicate: trait_ref.without_const().to_predicate(infcx.tcx), + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(infcx.tcx), }, ); } @@ -73,6 +74,8 @@ pub trait TraitEngine<'tcx>: 'tcx { } fn pending_obligations(&self) -> Vec>; + + fn relationships(&mut self) -> &mut FxHashMap; } pub trait TraitEngineExt<'tcx> { diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 3a25cb66896d5..30d5613d5820d 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -231,6 +231,7 @@ impl Elaborator<'tcx> { None } }) + .map(ty::Binder::dummy) .map(|predicate_kind| predicate_kind.to_predicate(tcx)) .filter(|&predicate| visited.insert(predicate)) .map(|predicate| { diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 95bd2993456ab..3c7908fae79be 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -41,7 +41,7 @@ fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { fn track_diagnostic(diagnostic: &Diagnostic) { tls::with_context_opt(|icx| { if let Some(icx) = icx { - if let Some(ref diagnostics) = icx.diagnostics { + if let Some(diagnostics) = icx.diagnostics { let mut diagnostics = diagnostics.lock(); diagnostics.extend(Some(diagnostic.clone())); } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 8393826aa1285..0861bd290df77 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -65,13 +65,7 @@ impl Compiler { sess: &Session, attrs: &[ast::Attribute], ) -> OutputFilenames { - util::build_output_filenames( - &self.input, - &self.output_dir, - &self.output_file, - &attrs, - &sess, - ) + util::build_output_filenames(&self.input, &self.output_dir, &self.output_file, attrs, sess) } } diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index c7424b9e2a120..2fc3759968fd3 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,6 +1,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(internal_output_capture)] +#![feature(thread_spawn_unchecked)] #![feature(nll)] #![feature(once_cell)] #![recursion_limit = "256"] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index cb7529b527e8f..bcfa0ef3520fc 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -16,25 +16,25 @@ use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_hir::Crate; use rustc_lint::LintStore; use rustc_metadata::creader::CStore; +use rustc_metadata::{encode_metadata, EncodedMetadata}; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::middle; -use rustc_middle::middle::cstore::{MetadataLoader, MetadataLoaderDyn}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt}; use rustc_mir_build as mir_build; -use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; +use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; use rustc_passes::{self, hir_stats, layout_test}; use rustc_plugin_impl as plugin; use rustc_query_impl::{OnDiskCache, Queries as TcxQueries}; use rustc_resolve::{Resolver, ResolverArenas}; use rustc_serialize::json; use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}; +use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn}; use rustc_session::lint; use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; -use rustc_session::Session; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_session::{Limit, Session}; +use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::FileName; use rustc_trait_selection::traits; use rustc_typeck as typeck; @@ -169,7 +169,7 @@ pub fn create_resolver( ) -> BoxedResolver { tracing::trace!("create_resolver"); BoxedResolver::new(sess, move |sess, resolver_arenas| { - Resolver::new(sess, &krate, &crate_name, metadata_loader, &resolver_arenas) + Resolver::new(sess, krate, crate_name, metadata_loader, resolver_arenas) }) } @@ -179,7 +179,7 @@ pub fn register_plugins<'a>( register_lints: impl Fn(&Session, &mut LintStore), mut krate: ast::Crate, crate_name: &str, -) -> Result<(ast::Crate, Lrc)> { +) -> Result<(ast::Crate, LintStore)> { krate = sess.time("attributes_injection", || { rustc_builtin_macros::cmdline_attrs::inject( krate, @@ -201,7 +201,7 @@ pub fn register_plugins<'a>( sess.opts.cg.metadata.clone(), ); sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized"); - rustc_incremental::prepare_session_directory(sess, &crate_name, stable_crate_id)?; + rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?; if sess.opts.incremental.is_some() { sess.time("incr_comp_garbage_collect_session_directories", || { @@ -219,7 +219,7 @@ pub fn register_plugins<'a>( sess.opts.debugging_opts.no_interleave_lints, sess.unstable_options(), ); - register_lints(&sess, &mut lint_store); + register_lints(sess, &mut lint_store); let registrars = sess.time("plugin_loading", || plugin::load::load_plugins(sess, metadata_loader, &krate)); @@ -230,9 +230,6 @@ pub fn register_plugins<'a>( } }); - let lint_store = Lrc::new(lint_store); - sess.init_lint_store(lint_store.clone()); - Ok((krate, lint_store)) } @@ -240,13 +237,15 @@ fn pre_expansion_lint( sess: &Session, lint_store: &LintStore, krate: &ast::Crate, + crate_attrs: &[ast::Attribute], crate_name: &str, ) { sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| { rustc_lint::check_ast_crate( sess, lint_store, - &krate, + krate, + crate_attrs, true, None, rustc_lint::BuiltinCombinedPreExpansionLintPass::new(), @@ -266,15 +265,15 @@ pub fn configure_and_expand( resolver: &mut Resolver<'_>, ) -> Result { tracing::trace!("configure_and_expand"); - pre_expansion_lint(sess, lint_store, &krate, crate_name); + pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); krate = sess.time("crate_injection", || { let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s)); - rustc_builtin_macros::standard_library_imports::inject(krate, resolver, &sess, alt_std_name) + rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess, alt_std_name) }); - util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer()); + util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer()); // Expand all macros krate = sess.time("macro_expand_crate", || { @@ -311,10 +310,9 @@ pub fn configure_and_expand( // Create the config for macro expansion let features = sess.features_untracked(); - let recursion_limit = - rustc_middle::middle::limits::get_recursion_limit(&krate.attrs, &sess); + let recursion_limit = get_recursion_limit(&krate.attrs, sess); let cfg = rustc_expand::expand::ExpansionConfig { - features: Some(&features), + features: Some(features), recursion_limit, trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, @@ -323,12 +321,13 @@ pub fn configure_and_expand( ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; + let crate_attrs = krate.attrs.clone(); let extern_mod_loaded = |ident: Ident, attrs, items, span| { let krate = ast::Crate { attrs, items, span }; - pre_expansion_lint(sess, lint_store, &krate, &ident.name.as_str()); + pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str()); (krate.attrs, krate.items) }; - let mut ecx = ExtCtxt::new(&sess, cfg, resolver, Some(&extern_mod_loaded)); + let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded)); // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); @@ -370,7 +369,7 @@ pub fn configure_and_expand( })?; sess.time("maybe_building_test_harness", || { - rustc_builtin_macros::test_harness::inject(&sess, resolver, &mut krate) + rustc_builtin_macros::test_harness::inject(sess, resolver, &mut krate) }); if let Some(PpMode::Source(PpSourceMode::EveryBodyLoops)) = sess.opts.pretty { @@ -393,8 +392,8 @@ pub fn configure_and_expand( // start passing '--crate-type proc-macro' if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate { let mut msg = sess.diagnostic().struct_warn( - &"Trying to document proc macro crate \ - without passing '--crate-type proc-macro to rustdoc", + "Trying to document proc macro crate \ + without passing '--crate-type proc-macro to rustdoc", ); msg.warn("The generated documentation may be incorrect"); @@ -404,7 +403,7 @@ pub fn configure_and_expand( let num_crate_types = crate_types.len(); let is_test_crate = sess.opts.test; rustc_builtin_macros::proc_macro_harness::inject( - &sess, + sess, resolver, krate, is_proc_macro_crate, @@ -438,12 +437,18 @@ pub fn configure_and_expand( }); // Add all buffered lints from the `ParseSess` to the `Session`. - sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { - info!("{} parse sess buffered_lints", buffered_lints.len()); - for early_lint in buffered_lints.drain(..) { - resolver.lint_buffer().add_early_lint(early_lint); - } - }); + // The ReplaceBodyWithLoop pass may have deleted some AST nodes, potentially + // causing a delay_span_bug later if a buffered lint refers to such a deleted + // AST node (issue #87308). Since everybody_loops is for pretty-printing only, + // anyway, we simply skip all buffered lints here. + if !matches!(sess.opts.pretty, Some(PpMode::Source(PpSourceMode::EveryBodyLoops))) { + sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { + info!("{} parse sess buffered_lints", buffered_lints.len()); + for early_lint in buffered_lints.drain(..) { + resolver.lint_buffer().add_early_lint(early_lint); + } + }); + } Ok(krate) } @@ -469,6 +474,7 @@ pub fn lower_to_hir<'res, 'tcx>( sess, lint_store, &krate, + &krate.attrs, false, Some(std::mem::take(resolver.lint_buffer())), rustc_lint::BuiltinCombinedEarlyLintPass::new(), @@ -691,7 +697,7 @@ pub fn prepare_outputs( ); let output_paths = - generated_output_paths(sess, &outputs, compiler.output_file.is_some(), &crate_name); + generated_output_paths(sess, &outputs, compiler.output_file.is_some(), crate_name); // Ensure the source file isn't accidentally overwritten during compilation. if let Some(ref input_path) = compiler.input_path { @@ -832,7 +838,7 @@ pub fn create_global_ctxt<'tcx>( dep_graph, queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn), queries.as_dyn(), - &crate_name, + crate_name, outputs, ) }) @@ -886,9 +892,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { parallel!( { sess.time("match_checking", || { - tcx.par_body_owners(|def_id| { - tcx.ensure().check_match(def_id.to_def_id()); - }); + tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id.to_def_id())) }); }, { @@ -907,11 +911,11 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { }); sess.time("MIR_borrow_checking", || { - tcx.par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); + tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); }); sess.time("MIR_effect_checking", || { - for def_id in tcx.body_owners() { + for def_id in tcx.hir().body_owners() { tcx.ensure().thir_check_unsafety(def_id); if !tcx.sess.opts.debugging_opts.thir_unsafeck { rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id); @@ -977,7 +981,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { fn encode_and_write_metadata( tcx: TyCtxt<'_>, outputs: &OutputFilenames, -) -> (middle::cstore::EncodedMetadata, bool) { +) -> (EncodedMetadata, bool) { #[derive(PartialEq, Eq, PartialOrd, Ord)] enum MetadataKind { None, @@ -1000,8 +1004,8 @@ fn encode_and_write_metadata( .unwrap_or(MetadataKind::None); let metadata = match metadata_kind { - MetadataKind::None => middle::cstore::EncodedMetadata::new(), - MetadataKind::Uncompressed | MetadataKind::Compressed => tcx.encode_metadata(), + MetadataKind::None => EncodedMetadata::new(), + MetadataKind::Uncompressed | MetadataKind::Compressed => encode_metadata(tcx), }; let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata"); @@ -1020,7 +1024,7 @@ fn encode_and_write_metadata( .tempdir_in(out_filename.parent().unwrap()) .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))); let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); - let metadata_filename = emit_metadata(tcx.sess, &metadata.raw_data, &metadata_tmpdir); + let metadata_filename = emit_metadata(tcx.sess, metadata.raw_data(), &metadata_tmpdir); if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) { tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); } @@ -1070,3 +1074,24 @@ pub fn start_codegen<'tcx>( codegen } + +fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit { + if let Some(attr) = krate_attrs + .iter() + .find(|attr| attr.has_name(sym::recursion_limit) && attr.value_str().is_none()) + { + // This is here mainly to check for using a macro, such as + // #![recursion_limit = foo!()]. That is not supported since that + // would require expanding this while in the middle of expansion, + // which needs to know the limit before expanding. Otherwise, + // validation would normally be caught in AstValidator (via + // `check_builtin_attribute`), but by the time that runs the macro + // is expanded, and it doesn't give an error. + validate_attr::emit_fatal_malformed_builtin_attribute( + &sess.parse_sess, + attr, + sym::recursion_limit, + ); + } + rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess) +} diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 88cf6275ebbd0..c0316ce58d26e 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -7,7 +7,7 @@ use rustc_span::symbol::sym; fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option { let mut finder = Finder { tcx, decls: None }; - tcx.hir().krate().visit_all_item_likes(&mut finder); + tcx.hir().visit_all_item_likes(&mut finder); finder.decls.map(|id| tcx.hir().local_def_id(id)) } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 2f540395b2d79..f188ad35605af 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -110,7 +110,7 @@ impl<'tcx> Queries<'tcx> { &self.compiler.sess } fn codegen_backend(&self) -> &Lrc> { - &self.compiler.codegen_backend() + self.compiler.codegen_backend() } fn dep_graph_future(&self) -> Result<&Query>> { @@ -135,7 +135,7 @@ impl<'tcx> Queries<'tcx> { let krate = self.parse()?.take(); let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {}; - let result = passes::register_plugins( + let (krate, lint_store) = passes::register_plugins( self.session(), &*self.codegen_backend().metadata_loader(), self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), @@ -150,7 +150,7 @@ impl<'tcx> Queries<'tcx> { // called, which happens within passes::register_plugins(). self.dep_graph_future().ok(); - Ok(result) + Ok((krate, Lrc::new(lint_store))) }) } @@ -181,7 +181,7 @@ impl<'tcx> Queries<'tcx> { &crate_name, ); let krate = resolver.access(|resolver| { - passes::configure_and_expand(&sess, &lint_store, krate, &crate_name, resolver) + passes::configure_and_expand(sess, &lint_store, krate, &crate_name, resolver) })?; Ok((Rc::new(krate), Rc::new(RefCell::new(resolver)), lint_store)) }) @@ -343,7 +343,7 @@ impl Linker { let sess = &self.sess; let dep_graph = self.dep_graph; sess.time("serialize_work_products", || { - rustc_incremental::save_work_product_index(&sess, &dep_graph, work_products) + rustc_incremental::save_work_product_index(sess, &dep_graph, work_products) }); let prof = self.sess.prof.clone(); @@ -386,7 +386,7 @@ impl Compiler { F: for<'tcx> FnOnce(&'tcx Queries<'tcx>) -> T, { let mut _timer = None; - let queries = Queries::new(&self); + let queries = Queries::new(self); let ret = f(&queries); // NOTE: intentionally does not compute the global context if it hasn't been built yet, diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 3d90a6c934536..cffb087af187f 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -10,6 +10,7 @@ use rustc_errors::registry::Registry; use rustc_metadata::dynamic_lib::DynamicLibrary; #[cfg(parallel_compiler)] use rustc_middle::ty::tls; +use rustc_parse::validate_attr; #[cfg(parallel_compiler)] use rustc_query_impl::QueryCtxt; use rustc_resolve::{self, Resolver}; @@ -115,25 +116,11 @@ fn get_stack_size() -> Option { /// for `'static` bounds. #[cfg(not(parallel_compiler))] pub fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { - struct Ptr(*mut ()); - unsafe impl Send for Ptr {} - unsafe impl Sync for Ptr {} - - let mut f = Some(f); - let run = Ptr(&mut f as *mut _ as *mut ()); - let mut result = None; - let result_ptr = Ptr(&mut result as *mut _ as *mut ()); - - let thread = cfg.spawn(move || { - let _ = (&run, &result_ptr); - let run = unsafe { (*(run.0 as *mut Option)).take().unwrap() }; - let result = unsafe { &mut *(result_ptr.0 as *mut Option) }; - *result = Some(run()); - }); - - match thread.unwrap().join() { - Ok(()) => result.unwrap(), - Err(p) => panic::resume_unwind(p), + // SAFETY: join() is called immediately, so any closure captures are still + // alive. + match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { + Ok(v) => v, + Err(e) => panic::resume_unwind(e), } } @@ -415,7 +402,7 @@ pub fn get_codegen_sysroot( .iter() .chain(sysroot_candidates.iter()) .map(|sysroot| { - filesearch::make_target_lib_path(&sysroot, &target).with_file_name("codegen-backends") + filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends") }) .find(|f| { info!("codegen backend candidate: {}", f.display()); @@ -489,7 +476,7 @@ pub fn get_codegen_sysroot( } pub(crate) fn check_attr_crate_type( - _sess: &Session, + sess: &Session, attrs: &[ast::Attribute], lint_buffer: &mut LintBuffer, ) { @@ -529,6 +516,19 @@ pub(crate) fn check_attr_crate_type( ); } } + } else { + // This is here mainly to check for using a macro, such as + // #![crate_type = foo!()]. That is not supported since the + // crate type needs to be known very early in compilation long + // before expansion. Otherwise, validation would normally be + // caught in AstValidator (via `check_builtin_attribute`), but + // by the time that runs the macro is expanded, and it doesn't + // give an error. + validate_attr::emit_fatal_malformed_builtin_attribute( + &sess.parse_sess, + a, + sym::crate_type, + ); } } } @@ -619,7 +619,7 @@ pub fn build_output_filenames( .opts .crate_name .clone() - .or_else(|| rustc_attr::find_crate_name(&sess, attrs).map(|n| n.to_string())) + .or_else(|| rustc_attr::find_crate_name(sess, attrs).map(|n| n.to_string())) .unwrap_or_else(|| input.filestem().to_owned()); OutputFilenames::new( diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 1facd97375433..d147148ac7136 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { let mut diag = lint.build(&format!( "this method call resolves to `<&{} as IntoIterator>::into_iter` \ (due to backwards compatibility), \ - but will resolve to <{} as IntoIterator>::into_iter in Rust 2021.", + but will resolve to <{} as IntoIterator>::into_iter in Rust 2021", target, target, )); diag.span_suggestion( diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e1bcc3aa52bc6..57c1c8f3ecb5c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -584,8 +584,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); } - fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) { - self.check_missing_docs_attrs(cx, CRATE_DEF_ID, krate.module().inner, "the", "crate"); + fn check_crate(&mut self, cx: &LateContext<'_>) { + self.check_missing_docs_attrs( + cx, + CRATE_DEF_ID, + cx.tcx.def_span(CRATE_DEF_ID), + "the", + "crate", + ); } fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { @@ -806,7 +812,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { _ => return, } - let debug = match cx.tcx.get_diagnostic_item(sym::debug_trait) { + let debug = match cx.tcx.get_diagnostic_item(sym::Debug) { Some(debug) => debug, None => return, }; @@ -912,7 +918,7 @@ impl EarlyLintPass for AnonymousParameters { lint.build( "anonymous parameters are deprecated and will be \ - removed in the next edition.", + removed in the next edition", ) .span_suggestion( arg.pat.span, @@ -1623,9 +1629,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { let predicates = cx.tcx.predicates_of(item.def_id); for &(predicate, span) in predicates.predicates { let predicate_kind_name = match predicate.kind().skip_binder() { - Trait(..) => "Trait", + Trait(..) => "trait", TypeOutlives(..) | - RegionOutlives(..) => "Lifetime", + RegionOutlives(..) => "lifetime", // Ignore projections, as they can only be global // if the trait bound is global @@ -2472,14 +2478,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // Find calls to `mem::{uninitialized,zeroed}` methods. if let hir::ExprKind::Path(ref qpath) = path_expr.kind { let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; - - if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) { - return Some(InitKind::Zeroed); - } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) { - return Some(InitKind::Uninit); - } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) && is_zero(&args[0]) - { - return Some(InitKind::Zeroed); + match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::mem_zeroed) => return Some(InitKind::Zeroed), + Some(sym::mem_uninitialized) => return Some(InitKind::Uninit), + Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed), + _ => {} } } } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind { @@ -2491,11 +2494,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind { if let hir::ExprKind::Path(ref qpath) = path_expr.kind { let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; - - if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) { - return Some(InitKind::Zeroed); - } else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) { - return Some(InitKind::Uninit); + match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed), + Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit), + _ => {} } } } @@ -3085,8 +3087,10 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { rustc_hir::ExprKind::Call(ref path, _) => { if let rustc_hir::ExprKind::Path(ref qpath) = path.kind { if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() { - return cx.tcx.is_diagnostic_item(sym::ptr_null, def_id) - || cx.tcx.is_diagnostic_item(sym::ptr_null_mut, def_id); + return matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_null | sym::ptr_null_mut) + ); } } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 4c45e33db79c7..d235b2209444e 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -38,7 +38,6 @@ use rustc_serialize::json::Json; use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; use rustc_session::Session; -use rustc_session::SessionLintStore; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; use rustc_target::abi; @@ -75,20 +74,6 @@ pub struct LintStore { lint_groups: FxHashMap<&'static str, LintGroup>, } -impl SessionLintStore for LintStore { - fn name_to_lint(&self, lint_name: &str) -> LintId { - let lints = self - .find_lints(lint_name) - .unwrap_or_else(|_| panic!("Failed to find lint with name `{}`", lint_name)); - - if let &[lint] = lints.as_slice() { - return lint; - } else { - panic!("Found mutliple lints with name `{}`: {:?}", lint_name, lints); - } - } -} - /// The target of the `by_name` map, which accounts for renaming/deprecation. #[derive(Debug)] enum TargetLint { @@ -805,6 +790,7 @@ impl<'a> EarlyContext<'a> { sess: &'a Session, lint_store: &'a LintStore, krate: &'a ast::Crate, + crate_attrs: &'a [ast::Attribute], buffered: LintBuffer, warn_about_weird_lints: bool, ) -> EarlyContext<'a> { @@ -812,7 +798,7 @@ impl<'a> EarlyContext<'a> { sess, krate, lint_store, - builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, &krate.attrs), + builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs), buffered, } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 7a8b731da5c2e..0bba66d383869 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -329,12 +329,20 @@ fn early_lint_crate( sess: &Session, lint_store: &LintStore, krate: &ast::Crate, + crate_attrs: &[ast::Attribute], pass: T, buffered: LintBuffer, warn_about_weird_lints: bool, ) -> LintBuffer { let mut cx = EarlyContextAndPass { - context: EarlyContext::new(sess, lint_store, krate, buffered, warn_about_weird_lints), + context: EarlyContext::new( + sess, + lint_store, + krate, + crate_attrs, + buffered, + warn_about_weird_lints, + ), pass, }; @@ -355,6 +363,7 @@ pub fn check_ast_crate( sess: &Session, lint_store: &LintStore, krate: &ast::Crate, + crate_attrs: &[ast::Attribute], pre_expansion: bool, lint_buffer: Option, builtin_lints: T, @@ -365,14 +374,22 @@ pub fn check_ast_crate( let mut buffered = lint_buffer.unwrap_or_default(); if !sess.opts.debugging_opts.no_interleave_lints { - buffered = - early_lint_crate(sess, lint_store, krate, builtin_lints, buffered, pre_expansion); + buffered = early_lint_crate( + sess, + lint_store, + krate, + crate_attrs, + builtin_lints, + buffered, + pre_expansion, + ); if !passes.is_empty() { buffered = early_lint_crate( sess, lint_store, krate, + crate_attrs, EarlyLintPassObjects { lints: &mut passes[..] }, buffered, false, @@ -386,6 +403,7 @@ pub fn check_ast_crate( sess, lint_store, krate, + crate_attrs, EarlyLintPassObjects { lints: slice::from_mut(pass) }, buffered, pre_expansion && i == 0, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 8a4a70894375d..50a0d211a366a 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -33,12 +33,10 @@ impl LateLintPass<'_> for DefaultHashTypes { // don't lint imports, only actual usages return; } - let replace = if cx.tcx.is_diagnostic_item(sym::hashmap_type, def_id) { - "FxHashMap" - } else if cx.tcx.is_diagnostic_item(sym::hashset_type, def_id) { - "FxHashSet" - } else { - return; + let replace = match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::HashMap) => "FxHashMap", + Some(sym::HashSet) => "FxHashSet", + _ => return, }; cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| { let msg = format!( @@ -174,26 +172,29 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { if let TyKind::Path(qpath) = &ty.kind { if let QPath::Resolved(_, path) = qpath { match path.res { - Res::Def(_, did) => { - if cx.tcx.is_diagnostic_item(sym::Ty, did) { - return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { - return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + Res::Def(_, def_id) => { + if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) + { + return Some(format!( + "{}{}", + name, + gen_args(path.segments.last().unwrap()) + )); } } // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. Res::SelfTy(None, Some((did, _))) => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { - if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) { + if let Some(name @ (sym::Ty | sym::TyCtxt)) = + cx.tcx.get_diagnostic_name(adt.did) + { // NOTE: This path is currently unreachable as `Ty<'tcx>` is // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>` // is not actually allowed. // // I(@lcnr) still kept this branch in so we don't miss this // if we ever change it in the future. - return Some(format!("Ty<{}>", substs[0])); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) { - return Some(format!("TyCtxt<{}>", substs[0])); + return Some(format!("{}<{}>", name, substs[0])); } } } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 00c3a6fa25e02..773e5751f1370 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -430,8 +430,6 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>( fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) { let access_levels = &tcx.privacy_access_levels(()); - let krate = tcx.hir().krate(); - let context = LateContext { tcx, enclosing_body: None, @@ -450,10 +448,10 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) cx.with_lint_attrs(hir::CRATE_HIR_ID, |cx| { // since the root module isn't visited as an item (because it isn't an // item), warn for it here. - lint_callback!(cx, check_crate, krate); + lint_callback!(cx, check_crate,); tcx.hir().walk_toplevel_module(cx); tcx.hir().walk_attributes(cx); - lint_callback!(cx, check_crate_post, krate); + lint_callback!(cx, check_crate_post,); }) } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 10285272130cc..17eb00545847c 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -26,7 +26,6 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![cfg_attr(test, feature(test))] #![feature(array_windows)] #![feature(bool_to_option)] #![feature(box_patterns)] diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index 8732845af0cec..5558947de0cb7 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -84,7 +84,7 @@ fn lint_cstring_as_ptr( ) { let source_type = cx.typeck_results().expr_ty(source); if let ty::Adt(def, substs) = source_type.kind() { - if cx.tcx.is_diagnostic_item(sym::result_type, def.did) { + if cx.tcx.is_diagnostic_item(sym::Result, def.did) { if let ty::Adt(adt, _) = substs.type_at(0).kind() { if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did) { cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| { diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 301e607fc58ad..9b4ee148df48a 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -331,9 +331,9 @@ impl EarlyLintPass for NonAsciiIdents { for ((sp, ch_list), script_set) in lint_reports { cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| { let message = format!( - "The usage of Script Group `{}` in this crate consists solely of mixed script confusables", + "the usage of Script Group `{}` in this crate consists solely of mixed script confusables", script_set); - let mut note = "The usage includes ".to_string(); + let mut note = "the usage includes ".to_string(); for (idx, ch) in ch_list.into_iter().enumerate() { if idx != 0 { note += ", "; @@ -341,8 +341,7 @@ impl EarlyLintPass for NonAsciiIdents { let char_info = format!("'{}' (U+{:04X})", ch, ch as u32); note += &char_info; } - note += "."; - lint.build(&message).note(¬e).note("Please recheck to make sure their usages are indeed what you want.").emit() + lint.build(&message).note(¬e).note("please recheck to make sure their usages are indeed what you want").emit() }); } } diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index ae9c5ce5c3c2b..103555a67524f 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -54,9 +54,10 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt { || Some(def_id) == cx.tcx.lang_items().panic_str() { if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id { - if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id) - || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id) - { + if matches!( + cx.tcx.get_diagnostic_name(id), + Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro) + ) { check_panic(cx, f, arg); } } @@ -130,14 +131,14 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc ty::Ref(_, r, _) if *r.kind() == ty::Str, ) || matches!( ty.ty_adt_def(), - Some(ty_def) if cx.tcx.is_diagnostic_item(sym::string_type, ty_def.did), + Some(ty_def) if cx.tcx.is_diagnostic_item(sym::String, ty_def.did), ); let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| { - let display = is_str || cx.tcx.get_diagnostic_item(sym::display_trait).map(|t| { + let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| { infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() }) == Some(true); - let debug = !display && cx.tcx.get_diagnostic_item(sym::debug_trait).map(|t| { + let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| { infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply() }) == Some(true); (display, debug) diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 03344973bb3e6..bcddc4f3d7643 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -437,12 +437,13 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { if let hir::Node::Pat(parent_pat) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid)) { if let PatKind::Struct(_, field_pats, _) = &parent_pat.kind { - for field in field_pats.iter() { - if field.ident != ident { - // Only check if a new name has been introduced, to avoid warning - // on both the struct definition and this pattern. - self.check_snake_case(cx, "variable", &ident); - } + if field_pats + .iter() + .any(|field| !field.is_shorthand && field.pat.hir_id == p.hir_id) + { + // Only check if a new name has been introduced, to avoid warning + // on both the struct definition and this pattern. + self.check_snake_case(cx, "variable", &ident); } return; } diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index c14f16b6d11ba..d2c970468abc7 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -51,9 +51,10 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) { // Check that we're dealing with a trait method for one of the traits we care about. Some(trait_id) - if [sym::Clone, sym::Deref, sym::Borrow] - .iter() - .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) => + if matches!( + cx.tcx.get_diagnostic_name(trait_id), + Some(sym::Borrow | sym::Clone | sym::Deref) + ) => { (trait_id, did) } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 2d047ac7a0814..b1b4229b1f738 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -16,8 +16,8 @@ macro_rules! late_lint_methods { fn check_body(a: &$hir hir::Body<$hir>); fn check_body_post(a: &$hir hir::Body<$hir>); fn check_name(a: Span, b: Symbol); - fn check_crate(a: &$hir hir::Crate<$hir>); - fn check_crate_post(a: &$hir hir::Crate<$hir>); + fn check_crate(); + fn check_crate_post(); fn check_mod(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId); fn check_mod_post(a: &$hir hir::Mod<$hir>, b: Span, c: hir::HirId); fn check_foreign_item(a: &$hir hir::ForeignItem<$hir>); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index d35497c1b381a..708cd56e068b5 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1056,6 +1056,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe } + ty::RawPtr(ty::TypeAndMut { ty, .. }) + if match ty.kind() { + ty::Tuple(tuple) => tuple.is_empty(), + _ => false, + } => + { + FfiSafe + } + ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { self.check_type_for_ffi(cache, ty) } @@ -1532,8 +1541,7 @@ impl InvalidAtomicOrdering { if let ExprKind::Call(ref func, ref args) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::fence, def_id) || - cx.tcx.is_diagnostic_item(sym::compiler_fence, def_id); + if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence)); if let ExprKind::Path(ref ordering_qpath) = &args[0].kind; if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id(); if Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5830ce26fea3f..7a51e1e321a2a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1960,6 +1960,7 @@ declare_lint! { "detects proc macro derives using inaccessible names from parent modules", @future_incompatible = FutureIncompatibleInfo { reference: "issue #83583 ", + reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow, }; } @@ -3050,6 +3051,7 @@ declare_lint_pass! { BREAK_WITH_LABEL_AND_LOOP, UNUSED_ATTRIBUTES, NON_EXHAUSTIVE_OMITTED_PATTERNS, + DEREF_INTO_DYN_SUPERTRAIT, ] } @@ -3511,3 +3513,48 @@ declare_lint! { Allow, "detect when patterns of types marked `non_exhaustive` are missed", } + +declare_lint! { + /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the + /// `Deref` implementation with a `dyn SuperTrait` type as `Output`. + /// + /// These implementations will become shadowed when the `trait_upcasting` feature is stablized. + /// The `deref` functions will no longer be called implicitly, so there might be behavior change. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(deref_into_dyn_supertrait)] + /// #![allow(dead_code)] + /// + /// use core::ops::Deref; + /// + /// trait A {} + /// trait B: A {} + /// impl<'a> Deref for dyn 'a + B { + /// type Target = dyn A; + /// fn deref(&self) -> &Self::Target { + /// todo!() + /// } + /// } + /// + /// fn take_a(_: &dyn A) { } + /// + /// fn take_b(b: &dyn B) { + /// take_a(b); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The dyn upcasting coercion feature adds new coercion rules, taking priority + /// over certain other coercion rules, which will cause some behavior change. + pub DEREF_INTO_DYN_SUPERTRAIT, + Warn, + "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #89460 ", + }; +} diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 1a0cfd5888593..ddb5f7dcebfad 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1004,7 +1004,10 @@ LLVMRustOptimizeWithNewPassManager( #endif bool NeedThinLTOBufferPasses = UseThinLTOBuffers; if (!NoPrepopulatePasses) { - if (OptLevel == OptimizationLevel::O0) { + // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead. + // At the same time, the LTO pipelines do support O0 and using them is required. + bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO; + if (OptLevel == OptimizationLevel::O0 && !IsLTO) { #if LLVM_VERSION_GE(12, 0) for (const auto &C : PipelineStartEPCallbacks) PB.registerPipelineStartEPCallback(C); @@ -1569,7 +1572,11 @@ extern "C" bool LLVMRustPrepareThinLTOResolveWeak(const LLVMRustThinLTOData *Data, LLVMModuleRef M) { Module &Mod = *unwrap(M); const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(Mod.getModuleIdentifier()); +#if LLVM_VERSION_GE(14, 0) + thinLTOFinalizeInModule(Mod, DefinedGlobals, /*PropagateAttrs=*/true); +#else thinLTOResolvePrevailingInModule(Mod, DefinedGlobals); +#endif return true; } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 9850f395a0f65..97114729c0a27 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -54,7 +54,11 @@ static LLVM_THREAD_LOCAL char *LastError; // // Notably it exits the process with code 101, unlike LLVM's default of 1. static void FatalErrorHandler(void *UserData, +#if LLVM_VERSION_LT(14, 0) const std::string& Reason, +#else + const char* Reason, +#endif bool GenCrashDiag) { // Do the same thing that the default error handler does. std::cerr << "LLVM ERROR: " << Reason << std::endl; diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 2f199989d3b21..6493bd91ca27a 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -17,6 +17,10 @@ impl RustString { pub fn len(&self) -> usize { self.bytes.borrow().len() } + + pub fn is_empty(&self) -> bool { + self.bytes.borrow().is_empty() + } } /// Appending to a Rust string -- used by RawRustStringOstream. diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs index b916113a0e551..dba885a27fe22 100644 --- a/compiler/rustc_macros/src/hash_stable.rs +++ b/compiler/rustc_macros/src/hash_stable.rs @@ -116,14 +116,14 @@ pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::To s.bound_impl( quote!( ::rustc_data_structures::stable_hasher::HashStable< - ::rustc_middle::ich::StableHashingContext<'__ctx>, + ::rustc_query_system::ich::StableHashingContext<'__ctx>, > ), quote! { #[inline] fn hash_stable( &self, - __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>, + __hcx: &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { #discriminant match *self { #body } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 7ad36973f46c7..005017185c148 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -455,28 +455,28 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { // Pass on the fatal_cycle modifier if let Some(fatal_cycle) = &modifiers.fatal_cycle { - attributes.push(quote! { #fatal_cycle }); + attributes.push(quote! { (#fatal_cycle) }); }; // Pass on the storage modifier if let Some(ref ty) = modifiers.storage { let span = ty.span(); - attributes.push(quote_spanned! {span=> storage(#ty) }); + attributes.push(quote_spanned! {span=> (storage #ty) }); }; // Pass on the cycle_delay_bug modifier if let Some(cycle_delay_bug) = &modifiers.cycle_delay_bug { - attributes.push(quote! { #cycle_delay_bug }); + attributes.push(quote! { (#cycle_delay_bug) }); }; // Pass on the no_hash modifier if let Some(no_hash) = &modifiers.no_hash { - attributes.push(quote! { #no_hash }); + attributes.push(quote! { (#no_hash) }); }; // Pass on the anon modifier if let Some(anon) = &modifiers.anon { - attributes.push(quote! { #anon }); + attributes.push(quote! { (#anon) }); }; // Pass on the eval_always modifier if let Some(eval_always) = &modifiers.eval_always { - attributes.push(quote! { #eval_always }); + attributes.push(quote! { (#eval_always) }); }; // This uses the span of the query definition for the commas, diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 48d8cdf57dcfc..95b74fd5306e5 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -13,11 +13,11 @@ use rustc_expand::base::SyntaxExtension; use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_index::vec::IndexVec; -use rustc_middle::middle::cstore::{CrateDepKind, CrateSource, ExternCrate}; -use rustc_middle::middle::cstore::{ExternCrateSource, MetadataLoaderDyn}; use rustc_middle::ty::TyCtxt; use rustc_serialize::json::ToJson; use rustc_session::config::{self, CrateType, ExternLocation}; +use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate}; +use rustc_session::cstore::{ExternCrateSource, MetadataLoaderDyn}; use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; @@ -878,7 +878,7 @@ impl<'a> CrateLoader<'a> { "no global memory allocator found but one is \ required; link to std or \ add `#[global_allocator]` to a static item \ - that implements the GlobalAlloc trait.", + that implements the GlobalAlloc trait", ); } self.cstore.allocator_kind = Some(AllocatorKind::Default); diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 8c41fd9c4a237..ddc3e10fa484f 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -55,11 +55,11 @@ use crate::creader::CStore; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::CrateNum; -use rustc_middle::middle::cstore::CrateDepKind; -use rustc_middle::middle::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage}; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; +use rustc_session::cstore::CrateDepKind; +use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic}; use rustc_target::spec::PanicStrategy; crate fn calculate(tcx: TyCtxt<'_>) -> Dependencies { @@ -277,7 +277,7 @@ fn attempt_static(tcx: TyCtxt<'_>) -> Option { let all_crates_available_as_rlib = tcx .crates(()) .iter() - .cloned() + .copied() .filter_map(|cnum| { if tcx.dep_kind(cnum).macros_only() { return None; @@ -291,10 +291,11 @@ fn attempt_static(tcx: TyCtxt<'_>) -> Option { // All crates are available in an rlib format, so we're just going to link // everything in explicitly so long as it's actually required. - let last_crate = tcx.crates(()).len(); - let mut ret = (1..last_crate + 1) - .map(|cnum| { - if tcx.dep_kind(CrateNum::new(cnum)) == CrateDepKind::Explicit { + let mut ret = tcx + .crates(()) + .iter() + .map(|&cnum| { + if tcx.dep_kind(cnum) == CrateDepKind::Explicit { Linkage::Static } else { Linkage::NotLinked diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs index 3d3071c18f249..5b42f48a7d466 100644 --- a/compiler/rustc_metadata/src/foreign_modules.rs +++ b/compiler/rustc_metadata/src/foreign_modules.rs @@ -1,11 +1,11 @@ use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_middle::middle::cstore::ForeignModule; use rustc_middle::ty::TyCtxt; +use rustc_session::cstore::ForeignModule; crate fn collect(tcx: TyCtxt<'_>) -> Vec { let mut collector = Collector { modules: Vec::new() }; - tcx.hir().krate().visit_all_item_likes(&mut collector); + tcx.hir().visit_all_item_likes(&mut collector); collector.modules } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 2c9bad7e5cedb..644b849a9f899 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -30,4 +30,4 @@ pub mod creader; pub mod dynamic_lib; pub mod locator; -pub use rmeta::METADATA_HEADER; +pub use rmeta::{encode_metadata, EncodedMetadata, METADATA_HEADER}; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index b6922e0d72a06..9b1ea3b4c4cf5 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -221,8 +221,8 @@ use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; use rustc_errors::struct_span_err; -use rustc_middle::middle::cstore::{CrateSource, MetadataLoader}; use rustc_session::config::{self, CrateType}; +use rustc_session::cstore::{CrateSource, MetadataLoader}; use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch}; use rustc_session::search_paths::PathKind; use rustc_session::utils::CanonicalizedPath; @@ -740,7 +740,9 @@ fn get_metadata_section( // Header is okay -> inflate the actual metadata let compressed_bytes = &buf[header_len..]; debug!("inflating {} bytes of compressed metadata", compressed_bytes.len()); - let mut inflated = Vec::new(); + // Assume the decompressed data will be at least the size of the compressed data, so we + // don't have to grow the buffer as much. + let mut inflated = Vec::with_capacity(compressed_bytes.len()); match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) { Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()), Err(_) => { @@ -1030,7 +1032,8 @@ impl CrateError { add, ); err.help(&format!( - "please recompile that crate using this compiler ({})", + "please recompile that crate using this compiler ({}) \ + (consider running `cargo clean` first)", rustc_version(), )); let mismatches = locator.crate_rejections.via_version.iter(); diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 5ad55dbf5c80d..75b9e2ef62a88 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -3,8 +3,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::itemlikevisit::ItemLikeVisitor; -use rustc_middle::middle::cstore::{DllCallingConvention, DllImport, NativeLib}; use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; +use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib}; use rustc_session::parse::feature_err; use rustc_session::utils::NativeLibKind; use rustc_session::Session; @@ -14,7 +14,7 @@ use rustc_target::spec::abi::Abi; crate fn collect(tcx: TyCtxt<'_>) -> Vec { let mut collector = Collector { tcx, libs: Vec::new() }; - tcx.hir().krate().visit_all_item_likes(&mut collector); + tcx.hir().visit_all_item_likes(&mut collector); collector.process_command_line(); collector.libs } @@ -319,13 +319,13 @@ impl Collector<'tcx> { self.tcx.sess.err(&format!( "renaming of the library `{}` was specified, \ however this crate contains no `#[link(...)]` \ - attributes referencing this library.", + attributes referencing this library", lib.name )); } else if !renames.insert(&lib.name) { self.tcx.sess.err(&format!( "multiple renamings were \ - specified for library `{}` .", + specified for library `{}`", lib.name )); } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index eb3a9f576a735..c7d0f594f0117 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -18,11 +18,10 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; +use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::lang_items; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::{CrateSource, ExternCrate}; -use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, Body, Promoted}; @@ -30,6 +29,9 @@ use rustc_middle::thir; use rustc_middle::ty::codec::TyDecoder; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; +use rustc_session::cstore::{ + CrateSource, ExternCrate, ForeignModule, LinkagePreference, NativeLib, +}; use rustc_session::Session; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::source_map::{respan, Spanned}; @@ -1051,16 +1053,23 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over the diagnostic items in the given crate. - fn get_diagnostic_items(&self) -> FxHashMap { + fn get_diagnostic_items(&self) -> DiagnosticItems { if self.root.is_proc_macro_crate() { // Proc macro crates do not export any diagnostic-items to the target. Default::default() } else { - self.root + let mut id_to_name = FxHashMap::default(); + let name_to_id = self + .root .diagnostic_items .decode(self) - .map(|(name, def_index)| (name, self.local_def_id(def_index))) - .collect() + .map(|(name, def_index)| { + let id = self.local_def_id(def_index); + id_to_name.insert(id, name); + (name, id) + }) + .collect(); + DiagnosticItems { id_to_name, name_to_id } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 70952d388d52d..292ef03d856d9 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -1,7 +1,6 @@ use crate::creader::{CStore, LoadedMacro}; use crate::foreign_modules; use crate::native_libs; -use crate::rmeta::encoder; use rustc_ast as ast; use rustc_data_structures::stable_map::FxHashMap; @@ -9,12 +8,11 @@ use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::ForeignModule; -use rustc_middle::middle::cstore::{CrateSource, CrateStore, EncodedMetadata}; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, Visibility}; +use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule}; use rustc_session::utils::NativeLibKind; use rustc_session::{Session, StableCrateId}; use rustc_span::hygiene::{ExpnHash, ExpnId}; @@ -304,17 +302,7 @@ pub fn provide(providers: &mut Providers) { // traversal, but not globally minimal across all crates. let bfs_queue = &mut VecDeque::new(); - // Preferring shortest paths alone does not guarantee a - // deterministic result; so sort by crate num to avoid - // hashtable iteration non-determinism. This only makes - // things as deterministic as crate-nums assignment is, - // which is to say, its not deterministic in general. But - // we believe that libstd is consistently assigned crate - // num 1, so it should be enough to resolve #46112. - let mut crates: Vec = (*tcx.crates(())).to_owned(); - crates.sort(); - - for &cnum in crates.iter() { + for &cnum in tcx.crates(()) { // Ignore crates without a corresponding local `extern crate` item. if tcx.missing_extern_crate_item(cnum) { continue; @@ -323,35 +311,31 @@ pub fn provide(providers: &mut Providers) { bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX }); } - // (restrict scope of mutable-borrow of `visible_parent_map`) - { - let visible_parent_map = &mut visible_parent_map; - let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| { - if child.vis != ty::Visibility::Public { - return; - } + let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| { + if child.vis != ty::Visibility::Public { + return; + } - if let Some(child) = child.res.opt_def_id() { - match visible_parent_map.entry(child) { - Entry::Occupied(mut entry) => { - // If `child` is defined in crate `cnum`, ensure - // that it is mapped to a parent in `cnum`. - if child.is_local() && entry.get().is_local() { - entry.insert(parent); - } - } - Entry::Vacant(entry) => { + if let Some(child) = child.res.opt_def_id() { + match visible_parent_map.entry(child) { + Entry::Occupied(mut entry) => { + // If `child` is defined in crate `cnum`, ensure + // that it is mapped to a parent in `cnum`. + if child.is_local() && entry.get().is_local() { entry.insert(parent); - bfs_queue.push_back(child); } } + Entry::Vacant(entry) => { + entry.insert(parent); + bfs_queue.push_back(child); + } } - }; + } + }; - while let Some(def) = bfs_queue.pop_front() { - for child in tcx.item_children(def).iter() { - add_child(bfs_queue, child, def); - } + while let Some(def) = bfs_queue.pop_front() { + for child in tcx.item_children(def).iter() { + add_child(bfs_queue, child, def); } } @@ -525,8 +509,4 @@ impl CrateStore for CStore { fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId { self.get_crate_data(cnum).expn_hash_to_expn_id(index_guess, hash) } - - fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata { - encoder::encode_metadata(tcx) - } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a50c4549d3d3f..dacb1e4029c20 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -18,7 +18,6 @@ use rustc_hir::{AnonConst, GenericParamKind}; use rustc_index::bit_set::GrowableBitSet; use rustc_index::vec::Idx; use rustc_middle::hir::map::Map; -use rustc_middle::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportLevel, @@ -30,6 +29,7 @@ use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_serialize::{opaque, Encodable, Encoder}; use rustc_session::config::CrateType; +use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use rustc_span::{ @@ -440,8 +440,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn encode_info_for_items(&mut self) { - let krate = self.tcx.hir().krate(); - self.encode_info_for_mod(CRATE_DEF_ID, krate.module()); + self.encode_info_for_mod(CRATE_DEF_ID, self.tcx.hir().root_module()); // Proc-macro crates only export proc-macro items, which are looked // up using `proc_macro_data` @@ -449,7 +448,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return; } - krate.visit_all_item_likes(&mut self.as_deep_visitor()); + self.tcx.hir().visit_all_item_likes(&mut self.as_deep_visitor()); } fn encode_def_path_table(&mut self) { @@ -1708,9 +1707,10 @@ impl EncodeContext<'a, 'tcx> { fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> { empty_proc_macro!(self); - let crates = self.tcx.crates(()); - let mut deps = crates + let deps = self + .tcx + .crates(()) .iter() .map(|&cnum| { let dep = CrateDep { @@ -1724,8 +1724,6 @@ impl EncodeContext<'a, 'tcx> { }) .collect::>(); - deps.sort_by_key(|&(cnum, _)| cnum); - { // Sanity-check the crate numbers let mut expected_cnum = 1; @@ -1752,7 +1750,7 @@ impl EncodeContext<'a, 'tcx> { fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> { empty_proc_macro!(self); let tcx = self.tcx; - let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE); + let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id; self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) } @@ -1783,7 +1781,7 @@ impl EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_impls()"); let tcx = self.tcx; let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() }; - tcx.hir().krate().visit_all_item_likes(&mut visitor); + tcx.hir().visit_all_item_likes(&mut visitor); let mut all_impls: Vec<_> = visitor.impls.into_iter().collect(); @@ -2102,7 +2100,26 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { // will allow us to slice the metadata to the precise length that we just // generated regardless of trailing bytes that end up in it. -pub(super) fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { +#[derive(Encodable, Decodable)] +pub struct EncodedMetadata { + raw_data: Vec, +} + +impl EncodedMetadata { + #[inline] + pub fn new() -> EncodedMetadata { + EncodedMetadata { raw_data: Vec::new() } + } + + #[inline] + pub fn raw_data(&self) -> &[u8] { + &self.raw_data[..] + } +} + +pub fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata { + let _prof_timer = tcx.prof.verbose_generic_activity("generate_crate_metadata"); + // Since encoding metadata is not in a query, and nothing is cached, // there's no need to do dep-graph tracking for any of it. tcx.dep_graph.assert_ignored(); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index eb2bd80f46e64..42855e9d9d12f 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -13,13 +13,13 @@ use rustc_hir::definitions::DefKey; use rustc_hir::lang_items; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; use rustc_middle::thir; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; +use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::symbol::{Ident, Symbol}; @@ -33,6 +33,7 @@ use decoder::DecodeContext; pub use decoder::{provide, provide_extern}; crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob}; use encoder::EncodeContext; +pub use encoder::{encode_metadata, EncodedMetadata}; use rustc_span::hygiene::SyntaxContextData; mod decoder; diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index b1fcc34bee1d7..d06c593d39481 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -32,3 +32,5 @@ chalk-ir = "0.55.0" smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } rustc_session = { path = "../rustc_session" } rustc_type_ir = { path = "../rustc_type_ir" } +rand = "0.8.4" +rand_xoshiro = "0.6.0" diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 2dd43a4e8522d..962aea448b82c 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -79,8 +79,8 @@ macro_rules! arena_types { >, [few] all_traits: Vec, [few] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels, - [few] foreign_module: rustc_middle::middle::cstore::ForeignModule, - [few] foreign_modules: Vec, + [few] foreign_module: rustc_session::cstore::ForeignModule, + [few] foreign_modules: Vec, [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap, [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>, diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index e788dd4be85d7..07d42902be5dd 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -140,11 +140,11 @@ macro_rules! is_eval_always_attr { } macro_rules! contains_anon_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false}); + ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_anon_attr!($attr) | )* false}); } macro_rules! contains_eval_always_attr { - ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false}); + ($(($attr:ident $($attr_args:tt)* )),*) => ({$(is_eval_always_attr!($attr) | )* false}); } #[allow(non_upper_case_globals)] diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 35dc1631db3c2..70895f7b98e84 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -1,7 +1,7 @@ -use crate::ich::StableHashingContext; use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; +use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; #[macro_use] @@ -90,10 +90,9 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { impl<'tcx> DepContext for TyCtxt<'tcx> { type DepKind = DepKind; - type StableHashingContext = StableHashingContext<'tcx>; #[inline] - fn create_stable_hashing_context(&self) -> Self::StableHashingContext { + fn create_stable_hashing_context(&self) -> StableHashingContext<'_> { TyCtxt::create_stable_hashing_context(*self) } diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 5ecb1c9b0ffcc..efebf73224f27 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -1,7 +1,6 @@ use crate::arena::Arena; use crate::hir::map::Map; use crate::hir::{IndexedHir, OwnerNodes, ParentedNode}; -use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -12,6 +11,7 @@ use rustc_hir::definitions; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::*; use rustc_index::vec::{Idx, IndexVec}; +use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::{Span, DUMMY_SP}; diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 3707fadadac20..e6f56b0be9303 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -6,6 +6,7 @@ use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; +use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; @@ -156,6 +157,21 @@ impl<'hir> Map<'hir> { self.tcx.hir_crate(()) } + pub fn root_module(&self) -> &'hir Mod<'hir> { + match self.tcx.hir_owner(CRATE_DEF_ID).map(|o| o.node) { + Some(OwnerNode::Crate(item)) => item, + _ => bug!(), + } + } + + pub fn items(&self) -> impl Iterator> + 'hir { + let krate = self.krate(); + krate.owners.iter().filter_map(|owner| match owner.as_ref()? { + OwnerNode::Item(item) => Some(*item), + _ => None, + }) + } + pub fn def_key(&self, def_id: LocalDefId) -> DefKey { // Accessing the DefKey is ok, since it is part of DefPathHash. self.tcx.untracked_resolutions.definitions.def_key(def_id) @@ -475,6 +491,17 @@ impl<'hir> Map<'hir> { Some(ccx) } + /// Returns an iterator of the `DefId`s for all body-owners in this + /// crate. If you would prefer to iterate over the bodies + /// themselves, you can do `self.hir().krate().body_ids.iter()`. + pub fn body_owners(self) -> impl Iterator + 'hir { + self.krate().bodies.keys().map(move |&body_id| self.body_owner_def_id(body_id)) + } + + pub fn par_body_owners(self, f: F) { + par_for_each_in(&self.krate().bodies, |(&body_id, _)| f(self.body_owner_def_id(body_id))); + } + pub fn ty_param_owner(&self, id: HirId) -> HirId { match self.get(id) { Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => id, @@ -531,6 +558,45 @@ impl<'hir> Map<'hir> { } } + /// Visits all items in the crate in some deterministic (but + /// unspecified) order. If you just need to process every item, + /// but don't care about nesting, this method is the best choice. + /// + /// If you do care about nesting -- usually because your algorithm + /// follows lexical scoping rules -- then you want a different + /// approach. You should override `visit_nested_item` in your + /// visitor and then call `intravisit::walk_crate` instead. + pub fn visit_all_item_likes(&self, visitor: &mut V) + where + V: itemlikevisit::ItemLikeVisitor<'hir>, + { + let krate = self.krate(); + for owner in krate.owners.iter().filter_map(Option::as_ref) { + match owner { + OwnerNode::Item(item) => visitor.visit_item(item), + OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), + OwnerNode::ImplItem(item) => visitor.visit_impl_item(item), + OwnerNode::TraitItem(item) => visitor.visit_trait_item(item), + OwnerNode::Crate(_) => {} + } + } + } + + /// A parallel version of `visit_all_item_likes`. + pub fn par_visit_all_item_likes(&self, visitor: &V) + where + V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send, + { + let krate = self.krate(); + par_for_each_in(&krate.owners.raw, |owner| match owner.as_ref() { + Some(OwnerNode::Item(item)) => visitor.visit_item(item), + Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item), + Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item), + Some(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item), + Some(OwnerNode::Crate(_)) | None => {} + }) + } + pub fn visit_item_likes_in_module(&self, module: LocalDefId, visitor: &mut V) where V: ItemLikeVisitor<'hir>, diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index de4b75f9463c3..5016c5ce95432 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -6,7 +6,6 @@ pub mod exports; pub mod map; pub mod place; -use crate::ich::StableHashingContext; use crate::ty::query::Providers; use crate::ty::TyCtxt; use rustc_ast::Attribute; @@ -16,6 +15,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::LocalDefId; use rustc_hir::*; use rustc_index::vec::{Idx, IndexVec}; +use rustc_query_system::ich::StableHashingContext; use rustc_span::DUMMY_SP; use std::collections::BTreeMap; diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 02f0294c8ad25..e41f5add457fb 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -41,20 +41,17 @@ #![feature(once_cell)] #![feature(min_specialization)] #![feature(trusted_len)] -#![feature(test)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] #![feature(half_open_range_patterns)] -#![feature(exclusive_range_pattern)] #![feature(control_flow_enum)] #![feature(associated_type_defaults)] #![feature(iter_zip)] #![feature(thread_local_const_init)] #![feature(trusted_step)] #![feature(try_blocks)] -#![feature(try_reserve)] #![feature(try_reserve_kind)] #![feature(nonzero_ops)] #![recursion_limit = "512"] @@ -84,7 +81,6 @@ pub mod arena; #[macro_use] pub mod dep_graph; pub mod hir; -pub mod ich; pub mod infer; pub mod lint; pub mod middle; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 60cb78d902ee6..1eba2994ed36e 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -1,11 +1,11 @@ use std::cmp; -use crate::ich::StableHashingContext; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; use rustc_index::vec::IndexVec; +use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::{ builtin::{self, FORBIDDEN_LINT_GROUPS}, FutureIncompatibilityReason, Level, Lint, LintId, @@ -389,9 +389,9 @@ pub fn struct_lint_level<'s, 'd>( pub fn in_external_macro(sess: &Session, span: Span) -> bool { let expn_data = span.ctxt().outer_expn_data(); match expn_data.kind { - ExpnKind::Inlined | ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => { - false - } + ExpnKind::Inlined + | ExpnKind::Root + | ExpnKind::Desugaring(DesugaringKind::ForLoop(_) | DesugaringKind::WhileLoop) => false, ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { // Dummy span for the `def_site` means it's an external macro. diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index b370ec152e8ec..80a54071311ce 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -1,5 +1,4 @@ pub mod codegen_fn_attrs; -pub mod cstore; pub mod dependency_format; pub mod exported_symbols; pub mod lang_items; diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index a11ca74b25ee3..f33bd3438b968 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -3,7 +3,9 @@ //! which are available for use externally when compiled as a library. use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; +use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_span::def_id::LocalDefId; use std::hash::Hash; @@ -53,3 +55,12 @@ impl Default for AccessLevels { AccessLevels { map: Default::default() } } } + +impl<'a> HashStable> for AccessLevels { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + let AccessLevels { ref map } = *self; + map.hash_stable(hcx, hasher); + }); + } +} diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index e271f59da8796..605e0bc2e63ef 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -6,10 +6,10 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/borrow_check.html -use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::ty::TyCtxt; use rustc_hir as hir; use rustc_hir::Node; +use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index f0b4b6b5a0ca6..597622b2ebf90 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -15,12 +15,11 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::{self, HirId}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; -use rustc_session::lint::{BuiltinLintDiagnostics, Lint, LintBuffer}; +use rustc_session::lint::{BuiltinLintDiagnostics, Level, Lint, LintBuffer}; use rustc_session::parse::feature_err_issue; use rustc_session::{DiagnosticMessageId, Session}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{MultiSpan, Span}; - use std::num::NonZeroU32; #[derive(PartialEq, Clone, Copy, Debug)] @@ -125,7 +124,11 @@ pub fn report_unstable( /// Checks whether an item marked with `deprecated(since="X")` is currently /// deprecated (i.e., whether X is not greater than the current rustc version). -pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool { +pub fn deprecation_in_effect(depr: &Deprecation) -> bool { + let is_since_rustc_version = depr.is_since_rustc_version; + let since = depr.since.map(Symbol::as_str); + let since = since.as_deref(); + fn parse_version(ver: &str) -> Vec { // We ignore non-integer components of the version (e.g., "nightly"). ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect() @@ -175,33 +178,50 @@ pub fn deprecation_suggestion( } } -pub fn deprecation_message(depr: &Deprecation, kind: &str, path: &str) -> (String, &'static Lint) { - let since = depr.since.map(Symbol::as_str); - let (message, lint) = if deprecation_in_effect(depr.is_since_rustc_version, since.as_deref()) { - (format!("use of deprecated {} `{}`", kind, path), DEPRECATED) +fn deprecation_lint(is_in_effect: bool) -> &'static Lint { + if is_in_effect { DEPRECATED } else { DEPRECATED_IN_FUTURE } +} + +fn deprecation_message( + is_in_effect: bool, + since: Option, + note: Option, + kind: &str, + path: &str, +) -> String { + let message = if is_in_effect { + format!("use of deprecated {} `{}`", kind, path) } else { - ( - if since.as_deref() == Some("TBD") { - format!( - "use of {} `{}` that will be deprecated in a future Rust version", - kind, path - ) - } else { - format!( - "use of {} `{}` that will be deprecated in future version {}", - kind, - path, - since.unwrap() - ) - }, - DEPRECATED_IN_FUTURE, - ) + let since = since.map(Symbol::as_str); + + if since.as_deref() == Some("TBD") { + format!("use of {} `{}` that will be deprecated in a future Rust version", kind, path) + } else { + format!( + "use of {} `{}` that will be deprecated in future version {}", + kind, + path, + since.unwrap() + ) + } }; - let message = match depr.note { + + match note { Some(reason) => format!("{}: {}", message, reason), None => message, - }; - (message, lint) + } +} + +pub fn deprecation_message_and_lint( + depr: &Deprecation, + kind: &str, + path: &str, +) -> (String, &'static Lint) { + let is_in_effect = deprecation_in_effect(depr); + ( + deprecation_message(is_in_effect, depr.since, depr.note, kind, path), + deprecation_lint(is_in_effect), + ) } pub fn early_report_deprecation( @@ -303,20 +323,34 @@ impl<'tcx> TyCtxt<'tcx> { // // #[rustc_deprecated] however wants to emit down the whole // hierarchy. - if !skip || depr_entry.attr.is_since_rustc_version { - let path = &with_no_trimmed_paths(|| self.def_path_str(def_id)); - let kind = self.def_kind(def_id).descr(def_id); - let (message, lint) = deprecation_message(&depr_entry.attr, kind, path); - late_report_deprecation( - self, - &message, - depr_entry.attr.suggestion, - lint, - span, - method_span, - id, - def_id, - ); + let depr_attr = &depr_entry.attr; + if !skip || depr_attr.is_since_rustc_version { + // Calculating message for lint involves calling `self.def_path_str`. + // Which by default to calculate visible path will invoke expensive `visible_parent_map` query. + // So we skip message calculation altogether, if lint is allowed. + let is_in_effect = deprecation_in_effect(depr_attr); + let lint = deprecation_lint(is_in_effect); + if self.lint_level_at_node(lint, id).0 != Level::Allow { + let def_path = &with_no_trimmed_paths(|| self.def_path_str(def_id)); + let def_kind = self.def_kind(def_id).descr(def_id); + + late_report_deprecation( + self, + &deprecation_message( + is_in_effect, + depr_attr.since, + depr_attr.note, + def_kind, + def_path, + ), + depr_attr.suggestion, + lint, + span, + method_span, + id, + def_id, + ); + } } }; } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 3e9c02ee268ca..971556d446300 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -803,8 +803,8 @@ pub enum ImplicitSelfKind { TrivialTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } mod binding_form_impl { - use crate::ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; + use rustc_query_system::ich::StableHashingContext; impl<'a, 'tcx> HashStable> for super::BindingForm<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { @@ -2200,6 +2200,12 @@ pub enum Rvalue<'tcx> { /// that `Foo` has a destructor. These rvalues can be optimized /// away after type-checking and before lowering. Aggregate(Box>, Vec>), + + /// Transmutes a `*mut u8` into shallow-initialized `Box`. + /// + /// This is different a normal transmute because dataflow analysis will treat the box + /// as initialized but its content as uninitialized. + ShallowInitBox(Operand<'tcx>, Ty<'tcx>), } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -2450,6 +2456,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { }), } } + + ShallowInitBox(ref place, ref ty) => { + write!(fmt, "ShallowInitBox({:?}, {:?})", place, ty) + } } } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 776cf002c1703..67a20d72905f9 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,5 +1,4 @@ use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; -use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; use rustc_attr::InlineAttr; use rustc_data_structures::base_n; @@ -8,6 +7,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::{HirId, ItemId}; +use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_session::config::OptLevel; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index b003a504691bb..d5541d7890c77 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -309,6 +309,9 @@ pub struct ClosureOutlivesRequirement<'tcx> { pub category: ConstraintCategory, } +// Make sure this enum doesn't unintentionally grow +rustc_data_structures::static_assert_size!(ConstraintCategory, 12); + /// Outlives-constraints can be categorized to determine whether and why they /// are interesting (for error reporting). Order of variants indicates sort /// order of the category, thereby influencing diagnostic output. @@ -338,6 +341,11 @@ pub enum ConstraintCategory { OpaqueType, ClosureUpvar(hir::HirId), + /// A constraint from a user-written predicate + /// with the provided span, written on the item + /// with the given `DefId` + Predicate(Span), + /// A "boring" constraint (caused by the given location) is one that /// the user probably doesn't want to see described in diagnostics, /// because it is kind of an artifact of the type system setup. diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index b48e8a868efdb..c3c5ebe705eff 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -206,6 +206,7 @@ impl<'tcx> Rvalue<'tcx> { tcx.mk_generator(did, substs, movability) } }, + Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty), } } @@ -214,7 +215,9 @@ impl<'tcx> Rvalue<'tcx> { /// whether its only shallowly initialized (`Rvalue::Box`). pub fn initialization_state(&self) -> RvalueInitializationState { match *self { - Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow, + Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => { + RvalueInitializationState::Shallow + } _ => RvalueInitializationState::Deep, } } diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index b2d4a22194c62..b7201f7acf392 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -210,6 +210,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { }); Aggregate(kind, fields.fold_with(folder)) } + ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)), } } @@ -255,6 +256,10 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { } fields.visit_with(visitor) } + ShallowInitBox(ref op, ty) => { + op.visit_with(visitor)?; + ty.visit_with(visitor) + } } } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index af7f779652260..fda7ebe1a49c1 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -348,7 +348,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::VtableShim(_def_id) | ty::InstanceDef::ReifyShim(_def_id) | ty::InstanceDef::Virtual(_def_id, _) | - ty::InstanceDef::ClosureOnceShim { call_once: _def_id } | + ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | ty::InstanceDef::DropGlue(_def_id, None) => {} ty::InstanceDef::FnPtrShim(_def_id, ty) | @@ -753,6 +753,11 @@ macro_rules! make_mir_visitor { self.visit_operand(operand, location); } } + + Rvalue::ShallowInitBox(operand, ty) => { + self.visit_operand(operand, location); + self.visit_ty(ty, TyContext::Location(location)); + } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c13d7720e3754..9b0b1377875d1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -599,7 +599,7 @@ rustc_queries! { desc { "computing the inferred outlives predicates for items in this crate" } } - /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items. + /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items. query associated_item_def_ids(key: DefId) -> &'tcx [DefId] { desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) } } @@ -1442,7 +1442,7 @@ rustc_queries! { } /// Returns all diagnostic items defined in all crates. - query all_diagnostic_items(_: ()) -> FxHashMap { + query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems { storage(ArenaCacheSelector<'tcx>) eval_always desc { "calculating the diagnostic items map" } @@ -1454,7 +1454,7 @@ rustc_queries! { } /// Returns the diagnostic items defined in a crate. - query diagnostic_items(_: CrateNum) -> FxHashMap { + query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems { storage(ArenaCacheSelector<'tcx>) desc { "calculating the diagnostic items map in a crate" } } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index b0ab0c9ae52ce..cb35a4005f8c2 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -5,7 +5,6 @@ //! The providers for the queries defined here can be found in //! `rustc_traits`. -use crate::ich::StableHashingContext; use crate::infer::canonical::{Canonical, QueryResponse}; use crate::ty::error::TypeError; use crate::ty::subst::GenericArg; @@ -14,6 +13,7 @@ use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::struct_span_err; +use rustc_query_system::ich::StableHashingContext; use rustc_span::source_map::Span; use std::iter::FromIterator; use std::mem; diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 3c0fedb360827..e236c4712c883 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -120,7 +120,9 @@ pub enum SelectionCandidate<'tcx> { /// Implementation of a `Fn`-family trait by one of the anonymous /// types generated for a fn pointer type (e.g., `fn(int) -> int`) - FnPointerCandidate, + FnPointerCandidate { + is_const: bool, + }, /// Builtin implementation of `DiscriminantKind`. DiscriminantKindCandidate, diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index cb60bfa4c5408..ab47c2a7636f9 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -1,9 +1,7 @@ -use crate::ich::{self, StableHashingContext}; use crate::ty::fast_reject::SimplifiedType; use crate::ty::fold::TypeFoldable; use crate::ty::{self, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorReported; use rustc_hir::def_id::{DefId, DefIdMap}; use rustc_span::symbol::Ident; @@ -50,19 +48,19 @@ impl Graph { /// Children of a given impl, grouped into blanket/non-blanket varieties as is /// done in `TraitDef`. -#[derive(Default, TyEncodable, TyDecodable, Debug)] +#[derive(Default, TyEncodable, TyDecodable, Debug, HashStable)] pub struct Children { // Impls of a trait (or specializations of a given impl). To allow for // quicker lookup, the impls are indexed by a simplified version of their // `Self` type: impls with a simplifiable `Self` are stored in - // `nonblanket_impls` keyed by it, while all other impls are stored in + // `non_blanket_impls` keyed by it, while all other impls are stored in // `blanket_impls`. // // A similar division is used within `TraitDef`, but the lists there collect // together *all* the impls for a trait, and are populated prior to building // the specialization graph. /// Impls of the trait. - pub nonblanket_impls: FxHashMap>, + pub non_blanket_impls: FxIndexMap>, /// Blanket impls associated with the trait. pub blanket_impls: Vec, @@ -235,11 +233,3 @@ pub fn ancestors( }) } } - -impl<'a> HashStable> for Children { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let Children { ref nonblanket_impls, ref blanket_impls } = *self; - - ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls); - } -} diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index c32f0ea9ca55a..44f741c5df1a2 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -1,4 +1,3 @@ -use crate::ich::StableHashingContext; use crate::mir::interpret::ErrorHandled; use crate::ty; use crate::ty::util::{Discr, IntTypeExt}; @@ -11,6 +10,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; +use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{self, Encodable, Encoder}; use rustc_session::DataTypeKind; use rustc_span::symbol::sym; diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 8b70692960df9..434008ecb1f4f 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -1,10 +1,10 @@ -// This module contains some shared code for encoding and decoding various -// things from the `ty` module, and in particular implements support for -// "shorthands" which allow to have pointers back into the already encoded -// stream instead of re-encoding the same thing twice. -// -// The functionality in here is shared between persisting to crate metadata and -// persisting to incr. comp. caches. +//! This module contains some shared code for encoding and decoding various +//! things from the `ty` module, and in particular implements support for +//! "shorthands" which allow to have pointers back into the already encoded +//! stream instead of re-encoding the same thing twice. +//! +//! The functionality in here is shared between persisting to crate metadata and +//! persisting to incr. comp. caches. use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 72b8d7cce7142..6a6fb30dce837 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3,11 +3,9 @@ use crate::arena::Arena; use crate::dep_graph::DepGraph; use crate::hir::place::Place as HirPlace; -use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::middle; -use crate::middle::cstore::EncodedMetadata; use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault}; use crate::middle::stability; use crate::mir::interpret::{self, AllocId, Allocation, ConstValue, Scalar}; @@ -46,6 +44,7 @@ use rustc_hir::{ use rustc_index::vec::{Idx, IndexVec}; use rustc_macros::HashStable; use rustc_middle::mir::FakeReadCause; +use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames}; use rustc_session::lint::{Level, Lint}; @@ -1233,12 +1232,17 @@ impl<'tcx> TyCtxt<'tcx> { /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to /// compare against another `DefId`, since `is_diagnostic_item` is cheaper. pub fn get_diagnostic_item(self, name: Symbol) -> Option { - self.all_diagnostic_items(()).get(&name).copied() + self.all_diagnostic_items(()).name_to_id.get(&name).copied() + } + + /// Obtain the diagnostic item's name + pub fn get_diagnostic_name(self, id: DefId) -> Option { + self.diagnostic_items(id.krate).id_to_name.get(&id).copied() } /// Check whether the diagnostic item with the given `name` has the given `DefId`. pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool { - self.diagnostic_items(did.krate).get(&name) == Some(&did) + self.diagnostic_items(did.krate).name_to_id.get(&name) == Some(&did) } pub fn stability(self) -> &'tcx stability::Index<'tcx> { @@ -1324,11 +1328,6 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn encode_metadata(self) -> EncodedMetadata { - let _prof_timer = self.prof.verbose_generic_activity("generate_crate_metadata"); - self.untracked_resolutions.cstore.encode_metadata(self) - } - /// Note that this is *untracked* and should only be used within the query /// system if the result is otherwise tracked through queries pub fn cstore_untracked(self) -> &'tcx ty::CrateStoreDyn { @@ -2123,7 +2122,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally) + /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally) /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used /// to identify which traits may define a given associated type to help avoid cycle errors. /// Returns a `DefId` iterator. @@ -2707,6 +2706,29 @@ impl<'tcx> TyCtxt<'tcx> { pub fn lifetime_scope(self, id: HirId) -> Option { self.lifetime_scope_map(id.owner).and_then(|mut map| map.remove(&id.local_id)) } + + /// Whether the `def_id` counts as const fn in the current crate, considering all active + /// feature gates + pub fn is_const_fn(self, def_id: DefId) -> bool { + if self.is_const_fn_raw(def_id) { + match self.lookup_const_stability(def_id) { + Some(stability) if stability.level.is_unstable() => { + // has a `rustc_const_unstable` attribute, check whether the user enabled the + // corresponding feature gate. + self.features() + .declared_lib_features + .iter() + .any(|&(sym, _)| sym == stability.feature) + } + // functions without const stability are either stable user written + // const fn or the user is using feature gates and we thus don't + // care what they do + _ => true, + } + } else { + false + } + } } impl TyCtxtAt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 94d75a469d3d7..11ee942b83e77 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -1,7 +1,7 @@ -use crate::ich::StableHashingContext; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::DefId; +use rustc_query_system::ich::StableHashingContext; use std::fmt::Debug; use std::hash::Hash; use std::mem; diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index a04b0a7ef6136..e16491dcc90b2 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -79,6 +79,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { == Some(FoundFlags) } + #[instrument(level = "trace")] fn has_type_flags(&self, flags: TypeFlags) -> bool { self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value() == Some(FoundFlags) @@ -476,21 +477,16 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { t } + #[instrument(skip(self), level = "debug")] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { - debug!( - "RegionFolder.fold_region({:?}) skipped bound region (current index={:?})", - r, self.current_index - ); + debug!(?self.current_index, "skipped bound region"); *self.skipped_regions = true; r } _ => { - debug!( - "RegionFolder.fold_region({:?}) folding free region (current_index={:?})", - r, self.current_index - ); + debug!(?self.current_index, "folding free region"); (self.fold_region_fn)(r, self.current_index) } } @@ -1125,6 +1121,12 @@ struct HasTypeFlagsVisitor<'tcx> { flags: ty::TypeFlags, } +impl std::fmt::Debug for HasTypeFlagsVisitor<'tcx> { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.flags.fmt(fmt) + } +} + impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { type BreakTy = FoundFlags; fn tcx_for_anon_const_substs(&self) -> Option> { @@ -1132,9 +1134,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(level = "trace")] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let flags = t.flags(); - debug!("HasTypeFlagsVisitor: t={:?} flags={:?} self.flags={:?}", t, flags, self.flags); + trace!(t.flags=?t.flags()); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1146,9 +1149,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(skip(self), level = "trace")] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let flags = r.type_flags(); - debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); + trace!(r.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1157,9 +1161,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(level = "trace")] fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow { let flags = FlagComputation::for_const(c); - debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); + trace!(r.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1171,9 +1176,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(level = "trace")] fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { let flags = FlagComputation::for_unevaluated_const(uv); - debug!("HasTypeFlagsVisitor: uv={:?} uv.flags={:?} self.flags={:?}", uv, flags, self.flags); + trace!(r.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { @@ -1185,12 +1191,10 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { } #[inline] + #[instrument(level = "trace")] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { let flags = predicate.inner.flags; - debug!( - "HasTypeFlagsVisitor: predicate={:?} flags={:?} self.flags={:?}", - predicate, flags, self.flags - ); + trace!(predicate.flags=?flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { diff --git a/compiler/rustc_middle/src/ich/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs similarity index 79% rename from compiler/rustc_middle/src/ich/impls_ty.rs rename to compiler/rustc_middle/src/ty/impls_ty.rs index 3b0640eb98d93..9f47ed89f13fa 100644 --- a/compiler/rustc_middle/src/ich/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -1,13 +1,13 @@ //! This module contains `HashStable` implementations for various data types //! from `rustc_middle::ty` in no particular order. -use crate::ich::{NodeIdHashingMode, StableHashingContext}; use crate::middle::region; use crate::mir; use crate::ty; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_query_system::ich::StableHashingContext; use std::cell::RefCell; use std::mem; @@ -163,37 +163,3 @@ impl<'a> ToStableHashKey> for region::Scope { *self } } - -impl<'a> HashStable> for ty::TyVid { - fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { - // `TyVid` values are confined to an inference context and hence - // should not be hashed. - bug!("ty::TyKind::hash_stable() - can't hash a TyVid {:?}.", *self) - } -} - -impl<'a> HashStable> for ty::IntVid { - fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { - // `IntVid` values are confined to an inference context and hence - // should not be hashed. - bug!("ty::TyKind::hash_stable() - can't hash an IntVid {:?}.", *self) - } -} - -impl<'a> HashStable> for ty::FloatVid { - fn hash_stable(&self, _hcx: &mut StableHashingContext<'a>, _hasher: &mut StableHasher) { - // `FloatVid` values are confined to an inference context and hence - // should not be hashed. - bug!("ty::TyKind::hash_stable() - can't hash a FloatVid {:?}.", *self) - } -} - -impl<'a> HashStable> for crate::middle::privacy::AccessLevels { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { - let crate::middle::privacy::AccessLevels { ref map } = *self; - - map.hash_stable(hcx, hasher); - }); - } -} diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 261a19f862e02..9b8247fd0283e 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -77,7 +77,7 @@ pub enum InstanceDef<'tcx> { /// `<[FnMut closure] as FnOnce>::call_once`. /// /// The `DefId` is the ID of the `call_once` method in `FnOnce`. - ClosureOnceShim { call_once: DefId }, + ClosureOnceShim { call_once: DefId, track_caller: bool }, /// `core::ptr::drop_in_place::`. /// @@ -146,7 +146,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id } + | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) => def_id, } @@ -161,7 +161,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::FnPtrShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id } + | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } | InstanceDef::DropGlue(def_id, _) | InstanceDef::CloneShim(def_id, _) => ty::WithOptConstParam::unknown(def_id), } @@ -231,6 +231,7 @@ impl<'tcx> InstanceDef<'tcx> { | InstanceDef::Virtual(def_id, _) => { tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) } + InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller, _ => false, } } @@ -381,6 +382,8 @@ impl<'tcx> Instance<'tcx> { substs: SubstsRef<'tcx>, ) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); + // Use either `resolve_closure` or `resolve_for_vtable` + assert!(!tcx.is_closure(def_id), "Called `resolve_for_fn_ptr` on closure: {:?}", def_id); Instance::resolve(tcx, param_env, def_id, substs).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { @@ -442,10 +445,20 @@ impl<'tcx> Instance<'tcx> { }) ) { - debug!( - " => vtable fn pointer created for function with #[track_caller]" - ); - resolved.def = InstanceDef::ReifyShim(def.did); + if tcx.is_closure(def.did) { + debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", + def.did, def_id, substs); + + // Create a shim for the `FnOnce/FnMut/Fn` method we are calling + // - unlike functions, invoking a closure always goes through a + // trait. + resolved = Instance { def: InstanceDef::ReifyShim(def_id), substs }; + } else { + debug!( + " => vtable fn pointer created for function with #[track_caller]: {:?}", def.did + ); + resolved.def = InstanceDef::ReifyShim(def.did); + } } } InstanceDef::Virtual(def_id, _) => { @@ -493,7 +506,9 @@ impl<'tcx> Instance<'tcx> { .find(|it| it.kind == ty::AssocKind::Fn) .unwrap() .def_id; - let def = ty::InstanceDef::ClosureOnceShim { call_once }; + let track_caller = + tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER); + let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller }; let self_ty = tcx.mk_closure(closure_did, substs); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index cfbbec374a172..fee13fd2e2eaf 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2,7 +2,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; use crate::ty::subst::Subst; use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable}; - use rustc_ast as ast; use rustc_attr as attr; use rustc_hir as hir; @@ -24,6 +23,9 @@ use std::iter; use std::num::NonZeroUsize; use std::ops::Bound; +use rand::{seq::SliceRandom, SeedableRng}; +use rand_xoshiro::Xoshiro128StarStar; + pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers }; @@ -324,6 +326,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut inverse_memory_index: Vec = (0..fields.len() as u32).collect(); + // `ReprOptions.layout_seed` is a deterministic seed that we can use to + // randomize field ordering with + let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); + let optimize = !repr.inhibit_struct_field_reordering_opt(); if optimize { let end = @@ -332,20 +338,35 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let field_align = |f: &TyAndLayout<'_>| { if let Some(pack) = pack { f.align.abi.min(pack) } else { f.align.abi } }; - match kind { - StructKind::AlwaysSized | StructKind::MaybeUnsized => { - optimizing.sort_by_key(|&x| { - // Place ZSTs first to avoid "interesting offsets", - // especially with only one or two non-ZST fields. - let f = &fields[x as usize]; - (!f.is_zst(), cmp::Reverse(field_align(f))) - }); - } - StructKind::Prefixed(..) => { - // Sort in ascending alignment so that the layout stay optimal - // regardless of the prefix - optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); + + // If `-Z randomize-layout` was enabled for the type definition we can shuffle + // the field ordering to try and catch some code making assumptions about layouts + // we don't guarantee + if repr.can_randomize_type_layout() { + // Shuffle the ordering of the fields + optimizing.shuffle(&mut rng); + + // Otherwise we just leave things alone and actually optimize the type's fields + } else { + match kind { + StructKind::AlwaysSized | StructKind::MaybeUnsized => { + optimizing.sort_by_key(|&x| { + // Place ZSTs first to avoid "interesting offsets", + // especially with only one or two non-ZST fields. + let f = &fields[x as usize]; + (!f.is_zst(), cmp::Reverse(field_align(f))) + }); + } + + StructKind::Prefixed(..) => { + // Sort in ascending alignment so that the layout stays optimal + // regardless of the prefix + optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); + } } + + // FIXME(Kixiron): We can always shuffle fields within a given alignment class + // regardless of the status of `-Z randomize-layout` } } @@ -1805,8 +1826,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { match layout.variants { Variants::Single { index } => { - debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variants[index].ident); - if !adt_def.variants.is_empty() { + if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive { + debug!( + "print-type-size `{:#?}` variant {}", + layout, adt_def.variants[index].ident + ); let variant_def = &adt_def.variants[index]; let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect(); record( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 777c6035be831..e124f0c389475 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -20,8 +20,6 @@ pub use generics::*; pub use vtable::*; use crate::hir::exports::ExportMap; -use crate::ich::StableHashingContext; -use crate::middle::cstore::CrateStoreDyn; use crate::mir::{Body, GeneratorLayout}; use crate::traits::{self, Reveal}; use crate::ty; @@ -29,16 +27,16 @@ use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::util::Discr; use rustc_ast as ast; use rustc_attr as attr; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{self, par_iter, ParallelIterator}; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX}; use rustc_hir::Node; use rustc_macros::HashStable; +use rustc_query_system::ich::StableHashingContext; +use rustc_session::cstore::CrateStoreDyn; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; use rustc_target::abi::Align; @@ -112,6 +110,7 @@ mod context; mod diagnostics; mod erase_regions; mod generics; +mod impls_ty; mod instance; mod list; mod structural_impls; @@ -601,7 +600,7 @@ impl<'tcx> Predicate<'tcx> { // where both `'x` and `'b` would have a DB index of 1. // The substitution from the input trait-ref is therefore going to be // `'a => 'x` (where `'x` has a DB index of 1). - // - The super-trait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an + // - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an // early-bound parameter and `'b' is a late-bound parameter with a // DB index of 1. // - If we replace `'a` with `'x` from the input, it too will have @@ -769,12 +768,6 @@ pub trait ToPolyTraitRef<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; } -impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - ty::Binder::dummy(*self) - } -} - impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { self.map_bound_ref(|trait_pred| trait_pred.trait_ref) @@ -792,23 +785,6 @@ impl ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { } } -impl ToPredicate<'tcx> for PredicateKind<'tcx> { - #[inline(always)] - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - tcx.mk_predicate(Binder::dummy(self)) - } -} - -impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - PredicateKind::Trait(ty::TraitPredicate { - trait_ref: self.value, - constness: self.constness, - }) - .to_predicate(tcx) - } -} - impl<'tcx> ToPredicate<'tcx> for ConstnessAnd> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.value @@ -1514,6 +1490,9 @@ bitflags! { const IS_LINEAR = 1 << 3; // If true, don't expose any niche to type's context. const HIDE_NICHE = 1 << 4; + // If true, the type's layout can be randomized using + // the seed stored in `ReprOptions.layout_seed` + const RANDOMIZE_LAYOUT = 1 << 5; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | ReprFlags::IS_SIMD.bits | @@ -1528,6 +1507,14 @@ pub struct ReprOptions { pub align: Option, pub pack: Option, pub flags: ReprFlags, + /// The seed to be used for randomizing a type's layout + /// + /// Note: This could technically be a `[u8; 16]` (a `u128`) which would + /// be the "most accurate" hash as it'd encompass the item and crate + /// hash without loss, but it does pay the price of being larger. + /// Everything's a tradeoff, a `u64` seed should be sufficient for our + /// purposes (primarily `-Z randomize-layout`) + pub field_shuffle_seed: u64, } impl ReprOptions { @@ -1536,6 +1523,11 @@ impl ReprOptions { let mut size = None; let mut max_align: Option = None; let mut min_pack: Option = None; + + // Generate a deterministically-derived seed from the item's path hash + // to allow for cross-crate compilation to actually work + let field_shuffle_seed = tcx.def_path_hash(did).0.to_smaller_hash(); + for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(&tcx.sess, attr) { flags.insert(match r { @@ -1564,33 +1556,45 @@ impl ReprOptions { } } + // If `-Z randomize-layout` was enabled for the type definition then we can + // consider performing layout randomization + if tcx.sess.opts.debugging_opts.randomize_layout { + flags.insert(ReprFlags::RANDOMIZE_LAYOUT); + } + // This is here instead of layout because the choice must make it into metadata. if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.def_path_str(did))) { flags.insert(ReprFlags::IS_LINEAR); } - ReprOptions { int: size, align: max_align, pack: min_pack, flags } + + Self { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed } } #[inline] pub fn simd(&self) -> bool { self.flags.contains(ReprFlags::IS_SIMD) } + #[inline] pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) } + #[inline] pub fn packed(&self) -> bool { self.pack.is_some() } + #[inline] pub fn transparent(&self) -> bool { self.flags.contains(ReprFlags::IS_TRANSPARENT) } + #[inline] pub fn linear(&self) -> bool { self.flags.contains(ReprFlags::IS_LINEAR) } + #[inline] pub fn hide_niche(&self) -> bool { self.flags.contains(ReprFlags::HIDE_NICHE) @@ -1617,9 +1621,17 @@ impl ReprOptions { return true; } } + self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.int.is_some() } + /// Returns `true` if this type is valid for reordering and `-Z randomize-layout` + /// was enabled for its declaration crate + pub fn can_randomize_type_layout(&self) -> bool { + !self.inhibit_struct_field_reordering_opt() + && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT) + } + /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations. pub fn inhibit_union_abi_opt(&self) -> bool { self.c() @@ -1627,8 +1639,8 @@ impl ReprOptions { } impl<'tcx> FieldDef { - /// Returns the type of this field. The `subst` is typically obtained - /// via the second field of `TyKind::AdtDef`. + /// Returns the type of this field. The resulting type is not normalized. The `subst` is + /// typically obtained via the second field of `TyKind::AdtDef`. pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> { tcx.type_of(self.did).subst(tcx, subst) } @@ -1683,18 +1695,6 @@ impl<'tcx> TyCtxt<'tcx> { self.typeck(self.hir().body_owner_def_id(body)) } - /// Returns an iterator of the `DefId`s for all body-owners in this - /// crate. If you would prefer to iterate over the bodies - /// themselves, you can do `self.hir().krate().body_ids.iter()`. - pub fn body_owners(self) -> impl Iterator + Captures<'tcx> + 'tcx { - self.hir().krate().bodies.keys().map(move |&body_id| self.hir().body_owner_def_id(body_id)) - } - - pub fn par_body_owners(self, f: F) { - par_iter(&self.hir().krate().bodies) - .for_each(|(&body_id, _)| f(self.hir().body_owner_def_id(body_id))); - } - pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator { self.associated_items(id) .in_definition_order() @@ -2090,3 +2090,16 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> { fmt::Display::fmt(&self.name, fmt) } } + +#[derive(Debug, Default, Copy, Clone)] +pub struct FoundRelationships { + /// This is true if we identified that this Ty (`?T`) is found in a `?T: Foo` + /// obligation, where: + /// + /// * `Foo` is not `Sized` + /// * `(): Foo` may be satisfied + pub self_in_trait: bool, + /// This is true if we identified that this Ty (`?T`) is found in a `<_ as + /// _>::AssocType = ?T` + pub output: bool, +} diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 13e2122a619dc..308b4d2fefc71 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -98,14 +98,14 @@ pub trait Printer<'tcx>: Sized { // Defaults (should not be overridden): + #[instrument(skip(self), level = "debug")] fn default_print_def_path( self, def_id: DefId, substs: &'tcx [GenericArg<'tcx>], ) -> Result { - debug!("default_print_def_path: def_id={:?}, substs={:?}", def_id, substs); let key = self.tcx().def_key(def_id); - debug!("default_print_def_path: key={:?}", key); + debug!(?key); match key.disambiguated_data.data { DefPathData::CrateRoot => { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index db4a1d94d1a7c..0bf81ea01130f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,4 +1,3 @@ -use crate::middle::cstore::{ExternCrate, ExternCrateSource}; use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable}; @@ -11,6 +10,7 @@ use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; use rustc_hir::ItemKind; use rustc_session::config::TrimmedDefPaths; +use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -59,6 +59,7 @@ thread_local! { static SHOULD_PREFIX_WITH_CRATE: Cell = const { Cell::new(false) }; static NO_TRIMMED_PATH: Cell = const { Cell::new(false) }; static NO_QUERIES: Cell = const { Cell::new(false) }; + static NO_VISIBLE_PATH: Cell = const { Cell::new(false) }; } /// Avoids running any queries during any prints that occur @@ -112,6 +113,16 @@ pub fn with_no_trimmed_paths R, R>(f: F) -> R { }) } +/// Prevent selection of visible paths. `Display` impl of DefId will prefer visible (public) reexports of types as paths. +pub fn with_no_visible_paths R, R>(f: F) -> R { + NO_VISIBLE_PATH.with(|flag| { + let old = flag.replace(true); + let result = f(); + flag.set(old); + result + }) +} + /// The "region highlights" are used to control region printing during /// specific error messages. When a "region highlight" is enabled, it /// gives an alternate way to print specific regions. For now, we @@ -268,6 +279,10 @@ pub trait PrettyPrinter<'tcx>: /// from at least one local module, and returns `true`. If the crate defining `def_id` is /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`. fn try_print_visible_def_path(self, def_id: DefId) -> Result<(Self, bool), Self::Error> { + if NO_VISIBLE_PATH.with(|flag| flag.get()) { + return Ok((self, false)); + } + let mut callers = Vec::new(); self.try_print_visible_def_path_recur(def_id, &mut callers) } @@ -2018,12 +2033,11 @@ impl FmtPrinter<'_, 'tcx, F> { Ok(inner) } + #[instrument(skip(self), level = "debug")] fn prepare_late_bound_region_info(&mut self, value: &ty::Binder<'tcx, T>) where T: TypeFoldable<'tcx>, { - debug!("prepare_late_bound_region_info(value: {:?})", value); - struct LateBoundRegionNameCollector<'a, 'tcx> { tcx: TyCtxt<'tcx>, used_region_names: &'a mut FxHashSet, @@ -2037,8 +2051,9 @@ impl FmtPrinter<'_, 'tcx, F> { Some(self.tcx) } + #[instrument(skip(self), level = "trace")] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r); + trace!("address: {:p}", r); if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { self.used_region_names.insert(name); } else if let ty::RePlaceholder(ty::PlaceholderRegion { @@ -2053,8 +2068,8 @@ impl FmtPrinter<'_, 'tcx, F> { // We collect types in order to prevent really large types from compiling for // a really long time. See issue #83150 for why this is necessary. + #[instrument(skip(self), level = "trace")] fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - debug!("LateBoundRegionNameCollector::visit_ty(ty: {:?}", ty); let not_previously_inserted = self.type_collector.insert(ty); if not_previously_inserted { ty.super_visit_with(self) @@ -2156,10 +2171,26 @@ impl fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> { } } +/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only +/// the trait name. That is, it will print `Trait` instead of +/// `>`. +#[derive(Copy, Clone, TypeFoldable, Lift)] +pub struct TraitRefPrintOnlyTraitName<'tcx>(ty::TraitRef<'tcx>); + +impl fmt::Debug for TraitRefPrintOnlyTraitName<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + impl ty::TraitRef<'tcx> { pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> { TraitRefPrintOnlyTraitPath(self) } + + pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> { + TraitRefPrintOnlyTraitName(self) + } } impl ty::Binder<'tcx, ty::TraitRef<'tcx>> { @@ -2178,6 +2209,7 @@ forward_display_to_print! { ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>, ty::Binder<'tcx, ty::TraitRef<'tcx>>, ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>, ty::Binder<'tcx, ty::FnSig<'tcx>>, ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>, @@ -2240,6 +2272,10 @@ define_print_and_forward_display! { p!(print_def_path(self.0.def_id, self.0.substs)); } + TraitRefPrintOnlyTraitName<'tcx> { + p!(print_def_path(self.0.def_id, &[])); + } + ty::ParamTy { p!(write("{}", self.name)) } @@ -2325,7 +2361,7 @@ define_print_and_forward_display! { fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) { // Iterate all local crate items no matter where they are defined. let hir = tcx.hir(); - for item in hir.krate().items() { + for item in hir.items() { if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) { continue; } @@ -2393,7 +2429,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N /// /// The implementation uses similar import discovery logic to that of 'use' suggestions. fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap { - let mut map = FxHashMap::default(); + let mut map: FxHashMap = FxHashMap::default(); if let TrimmedDefPaths::GoodPath = tcx.sess.opts.trimmed_def_paths { // For good paths causing this bug, the `rustc_middle::ty::print::with_no_trimmed_paths` @@ -2431,8 +2467,29 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap { }); for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() { + use std::collections::hash_map::Entry::{Occupied, Vacant}; + if let Some(def_id) = opt_def_id { - map.insert(def_id, symbol); + match map.entry(def_id) { + Occupied(mut v) => { + // A single DefId can be known under multiple names (e.g., + // with a `pub use ... as ...;`). We need to ensure that the + // name placed in this map is chosen deterministically, so + // if we find multiple names (`symbol`) resolving to the + // same `def_id`, we prefer the lexicographically smallest + // name. + // + // Any stable ordering would be fine here though. + if *v.get() != symbol { + if v.get().as_str() > symbol.as_str() { + v.insert(symbol); + } + } + } + Vacant(v) => { + v.insert(symbol); + } + } } } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index 154b26464a804..b1bc073ca99e4 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -3,8 +3,6 @@ use crate::hir::exports::Export; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintLevelMap; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; -use crate::middle::cstore::{CrateDepKind, CrateSource}; -use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::AccessLevels; @@ -46,6 +44,8 @@ use rustc_hir::lang_items::{LangItem, LanguageItems}; use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; +use rustc_session::cstore::{CrateDepKind, CrateSource}; +use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; use rustc_session::utils::NativeLibKind; use rustc_session::Limits; use rustc_target::abi; @@ -111,11 +111,11 @@ macro_rules! query_storage { ([][$K:ty, $V:ty]) => { >::Cache }; - ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => { + ([(storage $ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => { <$ty as CacheSelector<$K, $V>>::Cache }; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { - query_storage!([$($($modifiers)*)*][$($args)*]) + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + query_storage!([$($modifiers)*][$($args)*]) }; } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 89ad99d9f0794..8f343ba9fec22 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -638,8 +638,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> { Some(ty::InstanceDef::FnPtrShim(def_id, tcx.lift(ty)?)) } ty::InstanceDef::Virtual(def_id, n) => Some(ty::InstanceDef::Virtual(def_id, n)), - ty::InstanceDef::ClosureOnceShim { call_once } => { - Some(ty::InstanceDef::ClosureOnceShim { call_once }) + ty::InstanceDef::ClosureOnceShim { call_once, track_caller } => { + Some(ty::InstanceDef::ClosureOnceShim { call_once, track_caller }) } ty::InstanceDef::DropGlue(def_id, ty) => { Some(ty::InstanceDef::DropGlue(def_id, tcx.lift(ty)?)) @@ -824,8 +824,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { Intrinsic(did) => Intrinsic(did.fold_with(folder)), FnPtrShim(did, ty) => FnPtrShim(did.fold_with(folder), ty.fold_with(folder)), Virtual(did, i) => Virtual(did.fold_with(folder), i), - ClosureOnceShim { call_once } => { - ClosureOnceShim { call_once: call_once.fold_with(folder) } + ClosureOnceShim { call_once, track_caller } => { + ClosureOnceShim { call_once: call_once.fold_with(folder), track_caller } } DropGlue(did, ty) => DropGlue(did.fold_with(folder), ty.fold_with(folder)), CloneShim(did, ty) => CloneShim(did.fold_with(folder), ty.fold_with(folder)), @@ -849,7 +849,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { did.visit_with(visitor)?; ty.visit_with(visitor) } - ClosureOnceShim { call_once } => call_once.visit_with(visitor), + ClosureOnceShim { call_once, track_caller: _ } => call_once.visit_with(visitor), } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 0fbaf81c21e40..d3094b3e6ff4d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -844,8 +844,11 @@ impl<'tcx> TraitRef<'tcx> { /// Returns a `TraitRef` of the form `P0: Foo` where `Pi` /// are the parameters defined on trait. - pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> { - TraitRef { def_id, substs: InternalSubsts::identity_for_item(tcx, def_id) } + pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> { + ty::Binder::dummy(TraitRef { + def_id, + substs: InternalSubsts::identity_for_item(tcx, def_id), + }) } #[inline] @@ -1672,6 +1675,14 @@ impl<'tcx> TyS<'tcx> { matches!(self.kind(), Infer(TyVar(_))) } + #[inline] + pub fn ty_vid(&self) -> Option { + match self.kind() { + &Infer(TyVar(vid)) => Some(vid), + _ => None, + } + } + #[inline] pub fn is_ty_infer(&self) -> bool { matches!(self.kind(), Infer(_)) diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index ae86f51e6ac3f..25a310b12db58 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,4 +1,3 @@ -use crate::ich::{self, StableHashingContext}; use crate::traits::specialization_graph; use crate::ty::fast_reject; use crate::ty::fold::TypeFoldable; @@ -7,8 +6,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::definitions::DefPathHash; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorReported; use rustc_macros::HashStable; @@ -66,11 +64,11 @@ pub enum TraitSpecializationKind { AlwaysApplicable, } -#[derive(Default, Debug)] +#[derive(Default, Debug, HashStable)] pub struct TraitImpls { blanket_impls: Vec, /// Impls indexed by their simplified self type, for fast lookup. - non_blanket_impls: FxHashMap>, + non_blanket_impls: FxIndexMap>, } impl TraitImpls { @@ -249,11 +247,3 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait impls } - -impl<'a> HashStable> for TraitImpls { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let TraitImpls { ref blanket_impls, ref non_blanket_impls } = *self; - - ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, non_blanket_impls); - } -} diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 2ec06d472fee0..2c884813d2318 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1,6 +1,5 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. -use crate::ich::NodeIdHashingMode; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::fold::TypeFolder; use crate::ty::layout::IntegerExt; @@ -18,6 +17,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; +use rustc_query_system::ich::NodeIdHashingMode; use rustc_span::DUMMY_SP; use rustc_target::abi::{Integer, Size, TargetDataLayout}; use smallvec::SmallVec; @@ -516,6 +516,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Expands the given impl trait type, stopping if the type is recursive. + #[instrument(skip(self), level = "debug")] pub fn try_expand_impl_trait_type( self, def_id: DefId, @@ -532,6 +533,7 @@ impl<'tcx> TyCtxt<'tcx> { }; let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); + trace!(?expanded_type); if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 4b40faaf1956d..1464ea58ad02c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -5,6 +5,7 @@ use rustc_index::vec::Idx; use crate::build::expr::as_place::PlaceBase; use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; +use rustc_hir::lang_items::LangItem; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind; use rustc_middle::mir::Place; @@ -88,6 +89,56 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Box { value } => { let value = &this.thir[value]; + let tcx = this.tcx; + + // `exchange_malloc` is unsafe but box is safe, so need a new scope. + let synth_scope = this.new_source_scope( + expr_span, + LintLevel::Inherited, + Some(Safety::BuiltinUnsafe), + ); + let synth_info = SourceInfo { span: expr_span, scope: synth_scope }; + + let size = this.temp(tcx.types.usize, expr_span); + this.cfg.push_assign( + block, + synth_info, + size, + Rvalue::NullaryOp(NullOp::SizeOf, value.ty), + ); + + let align = this.temp(tcx.types.usize, expr_span); + this.cfg.push_assign( + block, + synth_info, + align, + Rvalue::NullaryOp(NullOp::AlignOf, value.ty), + ); + + // malloc some memory of suitable size and align: + let exchange_malloc = Operand::function_handle( + tcx, + tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)), + ty::List::empty(), + expr_span, + ); + let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span); + let success = this.cfg.start_new_block(); + this.cfg.terminate( + block, + synth_info, + TerminatorKind::Call { + func: exchange_malloc, + args: vec![Operand::Move(size), Operand::Move(align)], + destination: Some((Place::from(storage), success)), + cleanup: None, + from_hir_call: false, + fn_span: expr_span, + }, + ); + this.diverge_from(block); + block = success; + // The `Box` temporary created here is not a part of the HIR, // and therefore is not considered during generator auto-trait // determination. See the comment about `box` at `yield_in_scope`. @@ -101,8 +152,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.schedule_drop_storage_and_value(expr_span, scope, result); } - // malloc some memory of suitable type (thus far, uninitialized): - let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); + // Transmute `*mut u8` to the box (thus far, uninitialized): + let box_ = Rvalue::ShallowInitBox(Operand::Move(Place::from(storage)), value.ty); this.cfg.push_assign(block, source_info, Place::from(result), box_); // initialize the box contents: diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 1803a18441ce2..53868f2855763 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -449,8 +449,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) .collect(); - let destination = this.cfg.start_new_block(); + if !options.contains(InlineAsmOptions::NORETURN) { + this.cfg.push_assign_unit(block, source_info, destination, this.tcx); + } + let destination_block = this.cfg.start_new_block(); this.cfg.terminate( block, source_info, @@ -462,11 +465,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: if options.contains(InlineAsmOptions::NORETURN) { None } else { - Some(destination) + Some(destination_block) }, }, ); - destination.unit() + destination_block.unit() } // These cases don't actually need a destination diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 66005be05df75..17296a95bc17e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -39,10 +39,17 @@ impl<'tcx> Cx<'tcx> { let mut expr = self.make_mirror_unadjusted(hir_expr); + let adjustment_span = match self.adjustment_span { + Some((hir_id, span)) if hir_id == hir_expr.hir_id => Some(span), + _ => None, + }; + // Now apply adjustments, if any. for adjustment in self.typeck_results.expr_adjustments(hir_expr) { debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment); - expr = self.apply_adjustment(hir_expr, expr, adjustment); + let span = expr.span; + expr = + self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span)); } // Next, wrap this up in the expr's scope. @@ -82,8 +89,9 @@ impl<'tcx> Cx<'tcx> { hir_expr: &'tcx hir::Expr<'tcx>, mut expr: Expr<'tcx>, adjustment: &Adjustment<'tcx>, + mut span: Span, ) -> Expr<'tcx> { - let Expr { temp_lifetime, mut span, .. } = expr; + let Expr { temp_lifetime, .. } = expr; // Adjust the span from the block, to the last expression of the // block. This is a better span when returning a mutable reference @@ -150,6 +158,7 @@ impl<'tcx> Cx<'tcx> { fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { let expr_ty = self.typeck_results().expr_ty(expr); + let expr_span = expr.span; let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); let kind = match expr.kind { @@ -157,7 +166,13 @@ impl<'tcx> Cx<'tcx> { hir::ExprKind::MethodCall(_, method_span, ref args, fn_span) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) let expr = self.method_callee(expr, method_span, None); + // When we apply adjustments to the receiver, use the span of + // the overall method call for better diagnostics. args[0] + // is guaranteed to exist, since a method call always has a receiver. + let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span)); + tracing::info!("Using method span: {:?}", expr.span); let args = self.mirror_exprs(args); + self.adjustment_span = old_adjustment_span; ExprKind::Call { ty: expr.ty, fun: self.thir.exprs.push(expr), diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 5059dd939d92d..38a4676bd1561 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -9,6 +9,7 @@ use rustc_ast as ast; use rustc_data_structures::steal::Steal; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::HirId; use rustc_hir::Node; use rustc_middle::middle::region; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; @@ -46,6 +47,14 @@ struct Cx<'tcx> { crate region_scope_tree: &'tcx region::ScopeTree, crate typeck_results: &'tcx ty::TypeckResults<'tcx>, + /// When applying adjustments to the expression + /// with the given `HirId`, use the given `Span`, + /// instead of the usual span. This is used to + /// assign the span of an overall method call + /// (e.g. `my_val.foo()`) to the adjustment expressions + /// for the receiver. + adjustment_span: Option<(HirId, Span)>, + /// The `DefId` of the owner of this body. body_owner: DefId, } @@ -60,6 +69,7 @@ impl<'tcx> Cx<'tcx> { region_scope_tree: tcx.region_scope_tree(def.did), typeck_results, body_owner: def.did.to_def_id(), + adjustment_span: None, } } 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 4c51b9207bb75..e28fd2c50814f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,6 +1,6 @@ +use super::deconstruct_pat::{Constructor, DeconstructedPat}; use super::usefulness::{ - compute_match_usefulness, expand_pattern, is_wildcard, MatchArm, MatchCheckCtxt, Reachability, - UsefulnessReport, + compute_match_usefulness, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport, }; use super::{PatCtxt, PatternError}; @@ -12,14 +12,12 @@ use rustc_hir::def::*; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{HirId, Pat}; -use rustc_middle::thir::PatKind; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, }; use rustc_session::Session; use rustc_span::{DesugaringKind, ExpnKind, Span}; -use std::slice; crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { let body_id = match def_id.as_local() { @@ -27,11 +25,12 @@ crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { Some(id) => tcx.hir().body_owned_by(tcx.hir().local_def_id_to_hir_id(id)), }; + let pattern_arena = TypedArena::default(); let mut visitor = MatchVisitor { tcx, typeck_results: tcx.typeck_body(body_id), param_env: tcx.param_env(def_id), - pattern_arena: TypedArena::default(), + pattern_arena: &pattern_arena, }; visitor.visit_body(tcx.hir().body(body_id)); } @@ -40,14 +39,21 @@ fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBu struct_span_err!(sess, sp, E0004, "{}", &error_message) } -struct MatchVisitor<'a, 'tcx> { +#[derive(PartialEq)] +enum RefutableFlag { + Irrefutable, + Refutable, +} +use RefutableFlag::*; + +struct MatchVisitor<'a, 'p, 'tcx> { tcx: TyCtxt<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, - pattern_arena: TypedArena>, + pattern_arena: &'p TypedArena>, } -impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { +impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> { type Map = intravisit::ErasedMap<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { @@ -74,13 +80,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None), }; self.check_irrefutable(&loc.pat, msg, sp); - self.check_patterns(&loc.pat); + self.check_patterns(&loc.pat, Irrefutable); } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { intravisit::walk_param(self, param); self.check_irrefutable(¶m.pat, "function argument", None); - self.check_patterns(¶m.pat); + self.check_patterns(¶m.pat, Irrefutable); } } @@ -113,31 +119,30 @@ impl PatCtxt<'_, '_> { } } -impl<'tcx> MatchVisitor<'_, 'tcx> { - fn check_patterns(&self, pat: &Pat<'_>) { +impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { + fn check_patterns(&self, pat: &Pat<'_>, rf: RefutableFlag) { pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); - check_for_bindings_named_same_as_variants(self, pat); + check_for_bindings_named_same_as_variants(self, pat, rf); } - fn lower_pattern<'p>( + fn lower_pattern( &self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat: &'tcx hir::Pat<'tcx>, have_errors: &mut bool, - ) -> (&'p super::Pat<'tcx>, Ty<'tcx>) { + ) -> &'p DeconstructedPat<'p, 'tcx> { let mut patcx = PatCtxt::new(self.tcx, self.param_env, self.typeck_results); patcx.include_lint_checks(); let pattern = patcx.lower_pattern(pat); - let pattern_ty = pattern.ty; - let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(pattern)); + let pattern: &_ = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern)); if !patcx.errors.is_empty() { *have_errors = true; patcx.report_inlining_errors(); } - (pattern, pattern_ty) + pattern } - fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'_, 'tcx> { + fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'p, 'tcx> { MatchCheckCtxt { tcx: self.tcx, param_env: self.param_env, @@ -147,10 +152,10 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { } fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, expr: &hir::Expr<'_>, span: Span) { - self.check_patterns(pat); + self.check_patterns(pat, Refutable); let mut cx = self.new_cx(expr.hir_id); - let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; - check_let_reachability(&mut cx, pat.hir_id, &tpat, span); + let tpat = self.lower_pattern(&mut cx, pat, &mut false); + check_let_reachability(&mut cx, pat.hir_id, tpat, span); } fn check_match( @@ -163,11 +168,11 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { for arm in arms { // Check the arm for some things unrelated to exhaustiveness. - self.check_patterns(&arm.pat); + self.check_patterns(&arm.pat, Refutable); if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard { - self.check_patterns(pat); - let tpat = self.lower_pattern(&mut cx, pat, &mut false).0; - check_let_reachability(&mut cx, pat.hir_id, &tpat, tpat.span); + self.check_patterns(pat, Refutable); + let tpat = self.lower_pattern(&mut cx, pat, &mut false); + check_let_reachability(&mut cx, pat.hir_id, tpat, tpat.span()); } } @@ -176,7 +181,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let arms: Vec<_> = arms .iter() .map(|hir::Arm { pat, guard, .. }| MatchArm { - pat: self.lower_pattern(&mut cx, pat, &mut have_errors).0, + pat: self.lower_pattern(&mut cx, pat, &mut have_errors), hir_id: pat.hir_id, has_guard: guard.is_some(), }) @@ -190,20 +195,16 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut); let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty); - report_arm_reachability(&cx, &report, |_, arm_span, arm_hir_id, catchall| { - match source { - hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - unreachable_pattern(cx.tcx, arm_span, arm_hir_id, catchall); - } - // 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 => {} + match source { + hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { + 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 => {} + } // Check if the match is exhaustive. - // Note: An empty match isn't the same as an empty matrix for diagnostics purposes, - // since an empty matrix can occur when there are arms, if those arms all have guards. let is_empty_match = arms.is_empty(); let witnesses = report.non_exhaustiveness_witnesses; if !witnesses.is_empty() { @@ -214,7 +215,8 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option) { let mut cx = self.new_cx(pat.hir_id); - let (pattern, pattern_ty) = self.lower_pattern(&mut cx, pat, &mut false); + let pattern = self.lower_pattern(&mut cx, pat, &mut false); + let pattern_ty = pattern.ty(); let arms = vec![MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }]; let report = compute_match_usefulness(&cx, &arms, pat.hir_id, pattern_ty); @@ -226,7 +228,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { return; } - let joined_patterns = joined_uncovered_patterns(&witnesses); + let joined_patterns = joined_uncovered_patterns(&cx, &witnesses); let mut err = struct_span_err!( self.tcx.sess, pat.span, @@ -302,7 +304,11 @@ fn const_not_var( } } -fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) { +fn check_for_bindings_named_same_as_variants( + cx: &MatchVisitor<'_, '_, '_>, + pat: &Pat<'_>, + rf: RefutableFlag, +) { pat.walk_always(|p| { if let hir::PatKind::Binding(_, _, ident, None) = p.kind { if let Some(ty::BindByValue(hir::Mutability::Not)) = @@ -315,25 +321,31 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa variant.ident == ident && variant.ctor_kind == CtorKind::Const }) { + let variant_count = edef.variants.len(); cx.tcx.struct_span_lint_hir( BINDINGS_WITH_VARIANT_NAME, p.hir_id, p.span, |lint| { let ty_path = cx.tcx.def_path_str(edef.did); - lint.build(&format!( + let mut err = lint.build(&format!( "pattern binding `{}` is named the same as one \ - of the variants of the type `{}`", + of the variants of the type `{}`", ident, ty_path - )) - .code(error_code!(E0170)) - .span_suggestion( - p.span, - "to match on the variant, qualify the path", - format!("{}::{}", ty_path, ident), - Applicability::MachineApplicable, - ) - .emit(); + )); + err.code(error_code!(E0170)); + // If this is an irrefutable pattern, and there's > 1 variant, + // then we can't actually match on this. Applying the below + // suggestion would produce code that breaks on `check_irrefutable`. + if rf == Refutable || variant_count == 1 { + err.span_suggestion( + p.span, + "to match on the variant, qualify the path", + format!("{}::{}", ty_path, ident), + Applicability::MachineApplicable, + ); + } + err.emit(); }, ) } @@ -344,12 +356,11 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa } /// Checks for common cases of "catchall" patterns that may not be intended as such. -fn pat_is_catchall(pat: &super::Pat<'_>) -> bool { - use PatKind::*; - match &*pat.kind { - Binding { subpattern: None, .. } => true, - Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s), - Leaf { subpatterns: s } => s.iter().all(|p| pat_is_catchall(&p.pattern)), +fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { + use Constructor::*; + match pat.ctor() { + Wildcard => true, + Single => pat.iter_fields().all(|pat| pat_is_catchall(pat)), _ => false, } } @@ -428,29 +439,16 @@ fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) { fn check_let_reachability<'p, 'tcx>( cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId, - pat: &'p super::Pat<'tcx>, + pat: &'p DeconstructedPat<'p, 'tcx>, span: Span, ) { let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }]; - let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty); - - report_arm_reachability(&cx, &report, |arm_index, arm_span, arm_hir_id, _| { - match let_source(cx.tcx, pat_id) { - LetSource::IfLet | LetSource::WhileLet => { - match arm_index { - // The arm with the user-specified pattern. - 0 => unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None), - // The arm with the wildcard pattern. - 1 => irrefutable_let_pattern(cx.tcx, pat_id, arm_span), - _ => bug!(), - } - } - LetSource::IfLetGuard if arm_index == 0 => { - unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None); - } - _ => {} - } - }); + let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty()); + + // Report if the pattern is unreachable, which can only occur when the type is uninhabited. + // This also reports unreachable sub-patterns though, so we can't just replace it with an + // `is_uninhabited` check. + report_arm_reachability(&cx, &report); if report.non_exhaustiveness_witnesses.is_empty() { // The match is exhaustive, i.e. the `if let` pattern is irrefutable. @@ -459,18 +457,15 @@ fn check_let_reachability<'p, 'tcx>( } /// Report unreachable arms, if any. -fn report_arm_reachability<'p, 'tcx, F>( +fn report_arm_reachability<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, report: &UsefulnessReport<'p, 'tcx>, - unreachable: F, -) where - F: Fn(usize, Span, HirId, Option), -{ +) { use Reachability::*; let mut catchall = None; - for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() { + for (arm, is_useful) in report.arm_usefulness.iter() { match is_useful { - Unreachable => unreachable(arm_index, arm.pat.span, arm.hir_id, catchall), + Unreachable => unreachable_pattern(cx.tcx, arm.pat.span(), arm.hir_id, catchall), Reachable(unreachables) if unreachables.is_empty() => {} // The arm is reachable, but contains unreachable subpatterns (from or-patterns). Reachable(unreachables) => { @@ -483,7 +478,7 @@ fn report_arm_reachability<'p, 'tcx, F>( } } if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) { - catchall = Some(arm.pat.span); + catchall = Some(arm.pat.span()); } } } @@ -493,7 +488,7 @@ fn non_exhaustive_match<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, scrut_ty: Ty<'tcx>, sp: Span, - witnesses: Vec>, + witnesses: Vec>, is_empty_match: bool, ) { let non_empty_enum = match scrut_ty.kind() { @@ -510,7 +505,7 @@ fn non_exhaustive_match<'p, 'tcx>( format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty), ); } else { - let joined_patterns = joined_uncovered_patterns(&witnesses); + let joined_patterns = joined_uncovered_patterns(cx, &witnesses); err = create_e0004( cx.tcx.sess, sp, @@ -537,7 +532,7 @@ fn non_exhaustive_match<'p, 'tcx>( if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize) && !is_empty_match && witnesses.len() == 1 - && is_wildcard(&witnesses[0]) + && matches!(witnesses[0].ctor(), Constructor::NonExhaustive) { err.note(&format!( "`{}` does not have a fixed maximum value, \ @@ -560,33 +555,40 @@ fn non_exhaustive_match<'p, 'tcx>( err.emit(); } -crate fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String { +crate fn joined_uncovered_patterns<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, + witnesses: &[DeconstructedPat<'p, 'tcx>], +) -> String { const LIMIT: usize = 3; + let pat_to_str = |pat: &DeconstructedPat<'p, 'tcx>| pat.to_pat(cx).to_string(); match witnesses { [] => bug!(), - [witness] => format!("`{}`", witness), + [witness] => format!("`{}`", witness.to_pat(cx)), [head @ .., tail] if head.len() < LIMIT => { - let head: Vec<_> = head.iter().map(<_>::to_string).collect(); - format!("`{}` and `{}`", head.join("`, `"), tail) + let head: Vec<_> = head.iter().map(pat_to_str).collect(); + format!("`{}` and `{}`", head.join("`, `"), tail.to_pat(cx)) } _ => { let (head, tail) = witnesses.split_at(LIMIT); - let head: Vec<_> = head.iter().map(<_>::to_string).collect(); + let head: Vec<_> = head.iter().map(pat_to_str).collect(); format!("`{}` and {} more", head.join("`, `"), tail.len()) } } } -crate fn pattern_not_covered_label(witnesses: &[super::Pat<'_>], joined_patterns: &str) -> String { +crate fn pattern_not_covered_label( + witnesses: &[DeconstructedPat<'_, '_>], + joined_patterns: &str, +) -> String { format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns) } /// Point at the definition of non-covered `enum` variants. -fn adt_defined_here( - cx: &MatchCheckCtxt<'_, '_>, +fn adt_defined_here<'p, 'tcx>( + cx: &MatchCheckCtxt<'p, 'tcx>, err: &mut DiagnosticBuilder<'_>, - ty: Ty<'_>, - witnesses: &[super::Pat<'_>], + ty: Ty<'tcx>, + witnesses: &[DeconstructedPat<'p, 'tcx>], ) { let ty = ty.peel_refs(); if let ty::Adt(def, _) = ty.kind() { @@ -595,57 +597,42 @@ fn adt_defined_here( } if witnesses.len() < 4 { - for sp in maybe_point_at_variant(ty, &witnesses) { + for sp in maybe_point_at_variant(cx, def, witnesses.iter()) { err.span_label(sp, "not covered"); } } } } -fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec { +fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( + cx: &MatchCheckCtxt<'p, 'tcx>, + def: &AdtDef, + patterns: impl Iterator>, +) -> Vec { + use Constructor::*; let mut covered = vec![]; - if let ty::Adt(def, _) = ty.kind() { - // Don't point at variants that have already been covered due to other patterns to avoid - // visual clutter. - for pattern in patterns { - use PatKind::{AscribeUserType, Deref, Leaf, Or, Variant}; - match &*pattern.kind { - AscribeUserType { subpattern, .. } | Deref { subpattern } => { - covered.extend(maybe_point_at_variant(ty, slice::from_ref(&subpattern))); + for pattern in patterns { + if let Variant(variant_index) = pattern.ctor() { + if let ty::Adt(this_def, _) = pattern.ty().kind() { + if this_def.did != def.did { + continue; } - Variant { adt_def, variant_index, subpatterns, .. } if adt_def.did == def.did => { - let sp = def.variants[*variant_index].ident.span; - if covered.contains(&sp) { - continue; - } - covered.push(sp); - - let pats = subpatterns - .iter() - .map(|field_pattern| field_pattern.pattern.clone()) - .collect::>(); - covered.extend(maybe_point_at_variant(ty, &pats)); - } - Leaf { subpatterns } => { - let pats = subpatterns - .iter() - .map(|field_pattern| field_pattern.pattern.clone()) - .collect::>(); - covered.extend(maybe_point_at_variant(ty, &pats)); - } - Or { pats } => { - let pats = pats.iter().cloned().collect::>(); - covered.extend(maybe_point_at_variant(ty, &pats)); - } - _ => {} } + let sp = def.variants[*variant_index].ident.span; + if covered.contains(&sp) { + // Don't point at variants that have already been covered due to other patterns to avoid + // visual clutter. + continue; + } + covered.push(sp); } + covered.extend(maybe_point_at_variant(cx, def, pattern.iter_fields())); } covered } /// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`. -fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> bool { +fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId, span: Span) -> bool { !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env) } @@ -659,7 +646,7 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> b /// - `x @ Some(ref mut? y)`. /// /// This analysis is *not* subsumed by NLL. -fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) { +fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pat<'_>) { // Extract `sub` in `binding @ sub`. let (name, sub) = match &pat.kind { hir::PatKind::Binding(.., name, Some(sub)) => (*name, sub), diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index cee2a4db0a8b3..dfcbd0da3a6e1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -46,7 +46,7 @@ use self::Constructor::*; use self::SliceKind::*; use super::compare_const_vals; -use super::usefulness::{is_wildcard, MatchCheckCtxt, PatCtxt}; +use super::usefulness::{MatchCheckCtxt, PatCtxt}; use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; @@ -56,16 +56,35 @@ use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::Field; use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange}; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt, VariantDef}; use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; use smallvec::{smallvec, SmallVec}; +use std::cell::Cell; use std::cmp::{self, max, min, Ordering}; +use std::fmt; use std::iter::{once, IntoIterator}; use std::ops::RangeInclusive; +/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. +fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { + fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { + if let PatKind::Or { pats } = pat.kind.as_ref() { + for pat in pats { + expand(pat, vec); + } + } else { + vec.push(pat) + } + } + + let mut pats = Vec::new(); + expand(pat, &mut pats); + pats +} + /// An inclusive interval, used for precise integer exhaustiveness checking. /// `IntRange`s always store a contiguous range. This means that values are /// encoded such that `0` encodes the minimum value for the integer, @@ -76,9 +95,13 @@ use std::ops::RangeInclusive; /// /// `IntRange` is never used to encode an empty range or a "range" that wraps /// around the (offset) space: i.e., `range.lo <= range.hi`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub(super) struct IntRange { range: RangeInclusive, + /// Keeps the bias used for encoding the range. It depends on the type of the range and + /// possibly the pointer size of the current architecture. The algorithm ensures we never + /// compare `IntRange`s with different types/architectures. + bias: u128, } impl IntRange { @@ -131,7 +154,7 @@ impl IntRange { value.try_eval_bits(tcx, param_env, ty) })()?; let val = val ^ bias; - Some(IntRange { range: val..=val }) + Some(IntRange { range: val..=val, bias }) } else { None } @@ -155,7 +178,7 @@ impl IntRange { // This should have been caught earlier by E0030. bug!("malformed range pattern: {}..={}", lo, (hi - offset)); } - Some(IntRange { range: lo..=(hi - offset) }) + Some(IntRange { range: lo..=(hi - offset), bias }) } else { None } @@ -180,7 +203,7 @@ impl IntRange { let (lo, hi) = self.boundaries(); let (other_lo, other_hi) = other.boundaries(); if lo <= other_hi && other_lo <= hi { - Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi) }) + Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), bias: self.bias }) } else { None } @@ -203,10 +226,11 @@ impl IntRange { (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton() } + /// Only used for displaying the range properly. fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { let (lo, hi) = self.boundaries(); - let bias = IntRange::signed_bias(tcx, ty); + let bias = self.bias; let (lo, hi) = (lo ^ bias, hi ^ bias); let env = ty::ParamEnv::empty().and(ty); @@ -223,10 +247,10 @@ impl IntRange { } /// Lint on likely incorrect range patterns (#63987) - pub(super) fn lint_overlapping_range_endpoints<'a, 'tcx: 'a>( + pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>( &self, - pcx: PatCtxt<'_, '_, 'tcx>, - ctors: impl Iterator, Span)>, + pcx: PatCtxt<'_, 'p, 'tcx>, + pats: impl Iterator>, column_count: usize, hir_id: HirId, ) { @@ -248,8 +272,8 @@ impl IntRange { return; } - let overlaps: Vec<_> = ctors - .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))) + let overlaps: Vec<_> = pats + .filter_map(|pat| Some((pat.ctor().as_int_range()?, pat.span()))) .filter(|(range, _)| self.suspicious_intersection(range)) .map(|(range, span)| (self.intersection(&range).unwrap(), span)) .collect(); @@ -291,6 +315,19 @@ impl IntRange { } } +/// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and +/// would be displayed as such. To render properly, convert to a pattern first. +impl fmt::Debug for IntRange { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (lo, hi) = self.boundaries(); + let bias = self.bias; + let (lo, hi) = (lo ^ bias, hi ^ bias); + write!(f, "{}", lo)?; + write!(f, "{}", RangeEnd::Included)?; + write!(f, "{}", hi) + } +} + /// Represents a border between 2 integers. Because the intervals spanning borders must be able to /// cover every integer, we need to be able to represent 2^128 + 1 such borders. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -375,13 +412,13 @@ impl SplitIntRange { // Skip duplicates. .filter(|(prev_border, border)| prev_border != border) // Finally, convert to ranges. - .map(|(prev_border, border)| { + .map(move |(prev_border, border)| { let range = match (prev_border, border) { (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), (JustBefore(n), AfterMax) => n..=u128::MAX, _ => unreachable!(), // Ruled out by the sorting and filtering we did }; - IntRange { range } + IntRange { range, bias: self.range.bias } }) } } @@ -389,17 +426,17 @@ impl SplitIntRange { #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum SliceKind { /// Patterns of length `n` (`[x, y]`). - FixedLen(u64), + FixedLen(usize), /// Patterns using the `..` notation (`[x, .., y]`). /// Captures any array constructor of `length >= i + j`. /// In the case where `array_len` is `Some(_)`, /// this indicates that we only care about the first `i` and the last `j` values of the array, /// and everything in between is a wildcard `_`. - VarLen(u64, u64), + VarLen(usize, usize), } impl SliceKind { - fn arity(self) -> u64 { + fn arity(self) -> usize { match self { FixedLen(length) => length, VarLen(prefix, suffix) => prefix + suffix, @@ -407,7 +444,7 @@ impl SliceKind { } /// Whether this pattern includes patterns of length `other_len`. - fn covers_length(self, other_len: u64) -> bool { + fn covers_length(self, other_len: usize) -> bool { match self { FixedLen(len) => len == other_len, VarLen(prefix, suffix) => prefix + suffix <= other_len, @@ -419,13 +456,13 @@ impl SliceKind { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(super) struct Slice { /// `None` if the matched value is a slice, `Some(n)` if it is an array of size `n`. - array_len: Option, + array_len: Option, /// The kind of pattern it is: fixed-length `[x, y]` or variable length `[x, .., y]`. kind: SliceKind, } impl Slice { - fn new(array_len: Option, kind: SliceKind) -> Self { + fn new(array_len: Option, kind: SliceKind) -> Self { let kind = match (array_len, kind) { // If the middle `..` is empty, we effectively have a fixed-length pattern. (Some(len), VarLen(prefix, suffix)) if prefix + suffix >= len => FixedLen(len), @@ -434,7 +471,7 @@ impl Slice { Slice { array_len, kind } } - fn arity(self) -> u64 { + fn arity(self) -> usize { self.kind.arity() } @@ -508,16 +545,16 @@ impl Slice { #[derive(Debug)] struct SplitVarLenSlice { /// If the type is an array, this is its size. - array_len: Option, + array_len: Option, /// The arity of the input slice. - arity: u64, + arity: usize, /// The smallest slice bigger than any slice seen. `max_slice.arity()` is the length `L` /// described above. max_slice: SliceKind, } impl SplitVarLenSlice { - fn new(prefix: u64, suffix: u64, array_len: Option) -> Self { + fn new(prefix: usize, suffix: usize, array_len: Option) -> Self { SplitVarLenSlice { array_len, arity: prefix + suffix, max_slice: VarLen(prefix, suffix) } } @@ -611,6 +648,8 @@ pub(super) enum Constructor<'tcx> { Missing { nonexhaustive_enum_missing_real_variants: bool }, /// Wildcard pattern. Wildcard, + /// Or-pattern. + Or, } impl<'tcx> Constructor<'tcx> { @@ -647,60 +686,34 @@ impl<'tcx> Constructor<'tcx> { } } - /// Determines the constructor that the given pattern can be specialized to. - pub(super) fn from_pat<'p>(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &'p Pat<'tcx>) -> Self { - match pat.kind.as_ref() { - PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` - PatKind::Binding { .. } | PatKind::Wild => Wildcard, - PatKind::Leaf { .. } | PatKind::Deref { .. } => Single, - &PatKind::Variant { variant_index, .. } => Variant(variant_index), - PatKind::Constant { value } => { - if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) { - IntRange(int_range) - } else { - match pat.ty.kind() { - ty::Float(_) => FloatRange(value, value, RangeEnd::Included), - // In `expand_pattern`, we convert string literals to `&CONST` patterns with - // `CONST` a pattern of type `str`. In truth this contains a constant of type - // `&str`. - ty::Str => Str(value), - // All constants that can be structurally matched have already been expanded - // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are - // opaque. - _ => Opaque, + /// The number of fields for this constructor. This must be kept in sync with + /// `Fields::wildcards`. + pub(super) fn arity(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> usize { + match self { + Single | Variant(_) => match pcx.ty.kind() { + ty::Tuple(fs) => fs.len(), + ty::Ref(..) => 1, + ty::Adt(adt, ..) => { + if adt.is_box() { + // The only legal patterns of type `Box` (outside `std`) are `_` and box + // patterns. If we're here we can assume this is a box pattern. + 1 + } else { + let variant = &adt.variants[self.variant_index_for_adt(adt)]; + Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant).count() } } - } - &PatKind::Range(PatRange { lo, hi, end }) => { - let ty = lo.ty; - if let Some(int_range) = IntRange::from_range( - cx.tcx, - lo.eval_bits(cx.tcx, cx.param_env, lo.ty), - hi.eval_bits(cx.tcx, cx.param_env, hi.ty), - ty, - &end, - ) { - IntRange(int_range) - } else { - FloatRange(lo, hi, end) - } - } - PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { - let array_len = match pat.ty.kind() { - ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env)), - ty::Slice(_) => None, - _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), - }; - let prefix = prefix.len() as u64; - let suffix = suffix.len() as u64; - let kind = if slice.is_some() { - VarLen(prefix, suffix) - } else { - FixedLen(prefix + suffix) - }; - Slice(Slice::new(array_len, kind)) - } - PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."), + _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx.ty), + }, + Slice(slice) => slice.arity(), + Str(..) + | FloatRange(..) + | IntRange(..) + | NonExhaustive + | Opaque + | Missing { .. } + | Wildcard => 0, + Or => bug!("The `Or` constructor doesn't have a fixed arity"), } } @@ -823,7 +836,7 @@ impl<'tcx> Constructor<'tcx> { match self { // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s. Single => !used_ctors.is_empty(), - Variant(_) => used_ctors.iter().any(|c| c == self), + Variant(vid) => used_ctors.iter().any(|c| matches!(c, Variant(i) if i == vid)), IntRange(range) => used_ctors .iter() .filter_map(|c| c.as_int_range()) @@ -834,7 +847,7 @@ impl<'tcx> Constructor<'tcx> { .any(|other| slice.is_covered_by(other)), // This constructor is never covered by anything else NonExhaustive => false, - Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard => { + Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard | Or => { span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self) } } @@ -885,7 +898,7 @@ impl<'tcx> SplitWildcard<'tcx> { let all_ctors = match pcx.ty.kind() { ty::Bool => smallvec![make_range(0, 1)], ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => { - let len = len.eval_usize(cx.tcx, cx.param_env); + let len = len.eval_usize(cx.tcx, cx.param_env) as usize; if len != 0 && cx.is_uninhabited(sub_ty) { smallvec![] } else { @@ -1073,120 +1086,108 @@ impl<'tcx> SplitWildcard<'tcx> { } } -/// Some fields need to be explicitly hidden away in certain cases; see the comment above the -/// `Fields` struct. This struct represents such a potentially-hidden field. -#[derive(Debug, Copy, Clone)] -pub(super) enum FilteredField<'p, 'tcx> { - Kept(&'p Pat<'tcx>), - Hidden, -} - -impl<'p, 'tcx> FilteredField<'p, 'tcx> { - fn kept(self) -> Option<&'p Pat<'tcx>> { - match self { - FilteredField::Kept(p) => Some(p), - FilteredField::Hidden => None, - } - } -} - /// A value can be decomposed into a constructor applied to some fields. This struct represents /// those fields, generalized to allow patterns in each field. See also `Constructor`. -/// This is constructed from a constructor using [`Fields::wildcards()`]. /// -/// If a private or `non_exhaustive` field is uninhabited, the code mustn't observe that it is -/// uninhabited. For that, we filter these fields out of the matrix. This is handled automatically -/// in `Fields`. This filtering is uncommon in practice, because uninhabited fields are rarely used, -/// so we avoid it when possible to preserve performance. -#[derive(Debug, Clone)] -pub(super) enum Fields<'p, 'tcx> { - /// Lists of patterns that don't contain any filtered fields. - /// `Slice` and `Vec` behave the same; the difference is only to avoid allocating and - /// triple-dereferences when possible. Frankly this is premature optimization, I (Nadrieril) - /// have not measured if it really made a difference. - Slice(&'p [Pat<'tcx>]), - Vec(SmallVec<[&'p Pat<'tcx>; 2]>), - /// Patterns where some of the fields need to be hidden. For all intents and purposes we only - /// care about the non-hidden fields. We need to keep the real field index for those fields; - /// we're morally storing a `Vec<(usize, &Pat)>` but what we do is more convenient. - /// `len` counts the number of non-hidden fields - Filtered { - fields: SmallVec<[FilteredField<'p, 'tcx>; 2]>, - len: usize, - }, +/// This is constructed for a constructor using [`Fields::wildcards()`]. The idea is that +/// [`Fields::wildcards()`] constructs a list of fields where all entries are wildcards, and then +/// given a pattern we fill some of the fields with its subpatterns. +/// In the following example `Fields::wildcards` returns `[_, _, _, _]`. Then in +/// `extract_pattern_arguments` we fill some of the entries, and the result is +/// `[Some(0), _, _, _]`. +/// ```rust +/// let x: [Option; 4] = foo(); +/// match x { +/// [Some(0), ..] => {} +/// } +/// ``` +/// +/// Note that the number of fields of a constructor may not match the fields declared in the +/// original struct/variant. This happens if a private or `non_exhaustive` field is uninhabited, +/// because the code mustn't observe that it is uninhabited. In that case that field is not +/// included in `fields`. For that reason, when you have a `mir::Field` you must use +/// `index_with_declared_idx`. +#[derive(Debug, Clone, Copy)] +pub(super) struct Fields<'p, 'tcx> { + fields: &'p [DeconstructedPat<'p, 'tcx>], } impl<'p, 'tcx> Fields<'p, 'tcx> { - /// Internal use. Use `Fields::wildcards()` instead. - /// Must not be used if the pattern is a field of a struct/tuple/variant. - fn from_single_pattern(pat: &'p Pat<'tcx>) -> Self { - Fields::Slice(std::slice::from_ref(pat)) + fn empty() -> Self { + Fields { fields: &[] } + } + + fn singleton(cx: &MatchCheckCtxt<'p, 'tcx>, field: DeconstructedPat<'p, 'tcx>) -> Self { + let field: &_ = cx.pattern_arena.alloc(field); + Fields { fields: std::slice::from_ref(field) } + } + + pub(super) fn from_iter( + cx: &MatchCheckCtxt<'p, 'tcx>, + fields: impl IntoIterator>, + ) -> Self { + let fields: &[_] = cx.pattern_arena.alloc_from_iter(fields); + Fields { fields } } - /// Convenience; internal use. fn wildcards_from_tys( cx: &MatchCheckCtxt<'p, 'tcx>, tys: impl IntoIterator>, ) -> Self { - let wilds = tys.into_iter().map(Pat::wildcard_from_ty); - let pats = cx.pattern_arena.alloc_from_iter(wilds); - Fields::Slice(pats) + Fields::from_iter(cx, tys.into_iter().map(DeconstructedPat::wildcard)) } - /// Creates a new list of wildcard fields for a given constructor. - pub(super) fn wildcards(pcx: PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self { - let ty = pcx.ty; - let cx = pcx.cx; - let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); + // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide + // uninhabited fields in order not to reveal the uninhabitedness of the whole variant. + // This lists the fields we keep along with their types. + fn list_variant_nonhidden_fields<'a>( + cx: &'a MatchCheckCtxt<'p, 'tcx>, + ty: Ty<'tcx>, + variant: &'a VariantDef, + ) -> impl Iterator)> + Captures<'a> + Captures<'p> { + let (adt, substs) = match ty.kind() { + ty::Adt(adt, substs) => (adt, substs), + _ => bug!(), + }; + // Whether we must not match the fields of this variant exhaustively. + let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local(); + + variant.fields.iter().enumerate().filter_map(move |(i, field)| { + let ty = field.ty(cx.tcx, substs); + // `field.ty()` doesn't normalize after substituting. + let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); + let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); + let is_uninhabited = cx.is_uninhabited(ty); + + if is_uninhabited && (!is_visible || is_non_exhaustive) { + None + } else { + Some((Field::new(i), ty)) + } + }) + } + /// Creates a new list of wildcard fields for a given constructor. The result must have a + /// length of `constructor.arity()`. + pub(super) fn wildcards( + cx: &MatchCheckCtxt<'p, 'tcx>, + ty: Ty<'tcx>, + constructor: &Constructor<'tcx>, + ) -> Self { let ret = match constructor { Single | Variant(_) => match ty.kind() { - ty::Tuple(ref fs) => { - Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty())) - } - ty::Ref(_, rty, _) => Fields::from_single_pattern(wildcard_from_ty(rty)), + ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter().map(|ty| ty.expect_ty())), + ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)), ty::Adt(adt, substs) => { if adt.is_box() { - // Use T as the sub pattern type of Box. - Fields::from_single_pattern(wildcard_from_ty(substs.type_at(0))) + // The only legal patterns of type `Box` (outside `std`) are `_` and box + // patterns. If we're here we can assume this is a box pattern. + Fields::wildcards_from_tys(cx, once(substs.type_at(0))) } else { let variant = &adt.variants[constructor.variant_index_for_adt(adt)]; - // Whether we must not match the fields of this variant exhaustively. - let is_non_exhaustive = - variant.is_field_list_non_exhaustive() && !adt.did.is_local(); - let field_tys = variant.fields.iter().map(|field| field.ty(cx.tcx, substs)); - // In the following cases, we don't need to filter out any fields. This is - // the vast majority of real cases, since uninhabited fields are uncommon. - let has_no_hidden_fields = (adt.is_enum() && !is_non_exhaustive) - || !field_tys.clone().any(|ty| cx.is_uninhabited(ty)); - - if has_no_hidden_fields { - Fields::wildcards_from_tys(cx, field_tys) - } else { - let mut len = 0; - let fields = variant - .fields - .iter() - .map(|field| { - let ty = field.ty(cx.tcx, substs); - let is_visible = adt.is_enum() - || field.vis.is_accessible_from(cx.module, cx.tcx); - let is_uninhabited = cx.is_uninhabited(ty); - - // In the cases of either a `#[non_exhaustive]` field list - // or a non-public field, we hide uninhabited fields in - // order not to reveal the uninhabitedness of the whole - // variant. - if is_uninhabited && (!is_visible || is_non_exhaustive) { - FilteredField::Hidden - } else { - len += 1; - FilteredField::Kept(wildcard_from_ty(ty)) - } - }) - .collect(); - Fields::Filtered { fields, len } - } + let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant) + .map(|(_, ty)| ty); + Fields::wildcards_from_tys(cx, tys) } } _ => bug!("Unexpected type for `Single` constructor: {:?}", ty), @@ -1204,54 +1205,243 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { | NonExhaustive | Opaque | Missing { .. } - | Wildcard => Fields::Slice(&[]), + | Wildcard => Fields::empty(), + Or => { + bug!("called `Fields::wildcards` on an `Or` ctor") + } }; debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret); ret } - /// Apply a constructor to a list of patterns, yielding a new pattern. `self` - /// must have as many elements as this constructor's arity. - /// - /// This is roughly the inverse of `specialize_constructor`. - /// - /// Examples: - /// - /// ```text - /// ctor: `Constructor::Single` - /// ty: `Foo(u32, u32, u32)` - /// self: `[10, 20, _]` - /// returns `Foo(10, 20, _)` - /// - /// ctor: `Constructor::Variant(Option::Some)` - /// ty: `Option` - /// self: `[false]` - /// returns `Some(false)` - /// ``` - pub(super) fn apply(self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Pat<'tcx> { - let subpatterns_and_indices = self.patterns_and_indices(); - let mut subpatterns = subpatterns_and_indices.iter().map(|&(_, p)| p).cloned(); - - let pat = match ctor { - Single | Variant(_) => match pcx.ty.kind() { - ty::Adt(..) | ty::Tuple(..) => { - // We want the real indices here. - let subpatterns = subpatterns_and_indices - .iter() - .map(|&(field, p)| FieldPat { field, pattern: p.clone() }) - .collect(); + /// Returns the list of patterns. + pub(super) fn iter_patterns<'a>( + &'a self, + ) -> impl Iterator> + Captures<'a> { + self.fields.iter() + } +} - if let ty::Adt(adt, substs) = pcx.ty.kind() { - if adt.is_enum() { - PatKind::Variant { - adt_def: adt, - substs, - variant_index: ctor.variant_index_for_adt(adt), - subpatterns, - } +/// Values and patterns can be represented as a constructor applied to some fields. This represents +/// a pattern in this form. +/// This also keeps track of whether the pattern has been foundreachable during analysis. For this +/// reason we should be careful not to clone patterns for which we care about that. Use +/// `clone_and_forget_reachability` is you're sure. +pub(crate) struct DeconstructedPat<'p, 'tcx> { + ctor: Constructor<'tcx>, + fields: Fields<'p, 'tcx>, + ty: Ty<'tcx>, + span: Span, + reachable: Cell, +} + +impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { + pub(super) fn wildcard(ty: Ty<'tcx>) -> Self { + Self::new(Wildcard, Fields::empty(), ty, DUMMY_SP) + } + + pub(super) fn new( + ctor: Constructor<'tcx>, + fields: Fields<'p, 'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> Self { + DeconstructedPat { ctor, fields, ty, span, reachable: Cell::new(false) } + } + + /// Construct a pattern that matches everything that starts with this constructor. + /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern + /// `Some(_)`. + pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self { + let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor); + DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP) + } + + /// Clone this value. This method emphasizes that cloning loses reachability information and + /// should be done carefully. + pub(super) fn clone_and_forget_reachability(&self) -> Self { + DeconstructedPat::new(self.ctor.clone(), self.fields, self.ty, self.span) + } + + pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self { + let mkpat = |pat| DeconstructedPat::from_pat(cx, pat); + let ctor; + let fields; + match pat.kind.as_ref() { + PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern), + PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat), + PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { + ctor = Wildcard; + fields = Fields::empty(); + } + PatKind::Deref { subpattern } => { + ctor = Single; + fields = Fields::singleton(cx, mkpat(subpattern)); + } + PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { + match pat.ty.kind() { + ty::Tuple(fs) => { + ctor = Single; + let mut wilds: SmallVec<[_; 2]> = fs + .iter() + .map(|ty| ty.expect_ty()) + .map(DeconstructedPat::wildcard) + .collect(); + for pat in subpatterns { + wilds[pat.field.index()] = mkpat(&pat.pattern); + } + fields = Fields::from_iter(cx, wilds); + } + ty::Adt(adt, substs) if adt.is_box() => { + // The only legal patterns of type `Box` (outside `std`) are `_` and box + // patterns. If we're here we can assume this is a box pattern. + // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_, + // _)` or a box pattern. As a hack to avoid an ICE with the former, we + // ignore other fields than the first one. This will trigger an error later + // anyway. + // See https://github.com/rust-lang/rust/issues/82772 , + // explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977 + // The problem is that we can't know from the type whether we'll match + // normally or through box-patterns. We'll have to figure out a proper + // solution when we introduce generalized deref patterns. Also need to + // prevent mixing of those two options. + let pat = subpatterns.into_iter().find(|pat| pat.field.index() == 0); + let pat = if let Some(pat) = pat { + mkpat(&pat.pattern) } else { - PatKind::Leaf { subpatterns } + DeconstructedPat::wildcard(substs.type_at(0)) + }; + ctor = Single; + fields = Fields::singleton(cx, pat); + } + ty::Adt(adt, _) => { + ctor = match pat.kind.as_ref() { + PatKind::Leaf { .. } => Single, + PatKind::Variant { variant_index, .. } => Variant(*variant_index), + _ => bug!(), + }; + let variant = &adt.variants[ctor.variant_index_for_adt(adt)]; + // For each field in the variant, we store the relevant index into `self.fields` if any. + let mut field_id_to_id: Vec> = + (0..variant.fields.len()).map(|_| None).collect(); + let tys = Fields::list_variant_nonhidden_fields(cx, pat.ty, variant) + .enumerate() + .map(|(i, (field, ty))| { + field_id_to_id[field.index()] = Some(i); + ty + }); + let mut wilds: SmallVec<[_; 2]> = + tys.map(DeconstructedPat::wildcard).collect(); + for pat in subpatterns { + if let Some(i) = field_id_to_id[pat.field.index()] { + wilds[i] = mkpat(&pat.pattern); + } + } + fields = Fields::from_iter(cx, wilds); + } + _ => bug!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, pat.ty), + } + } + PatKind::Constant { value } => { + if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) { + ctor = IntRange(int_range); + fields = Fields::empty(); + } else { + match pat.ty.kind() { + ty::Float(_) => { + ctor = FloatRange(value, value, RangeEnd::Included); + fields = Fields::empty(); + } + ty::Ref(_, t, _) if t.is_str() => { + // We want a `&str` constant to behave like a `Deref` pattern, to be compatible + // with other `Deref` patterns. This could have been done in `const_to_pat`, + // but that causes issues with the rest of the matching code. + // So here, the constructor for a `"foo"` pattern is `&` (represented by + // `Single`), and has one field. That field has constructor `Str(value)` and no + // fields. + // Note: `t` is `str`, not `&str`. + let subpattern = + DeconstructedPat::new(Str(value), Fields::empty(), t, pat.span); + ctor = Single; + fields = Fields::singleton(cx, subpattern) + } + // All constants that can be structurally matched have already been expanded + // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are + // opaque. + _ => { + ctor = Opaque; + fields = Fields::empty(); } + } + } + } + &PatKind::Range(PatRange { lo, hi, end }) => { + let ty = lo.ty; + ctor = if let Some(int_range) = IntRange::from_range( + cx.tcx, + lo.eval_bits(cx.tcx, cx.param_env, lo.ty), + hi.eval_bits(cx.tcx, cx.param_env, hi.ty), + ty, + &end, + ) { + IntRange(int_range) + } else { + FloatRange(lo, hi, end) + }; + fields = Fields::empty(); + } + PatKind::Array { prefix, slice, suffix } | PatKind::Slice { prefix, slice, suffix } => { + let array_len = match pat.ty.kind() { + ty::Array(_, length) => Some(length.eval_usize(cx.tcx, cx.param_env) as usize), + ty::Slice(_) => None, + _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), + }; + let kind = if slice.is_some() { + VarLen(prefix.len(), suffix.len()) + } else { + FixedLen(prefix.len() + suffix.len()) + }; + ctor = Slice(Slice::new(array_len, kind)); + fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(mkpat)); + } + PatKind::Or { .. } => { + ctor = Or; + let pats = expand_or_pat(pat); + fields = Fields::from_iter(cx, pats.into_iter().map(mkpat)); + } + } + DeconstructedPat::new(ctor, fields, pat.ty, pat.span) + } + + pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> { + let is_wildcard = |pat: &Pat<'_>| { + matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) + }; + let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx)); + let pat = match &self.ctor { + Single | Variant(_) => match self.ty.kind() { + ty::Tuple(..) => PatKind::Leaf { + subpatterns: subpatterns + .enumerate() + .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) + .collect(), + }, + ty::Adt(adt_def, _) if adt_def.is_box() => { + // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside + // of `std`). So this branch is only reachable when the feature is enabled and + // the pattern is a box pattern. + PatKind::Deref { subpattern: subpatterns.next().unwrap() } + } + ty::Adt(adt_def, substs) => { + let variant_index = self.ctor.variant_index_for_adt(adt_def); + let variant = &adt_def.variants[variant_index]; + let subpatterns = Fields::list_variant_nonhidden_fields(cx, self.ty, variant) + .zip(subpatterns) + .map(|((field, _ty), pattern)| FieldPat { field, pattern }) + .collect(); + + if adt_def.is_enum() { + PatKind::Variant { adt_def, substs, variant_index, subpatterns } } else { PatKind::Leaf { subpatterns } } @@ -1259,195 +1449,239 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should // be careful to reconstruct the correct constant pattern here. However a string // literal pattern will never be reported as a non-exhaustiveness witness, so we - // can ignore this issue. + // ignore this issue. ty::Ref(..) => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, - ty::Slice(_) | ty::Array(..) => bug!("bad slice pattern {:?} {:?}", ctor, pcx.ty), - _ => PatKind::Wild, + _ => bug!("unexpected ctor for type {:?} {:?}", self.ctor, self.ty), }, - Slice(slice) => match slice.kind { - FixedLen(_) => { - PatKind::Slice { prefix: subpatterns.collect(), slice: None, suffix: vec![] } - } - VarLen(prefix, _) => { - let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix as usize).collect(); - if slice.array_len.is_some() { - // Improves diagnostics a bit: if the type is a known-size array, instead - // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. - // This is incorrect if the size is not known, since `[_, ..]` captures - // arrays of lengths `>= 1` whereas `[..]` captures any length. - while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) { - prefix.pop(); + Slice(slice) => { + match slice.kind { + FixedLen(_) => PatKind::Slice { + prefix: subpatterns.collect(), + slice: None, + suffix: vec![], + }, + VarLen(prefix, _) => { + let mut subpatterns = subpatterns.peekable(); + let mut prefix: Vec<_> = subpatterns.by_ref().take(prefix).collect(); + if slice.array_len.is_some() { + // Improves diagnostics a bit: if the type is a known-size array, instead + // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. + // This is incorrect if the size is not known, since `[_, ..]` captures + // arrays of lengths `>= 1` whereas `[..]` captures any length. + while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) { + prefix.pop(); + } + while subpatterns.peek().is_some() + && is_wildcard(subpatterns.peek().unwrap()) + { + subpatterns.next(); + } } + let suffix: Vec<_> = subpatterns.collect(); + let wild = Pat::wildcard_from_ty(self.ty); + PatKind::Slice { prefix, slice: Some(wild), suffix } } - let suffix: Vec<_> = if slice.array_len.is_some() { - // Same as above. - subpatterns.skip_while(is_wildcard).collect() - } else { - subpatterns.collect() - }; - let wild = Pat::wildcard_from_ty(pcx.ty); - PatKind::Slice { prefix, slice: Some(wild), suffix } } - }, + } &Str(value) => PatKind::Constant { value }, &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), - IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty), - NonExhaustive => PatKind::Wild, - Wildcard => return Pat::wildcard_from_ty(pcx.ty), - Opaque => bug!("we should not try to apply an opaque constructor"), + IntRange(range) => return range.to_pat(cx.tcx, self.ty), + Wildcard | NonExhaustive => PatKind::Wild, Missing { .. } => bug!( - "trying to apply the `Missing` constructor; this should have been done in `apply_constructors`" + "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, + `Missing` should have been processed in `apply_constructors`" ), + Opaque | Or => { + bug!("can't convert to pattern: {:?}", self) + } }; - Pat { ty: pcx.ty, span: DUMMY_SP, kind: Box::new(pat) } + Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(pat) } } - /// Returns the number of patterns. This is the same as the arity of the constructor used to - /// construct `self`. - pub(super) fn len(&self) -> usize { - match self { - Fields::Slice(pats) => pats.len(), - Fields::Vec(pats) => pats.len(), - Fields::Filtered { len, .. } => *len, - } + pub(super) fn is_or_pat(&self) -> bool { + matches!(self.ctor, Or) } - /// Returns the list of patterns along with the corresponding field indices. - fn patterns_and_indices(&self) -> SmallVec<[(Field, &'p Pat<'tcx>); 2]> { - match self { - Fields::Slice(pats) => { - pats.iter().enumerate().map(|(i, p)| (Field::new(i), p)).collect() - } - Fields::Vec(pats) => { - pats.iter().copied().enumerate().map(|(i, p)| (Field::new(i), p)).collect() - } - Fields::Filtered { fields, .. } => { - // Indices must be relative to the full list of patterns - fields - .iter() - .enumerate() - .filter_map(|(i, p)| Some((Field::new(i), p.kept()?))) - .collect() - } - } + pub(super) fn ctor(&self) -> &Constructor<'tcx> { + &self.ctor } - - /// Returns the list of patterns. - pub(super) fn into_patterns(self) -> SmallVec<[&'p Pat<'tcx>; 2]> { - match self { - Fields::Slice(pats) => pats.iter().collect(), - Fields::Vec(pats) => pats, - Fields::Filtered { fields, .. } => fields.iter().filter_map(|p| p.kept()).collect(), - } + pub(super) fn ty(&self) -> Ty<'tcx> { + self.ty } - - /// Overrides some of the fields with the provided patterns. Exactly like - /// `replace_fields_indexed`, except that it takes `FieldPat`s as input. - fn replace_with_fieldpats( - &self, - new_pats: impl IntoIterator>, - ) -> Self { - self.replace_fields_indexed( - new_pats.into_iter().map(|pat| (pat.field.index(), &pat.pattern)), - ) + pub(super) fn span(&self) -> Span { + self.span } - /// Overrides some of the fields with the provided patterns. This is used when a pattern - /// defines some fields but not all, for example `Foo { field1: Some(_), .. }`: here we start - /// with a `Fields` that is just one wildcard per field of the `Foo` struct, and override the - /// entry corresponding to `field1` with the pattern `Some(_)`. This is also used for slice - /// patterns for the same reason. - fn replace_fields_indexed( - &self, - new_pats: impl IntoIterator)>, - ) -> Self { - let mut fields = self.clone(); - if let Fields::Slice(pats) = fields { - fields = Fields::Vec(pats.iter().collect()); - } + pub(super) fn iter_fields<'a>( + &'a self, + ) -> impl Iterator> + Captures<'a> { + self.fields.iter_patterns() + } - match &mut fields { - Fields::Vec(pats) => { - for (i, pat) in new_pats { - if let Some(p) = pats.get_mut(i) { - *p = pat; - } - } + /// Specialize this pattern with a constructor. + /// `other_ctor` can be different from `self.ctor`, but must be covered by it. + pub(super) fn specialize<'a>( + &'a self, + cx: &MatchCheckCtxt<'p, 'tcx>, + other_ctor: &Constructor<'tcx>, + ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> { + match (&self.ctor, other_ctor) { + (Wildcard, _) => { + // We return a wildcard for each field of `other_ctor`. + Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect() } - Fields::Filtered { fields, .. } => { - for (i, pat) in new_pats { - if let FilteredField::Kept(p) = &mut fields[i] { - *p = pat + (Slice(self_slice), Slice(other_slice)) + if self_slice.arity() != other_slice.arity() => + { + // The only tricky case: two slices of different arity. Since `self_slice` covers + // `other_slice`, `self_slice` must be `VarLen`, i.e. of the form + // `[prefix, .., suffix]`. Moreover `other_slice` is guaranteed to have a larger + // arity. So we fill the middle part with enough wildcards to reach the length of + // the new, larger slice. + match self_slice.kind { + FixedLen(_) => bug!("{:?} doesn't cover {:?}", self_slice, other_slice), + VarLen(prefix, suffix) => { + let inner_ty = match *self.ty.kind() { + ty::Slice(ty) | ty::Array(ty, _) => ty, + _ => bug!("bad slice pattern {:?} {:?}", self.ctor, self.ty), + }; + let prefix = &self.fields.fields[..prefix]; + let suffix = &self.fields.fields[self_slice.arity() - suffix..]; + let wildcard: &_ = + cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty)); + let extra_wildcards = other_slice.arity() - self_slice.arity(); + let extra_wildcards = (0..extra_wildcards).map(|_| wildcard); + prefix.iter().chain(extra_wildcards).chain(suffix).collect() } } } - Fields::Slice(_) => unreachable!(), + _ => self.fields.iter_patterns().collect(), } - fields } - /// Replaces contained fields with the given list of patterns. There must be `len()` patterns - /// in `pats`. - pub(super) fn replace_fields( - &self, - cx: &MatchCheckCtxt<'p, 'tcx>, - pats: impl IntoIterator>, - ) -> Self { - let pats: &[_] = cx.pattern_arena.alloc_from_iter(pats); + /// We keep track for each pattern if it was ever reachable during the analysis. This is used + /// with `unreachable_spans` to report unreachable subpatterns arising from or patterns. + pub(super) fn set_reachable(&self) { + self.reachable.set(true) + } + pub(super) fn is_reachable(&self) -> bool { + self.reachable.get() + } - match self { - Fields::Filtered { fields, len } => { - let mut pats = pats.iter(); - let mut fields = fields.clone(); - for f in &mut fields { - if let FilteredField::Kept(p) = f { - // We take one input pattern for each `Kept` field, in order. - *p = pats.next().unwrap(); - } - } - Fields::Filtered { fields, len: *len } + /// Report the spans of subpatterns that were not reachable, if any. + pub(super) fn unreachable_spans(&self) -> Vec { + let mut spans = Vec::new(); + self.collect_unreachable_spans(&mut spans); + spans + } + + fn collect_unreachable_spans(&self, spans: &mut Vec) { + // We don't look at subpatterns if we already reported the whole pattern as unreachable. + if !self.is_reachable() { + spans.push(self.span); + } else { + for p in self.iter_fields() { + p.collect_unreachable_spans(spans); } - _ => Fields::Slice(pats), } } +} - /// Replaces contained fields with the arguments of the given pattern. Only use on a pattern - /// that is compatible with the constructor used to build `self`. - /// This is meant to be used on the result of `Fields::wildcards()`. The idea is that - /// `wildcards` constructs a list of fields where all entries are wildcards, and the pattern - /// provided to this function fills some of the fields with non-wildcards. - /// In the following example `Fields::wildcards` would return `[_, _, _, _]`. If we call - /// `replace_with_pattern_arguments` on it with the pattern, the result will be `[Some(0), _, - /// _, _]`. - /// ```rust - /// let x: [Option; 4] = foo(); - /// match x { - /// [Some(0), ..] => {} - /// } - /// ``` - /// This is guaranteed to preserve the number of patterns in `self`. - pub(super) fn replace_with_pattern_arguments(&self, pat: &'p Pat<'tcx>) -> Self { - match pat.kind.as_ref() { - PatKind::Deref { subpattern } => { - assert_eq!(self.len(), 1); - Fields::from_single_pattern(subpattern) +/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a +/// `Display` impl. +impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Printing lists is a chore. + let mut first = true; + let mut start_or_continue = |s| { + if first { + first = false; + "" + } else { + s } - PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { - self.replace_with_fieldpats(subpatterns) + }; + let mut start_or_comma = || start_or_continue(", "); + + match &self.ctor { + Single | Variant(_) => match self.ty.kind() { + ty::Adt(def, _) if def.is_box() => { + // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside + // of `std`). So this branch is only reachable when the feature is enabled and + // the pattern is a box pattern. + let subpattern = self.iter_fields().next().unwrap(); + write!(f, "box {:?}", subpattern) + } + ty::Adt(..) | ty::Tuple(..) => { + let variant = match self.ty.kind() { + ty::Adt(adt, _) => { + Some(&adt.variants[self.ctor.variant_index_for_adt(adt)]) + } + ty::Tuple(_) => None, + _ => unreachable!(), + }; + + if let Some(variant) = variant { + write!(f, "{}", variant.ident)?; + } + + // Without `cx`, we can't know which field corresponds to which, so we can't + // get the names of the fields. Instead we just display everything as a suple + // struct, which should be good enough. + write!(f, "(")?; + for p in self.iter_fields() { + write!(f, "{}", start_or_comma())?; + write!(f, "{:?}", p)?; + } + write!(f, ")") + } + // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should + // be careful to detect strings here. However a string literal pattern will never + // be reported as a non-exhaustiveness witness, so we can ignore this issue. + ty::Ref(_, _, mutbl) => { + let subpattern = self.iter_fields().next().unwrap(); + write!(f, "&{}{:?}", mutbl.prefix_str(), subpattern) + } + _ => write!(f, "_"), + }, + Slice(slice) => { + let mut subpatterns = self.fields.iter_patterns(); + write!(f, "[")?; + match slice.kind { + FixedLen(_) => { + for p in subpatterns { + write!(f, "{}{:?}", start_or_comma(), p)?; + } + } + VarLen(prefix_len, _) => { + for p in subpatterns.by_ref().take(prefix_len) { + write!(f, "{}{:?}", start_or_comma(), p)?; + } + write!(f, "{}", start_or_comma())?; + write!(f, "..")?; + for p in subpatterns { + write!(f, "{}{:?}", start_or_comma(), p)?; + } + } + } + write!(f, "]") + } + &FloatRange(lo, hi, end) => { + write!(f, "{}", lo)?; + write!(f, "{}", end)?; + write!(f, "{}", hi) } - PatKind::Array { prefix, suffix, .. } | PatKind::Slice { prefix, suffix, .. } => { - // Number of subpatterns for the constructor - let ctor_arity = self.len(); - - // Replace the prefix and the suffix with the given patterns, leaving wildcards in - // the middle if there was a subslice pattern `..`. - let prefix = prefix.iter().enumerate(); - let suffix = - suffix.iter().enumerate().map(|(i, p)| (ctor_arity - suffix.len() + i, p)); - self.replace_fields_indexed(prefix.chain(suffix)) + IntRange(range) => write!(f, "{:?}", range), // Best-effort, will render e.g. `false` as `0..=0` + Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty), + Or => { + for pat in self.iter_fields() { + write!(f, "{}{:?}", start_or_continue(" | "), pat)?; + } + Ok(()) } - _ => self.clone(), + Str(value) => write!(f, "{}", value), + Opaque => write!(f, ""), } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index f4255713e2a37..43adef3d03bed 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -284,27 +284,22 @@ use self::ArmType::*; use self::Usefulness::*; use super::check_match::{joined_uncovered_patterns, pattern_not_covered_label}; -use super::deconstruct_pat::{Constructor, Fields, SplitWildcard}; -use super::{PatternFoldable, PatternFolder}; +use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard}; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashMap; -use hir::def_id::DefId; -use hir::HirId; use rustc_arena::TypedArena; -use rustc_hir as hir; -use rustc_middle::thir::{Pat, PatKind}; +use rustc_hir::def_id::DefId; +use rustc_hir::HirId; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::fmt; -use std::iter::{FromIterator, IntoIterator}; -use std::lazy::OnceCell; +use std::iter::once; -crate struct MatchCheckCtxt<'a, 'tcx> { +crate struct MatchCheckCtxt<'p, 'tcx> { crate tcx: TyCtxt<'tcx>, /// The module in which the match occurs. This is necessary for /// checking inhabited-ness of types because whether a type is (visibly) @@ -313,7 +308,7 @@ crate struct MatchCheckCtxt<'a, 'tcx> { /// outside its module and should not be matchable with an empty match statement. crate module: DefId, crate param_env: ty::ParamEnv<'tcx>, - crate pattern_arena: &'a TypedArena>, + crate pattern_arena: &'p TypedArena>, } impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { @@ -356,78 +351,20 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> { } } -crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> { - LiteralExpander.fold_pattern(&pat) -} - -struct LiteralExpander; - -impl<'tcx> PatternFolder<'tcx> for LiteralExpander { - fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> { - debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind); - match (pat.ty.kind(), pat.kind.as_ref()) { - (_, PatKind::Binding { subpattern: Some(s), .. }) => s.fold_with(self), - (_, PatKind::AscribeUserType { subpattern: s, .. }) => s.fold_with(self), - (ty::Ref(_, t, _), PatKind::Constant { .. }) if t.is_str() => { - // Treat string literal patterns as deref patterns to a `str` constant, i.e. - // `&CONST`. This expands them like other const patterns. This could have been done - // in `const_to_pat`, but that causes issues with the rest of the matching code. - let mut new_pat = pat.super_fold_with(self); - // Make a fake const pattern of type `str` (instead of `&str`). That the carried - // constant value still knows it is of type `&str`. - new_pat.ty = t; - Pat { - kind: Box::new(PatKind::Deref { subpattern: new_pat }), - span: pat.span, - ty: pat.ty, - } - } - _ => pat.super_fold_with(self), - } - } -} - -pub(super) fn is_wildcard(pat: &Pat<'_>) -> bool { - matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) -} - -fn is_or_pat(pat: &Pat<'_>) -> bool { - matches!(*pat.kind, PatKind::Or { .. }) -} - -/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. -fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { - fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { - if let PatKind::Or { pats } = pat.kind.as_ref() { - for pat in pats { - expand(pat, vec); - } - } else { - vec.push(pat) - } - } - - let mut pats = Vec::new(); - expand(pat, &mut pats); - pats -} - /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` /// works well. #[derive(Clone)] struct PatStack<'p, 'tcx> { - pats: SmallVec<[&'p Pat<'tcx>; 2]>, - /// Cache for the constructor of the head - head_ctor: OnceCell>, + pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, } impl<'p, 'tcx> PatStack<'p, 'tcx> { - fn from_pattern(pat: &'p Pat<'tcx>) -> Self { + fn from_pattern(pat: &'p DeconstructedPat<'p, 'tcx>) -> Self { Self::from_vec(smallvec![pat]) } - fn from_vec(vec: SmallVec<[&'p Pat<'tcx>; 2]>) -> Self { - PatStack { pats: vec, head_ctor: OnceCell::new() } + fn from_vec(vec: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>) -> Self { + PatStack { pats: vec } } fn is_empty(&self) -> bool { @@ -438,79 +375,56 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { self.pats.len() } - fn head(&self) -> &'p Pat<'tcx> { + fn head(&self) -> &'p DeconstructedPat<'p, 'tcx> { self.pats[0] } - #[inline] - fn head_ctor<'a>(&'a self, cx: &MatchCheckCtxt<'p, 'tcx>) -> &'a Constructor<'tcx> { - self.head_ctor.get_or_init(|| Constructor::from_pat(cx, self.head())) - } - - fn iter(&self) -> impl Iterator> { + fn iter(&self) -> impl Iterator> { self.pats.iter().copied() } // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an // or-pattern. Panics if `self` is empty. fn expand_or_pat<'a>(&'a self) -> impl Iterator> + Captures<'a> { - expand_or_pat(self.head()).into_iter().map(move |pat| { + self.head().iter_fields().map(move |pat| { let mut new_patstack = PatStack::from_pattern(pat); new_patstack.pats.extend_from_slice(&self.pats[1..]); new_patstack }) } - /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations. + /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations. /// /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing /// fields filled with wild patterns. /// /// This is roughly the inverse of `Constructor::apply`. - fn pop_head_constructor(&self, ctor_wild_subpatterns: &Fields<'p, 'tcx>) -> PatStack<'p, 'tcx> { + fn pop_head_constructor( + &self, + cx: &MatchCheckCtxt<'p, 'tcx>, + ctor: &Constructor<'tcx>, + ) -> PatStack<'p, 'tcx> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. - let mut new_fields = - ctor_wild_subpatterns.replace_with_pattern_arguments(self.head()).into_patterns(); + let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor); new_fields.extend_from_slice(&self.pats[1..]); PatStack::from_vec(new_fields) } } -impl<'p, 'tcx> Default for PatStack<'p, 'tcx> { - fn default() -> Self { - Self::from_vec(smallvec![]) - } -} - -impl<'p, 'tcx> PartialEq for PatStack<'p, 'tcx> { - fn eq(&self, other: &Self) -> bool { - self.pats == other.pats - } -} - -impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { - fn from_iter(iter: T) -> Self - where - T: IntoIterator>, - { - Self::from_vec(iter.into_iter().collect()) - } -} - /// Pretty-printing for matrix row. impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "+")?; for pat in self.iter() { - write!(f, " {} +", pat)?; + write!(f, " {:?} +", pat)?; } Ok(()) } } /// A 2D matrix. -#[derive(Clone, PartialEq)] +#[derive(Clone)] pub(super) struct Matrix<'p, 'tcx> { patterns: Vec>, } @@ -528,7 +442,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively /// expands it. fn push(&mut self, row: PatStack<'p, 'tcx>) { - if !row.is_empty() && is_or_pat(row.head()) { + if !row.is_empty() && row.head().is_or_pat() { for row in row.expand_or_pat() { self.patterns.push(row); } @@ -538,24 +452,10 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { } /// Iterate over the first component of each row - fn heads<'a>(&'a self) -> impl Iterator> + Captures<'p> { - self.patterns.iter().map(|r| r.head()) - } - - /// Iterate over the first constructor of each row. - pub(super) fn head_ctors<'a>( + fn heads<'a>( &'a self, - cx: &'a MatchCheckCtxt<'p, 'tcx>, - ) -> impl Iterator> + Captures<'p> + Clone { - self.patterns.iter().map(move |r| r.head_ctor(cx)) - } - - /// Iterate over the first constructor and the corresponding span of each row. - pub(super) fn head_ctors_and_spans<'a>( - &'a self, - cx: &'a MatchCheckCtxt<'p, 'tcx>, - ) -> impl Iterator, Span)> + Captures<'p> { - self.patterns.iter().map(move |r| (r.head_ctor(cx), r.head().span)) + ) -> impl Iterator> + Clone + Captures<'a> { + self.patterns.iter().map(|r| r.head()) } /// This computes `S(constructor, self)`. See top of the file for explanations. @@ -563,13 +463,15 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { &self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, - ctor_wild_subpatterns: &Fields<'p, 'tcx>, ) -> Matrix<'p, 'tcx> { - self.patterns - .iter() - .filter(|r| ctor.is_covered_by(pcx, r.head_ctor(pcx.cx))) - .map(|r| r.pop_head_constructor(ctor_wild_subpatterns)) - .collect() + let mut matrix = Matrix::empty(); + for row in &self.patterns { + if ctor.is_covered_by(pcx, row.head().ctor()) { + let new_row = row.pop_head_constructor(pcx.cx, ctor); + matrix.push(new_row); + } + } + matrix } } @@ -588,7 +490,7 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { let Matrix { patterns: m, .. } = self; let pretty_printed_matrix: Vec> = - m.iter().map(|row| row.iter().map(|pat| format!("{}", pat)).collect()).collect(); + m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); let column_count = m.iter().map(|row| row.len()).next().unwrap_or(0); assert!(m.iter().all(|row| row.len() == column_count)); @@ -609,296 +511,40 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { } } -impl<'p, 'tcx> FromIterator> for Matrix<'p, 'tcx> { - fn from_iter(iter: T) -> Self - where - T: IntoIterator>, - { - let mut matrix = Matrix::empty(); - for x in iter { - // Using `push` ensures we correctly expand or-patterns. - matrix.push(x); - } - matrix - } -} - -/// Given a pattern or a pattern-stack, this struct captures a set of its subpatterns. We use that -/// to track reachable sub-patterns arising from or-patterns. In the absence of or-patterns this -/// will always be either `Empty` (the whole pattern is unreachable) or `Full` (the whole pattern -/// is reachable). When there are or-patterns, some subpatterns may be reachable while others -/// aren't. In this case the whole pattern still counts as reachable, but we will lint the -/// unreachable subpatterns. -/// -/// This supports a limited set of operations, so not all possible sets of subpatterns can be -/// represented. That's ok, we only want the ones that make sense for our usage. -/// -/// What we're doing is illustrated by this: -/// ``` -/// match (true, 0) { -/// (true, 0) => {} -/// (_, 1) => {} -/// (true | false, 0 | 1) => {} -/// } -/// ``` -/// When we try the alternatives of the `true | false` or-pattern, the last `0` is reachable in the -/// `false` alternative but not the `true`. So overall it is reachable. By contrast, the last `1` -/// is not reachable in either alternative, so we want to signal this to the user. -/// Therefore we take the union of sets of reachable patterns coming from different alternatives in -/// order to figure out which subpatterns are overall reachable. -/// -/// Invariant: we try to construct the smallest representation we can. In particular if -/// `self.is_empty()` we ensure that `self` is `Empty`, and same with `Full`. This is not important -/// for correctness currently. -#[derive(Debug, Clone)] -enum SubPatSet<'p, 'tcx> { - /// The empty set. This means the pattern is unreachable. - Empty, - /// The set containing the full pattern. - Full, - /// If the pattern is a pattern with a constructor or a pattern-stack, we store a set for each - /// of its subpatterns. Missing entries in the map are implicitly full, because that's the - /// common case. - Seq { subpats: FxHashMap> }, - /// If the pattern is an or-pattern, we store a set for each of its alternatives. Missing - /// entries in the map are implicitly empty. Note: we always flatten nested or-patterns. - Alt { - subpats: FxHashMap>, - /// Counts the total number of alternatives in the pattern - alt_count: usize, - /// We keep the pattern around to retrieve spans. - pat: &'p Pat<'tcx>, - }, -} - -impl<'p, 'tcx> SubPatSet<'p, 'tcx> { - fn full() -> Self { - SubPatSet::Full - } - fn empty() -> Self { - SubPatSet::Empty - } - - fn is_empty(&self) -> bool { - match self { - SubPatSet::Empty => true, - SubPatSet::Full => false, - // If any subpattern in a sequence is unreachable, the whole pattern is unreachable. - SubPatSet::Seq { subpats } => subpats.values().any(|set| set.is_empty()), - // An or-pattern is reachable if any of its alternatives is. - SubPatSet::Alt { subpats, .. } => subpats.values().all(|set| set.is_empty()), - } - } - - fn is_full(&self) -> bool { - match self { - SubPatSet::Empty => false, - SubPatSet::Full => true, - // The whole pattern is reachable only when all its alternatives are. - SubPatSet::Seq { subpats } => subpats.values().all(|sub_set| sub_set.is_full()), - // The whole or-pattern is reachable only when all its alternatives are. - SubPatSet::Alt { subpats, alt_count, .. } => { - subpats.len() == *alt_count && subpats.values().all(|set| set.is_full()) - } - } - } - - /// Union `self` with `other`, mutating `self`. - fn union(&mut self, other: Self) { - use SubPatSet::*; - // Union with full stays full; union with empty changes nothing. - if self.is_full() || other.is_empty() { - return; - } else if self.is_empty() { - *self = other; - return; - } else if other.is_full() { - *self = Full; - return; - } - - match (&mut *self, other) { - (Seq { subpats: s_set }, Seq { subpats: mut o_set }) => { - s_set.retain(|i, s_sub_set| { - // Missing entries count as full. - let o_sub_set = o_set.remove(&i).unwrap_or(Full); - s_sub_set.union(o_sub_set); - // We drop full entries. - !s_sub_set.is_full() - }); - // Everything left in `o_set` is missing from `s_set`, i.e. counts as full. Since - // unioning with full returns full, we can drop those entries. - } - (Alt { subpats: s_set, .. }, Alt { subpats: mut o_set, .. }) => { - s_set.retain(|i, s_sub_set| { - // Missing entries count as empty. - let o_sub_set = o_set.remove(&i).unwrap_or(Empty); - s_sub_set.union(o_sub_set); - // We drop empty entries. - !s_sub_set.is_empty() - }); - // Everything left in `o_set` is missing from `s_set`, i.e. counts as empty. Since - // unioning with empty changes nothing, we can take those entries as is. - s_set.extend(o_set); - } - _ => bug!(), - } - - if self.is_full() { - *self = Full; - } - } - - /// Returns a list of the spans of the unreachable subpatterns. If `self` is empty (i.e. the - /// whole pattern is unreachable) we return `None`. - fn list_unreachable_spans(&self) -> Option> { - /// Panics if `set.is_empty()`. - fn fill_spans(set: &SubPatSet<'_, '_>, spans: &mut Vec) { - match set { - SubPatSet::Empty => bug!(), - SubPatSet::Full => {} - SubPatSet::Seq { subpats } => { - for (_, sub_set) in subpats { - fill_spans(sub_set, spans); - } - } - SubPatSet::Alt { subpats, pat, alt_count, .. } => { - let expanded = expand_or_pat(pat); - for i in 0..*alt_count { - let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty); - if sub_set.is_empty() { - // Found an unreachable subpattern. - spans.push(expanded[i].span); - } else { - fill_spans(sub_set, spans); - } - } - } - } - } - - if self.is_empty() { - return None; - } - if self.is_full() { - // No subpatterns are unreachable. - return Some(Vec::new()); - } - let mut spans = Vec::new(); - fill_spans(self, &mut spans); - Some(spans) - } - - /// When `self` refers to a patstack that was obtained from specialization, after running - /// `unspecialize` it will refer to the original patstack before specialization. - fn unspecialize(self, arity: usize) -> Self { - use SubPatSet::*; - match self { - Full => Full, - Empty => Empty, - Seq { subpats } => { - // We gather the first `arity` subpatterns together and shift the remaining ones. - let mut new_subpats = FxHashMap::default(); - let mut new_subpats_first_col = FxHashMap::default(); - for (i, sub_set) in subpats { - if i < arity { - // The first `arity` indices are now part of the pattern in the first - // column. - new_subpats_first_col.insert(i, sub_set); - } else { - // Indices after `arity` are simply shifted - new_subpats.insert(i - arity + 1, sub_set); - } - } - // If `new_subpats_first_col` has no entries it counts as full, so we can omit it. - if !new_subpats_first_col.is_empty() { - new_subpats.insert(0, Seq { subpats: new_subpats_first_col }); - } - Seq { subpats: new_subpats } - } - Alt { .. } => bug!(), // `self` is a patstack - } - } - - /// When `self` refers to a patstack that was obtained from splitting an or-pattern, after - /// running `unspecialize` it will refer to the original patstack before splitting. - /// - /// For example: - /// ``` - /// match Some(true) { - /// Some(true) => {} - /// None | Some(true | false) => {} - /// } - /// ``` - /// Here `None` would return the full set and `Some(true | false)` would return the set - /// containing `false`. After `unsplit_or_pat`, we want the set to contain `None` and `false`. - /// This is what this function does. - fn unsplit_or_pat(mut self, alt_id: usize, alt_count: usize, pat: &'p Pat<'tcx>) -> Self { - use SubPatSet::*; - if self.is_empty() { - return Empty; - } - - // Subpatterns coming from inside the or-pattern alternative itself, e.g. in `None | Some(0 - // | 1)`. - let set_first_col = match &mut self { - Full => Full, - Seq { subpats } => subpats.remove(&0).unwrap_or(Full), - Empty => unreachable!(), - Alt { .. } => bug!(), // `self` is a patstack - }; - let mut subpats_first_col = FxHashMap::default(); - subpats_first_col.insert(alt_id, set_first_col); - let set_first_col = Alt { subpats: subpats_first_col, pat, alt_count }; - - let mut subpats = match self { - Full => FxHashMap::default(), - Seq { subpats } => subpats, - Empty => unreachable!(), - Alt { .. } => bug!(), // `self` is a patstack - }; - subpats.insert(0, set_first_col); - Seq { subpats } - } -} - /// This carries the results of computing usefulness, as described at the top of the file. When /// checking usefulness of a match branch, we use the `NoWitnesses` variant, which also keeps track /// of potential unreachable sub-patterns (in the presence of or-patterns). When checking /// exhaustiveness of a whole match, we use the `WithWitnesses` variant, which carries a list of /// witnesses of non-exhaustiveness when there are any. /// Which variant to use is dictated by `ArmType`. -#[derive(Clone, Debug)] +#[derive(Debug)] enum Usefulness<'p, 'tcx> { - /// Carries a set of subpatterns that have been found to be reachable. If empty, this indicates - /// the whole pattern is unreachable. If not, this indicates that the pattern is reachable but - /// that some sub-patterns may be unreachable (due to or-patterns). In the absence of - /// or-patterns this will always be either `Empty` (the whole pattern is unreachable) or `Full` - /// (the whole pattern is reachable). - NoWitnesses(SubPatSet<'p, 'tcx>), + /// If we don't care about witnesses, simply remember if the pattern was useful. + NoWitnesses { useful: bool }, /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole /// pattern is unreachable. - WithWitnesses(Vec>), + WithWitnesses(Vec>), } impl<'p, 'tcx> Usefulness<'p, 'tcx> { fn new_useful(preference: ArmType) -> Self { match preference { + // A single (empty) witness of reachability. FakeExtraWildcard => WithWitnesses(vec![Witness(vec![])]), - RealArm => NoWitnesses(SubPatSet::full()), + RealArm => NoWitnesses { useful: true }, } } fn new_not_useful(preference: ArmType) -> Self { match preference { FakeExtraWildcard => WithWitnesses(vec![]), - RealArm => NoWitnesses(SubPatSet::empty()), + RealArm => NoWitnesses { useful: false }, } } fn is_useful(&self) -> bool { match self { - Usefulness::NoWitnesses(set) => !set.is_empty(), + Usefulness::NoWitnesses { useful } => *useful, Usefulness::WithWitnesses(witnesses) => !witnesses.is_empty(), } } @@ -909,33 +555,10 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { (WithWitnesses(_), WithWitnesses(o)) if o.is_empty() => {} (WithWitnesses(s), WithWitnesses(o)) if s.is_empty() => *self = WithWitnesses(o), (WithWitnesses(s), WithWitnesses(o)) => s.extend(o), - (NoWitnesses(s), NoWitnesses(o)) => s.union(o), - _ => unreachable!(), - } - } - - /// When trying several branches and each returns a `Usefulness`, we need to combine the - /// results together. - fn merge(pref: ArmType, usefulnesses: impl Iterator) -> Self { - let mut ret = Self::new_not_useful(pref); - for u in usefulnesses { - ret.extend(u); - if let NoWitnesses(subpats) = &ret { - if subpats.is_full() { - // Once we reach the full set, more unions won't change the result. - return ret; - } + (NoWitnesses { useful: s_useful }, NoWitnesses { useful: o_useful }) => { + *s_useful = *s_useful || o_useful } - } - ret - } - - /// After calculating the usefulness for a branch of an or-pattern, call this to make this - /// usefulness mergeable with those from the other branches. - fn unsplit_or_pat(self, alt_id: usize, alt_count: usize, pat: &'p Pat<'tcx>) -> Self { - match self { - NoWitnesses(subpats) => NoWitnesses(subpats.unsplit_or_pat(alt_id, alt_count, pat)), - WithWitnesses(_) => bug!(), + _ => unreachable!(), } } @@ -947,10 +570,10 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { pcx: PatCtxt<'_, 'p, 'tcx>, matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors ctor: &Constructor<'tcx>, - ctor_wild_subpatterns: &Fields<'p, 'tcx>, ) -> Self { match self { - WithWitnesses(witnesses) if witnesses.is_empty() => WithWitnesses(witnesses), + NoWitnesses { .. } => self, + WithWitnesses(ref witnesses) if witnesses.is_empty() => self, WithWitnesses(witnesses) => { let new_witnesses = if let Constructor::Missing { .. } = ctor { // We got the special `Missing` constructor, so each of the missing constructors @@ -958,22 +581,18 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { let new_patterns = if pcx.is_non_exhaustive { // Here we don't want the user to try to list all variants, we want them to add // a wildcard, so we only suggest that. - vec![ - Fields::wildcards(pcx, &Constructor::NonExhaustive) - .apply(pcx, &Constructor::NonExhaustive), - ] + vec![DeconstructedPat::wildcard(pcx.ty)] } else { let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, matrix.head_ctors(pcx.cx)); + split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); // Construct for each missing constructor a "wild" version of this // constructor, that matches everything that can be built with // it. For example, if `ctor` is a `Constructor::Variant` for // `Option::Some`, we get the pattern `Some(_)`. split_wildcard .iter_missing(pcx) - .map(|missing_ctor| { - Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor) - }) + .cloned() + .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) .collect() }; @@ -981,21 +600,25 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { .into_iter() .flat_map(|witness| { new_patterns.iter().map(move |pat| { - let mut witness = witness.clone(); - witness.0.push(pat.clone()); - witness + Witness( + witness + .0 + .iter() + .chain(once(pat)) + .map(DeconstructedPat::clone_and_forget_reachability) + .collect(), + ) }) }) .collect() } else { witnesses .into_iter() - .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns)) + .map(|witness| witness.apply_constructor(pcx, &ctor)) .collect() }; WithWitnesses(new_witnesses) } - NoWitnesses(subpats) => NoWitnesses(subpats.unspecialize(ctor_wild_subpatterns.len())), } } } @@ -1039,12 +662,12 @@ enum ArmType { /// `Witness(vec![Pair(Some(_), true)])` /// /// The final `Pair(Some(_), true)` is then the resulting witness. -#[derive(Clone, Debug)] -crate struct Witness<'tcx>(Vec>); +#[derive(Debug)] +crate struct Witness<'p, 'tcx>(Vec>); -impl<'tcx> Witness<'tcx> { +impl<'p, 'tcx> Witness<'p, 'tcx> { /// Asserts that the witness contains a single pattern, and returns it. - fn single_pattern(self) -> Pat<'tcx> { + fn single_pattern(self) -> DeconstructedPat<'p, 'tcx> { assert_eq!(self.0.len(), 1); self.0.into_iter().next().unwrap() } @@ -1062,17 +685,13 @@ impl<'tcx> Witness<'tcx> { /// /// left_ty: struct X { a: (bool, &'static str), b: usize} /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } - fn apply_constructor<'p>( - mut self, - pcx: PatCtxt<'_, 'p, 'tcx>, - ctor: &Constructor<'tcx>, - ctor_wild_subpatterns: &Fields<'p, 'tcx>, - ) -> Self { + fn apply_constructor(mut self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Self { let pat = { let len = self.0.len(); - let arity = ctor_wild_subpatterns.len(); + let arity = ctor.arity(pcx); let pats = self.0.drain((len - arity)..).rev(); - ctor_wild_subpatterns.replace_fields(pcx.cx, pats).apply(pcx, ctor) + let fields = Fields::from_iter(pcx.cx, pats); + DeconstructedPat::new(ctor.clone(), fields, pcx.ty, DUMMY_SP) }; self.0.push(pat); @@ -1090,9 +709,9 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>( scrut_ty: Ty<'tcx>, sp: Span, hir_id: HirId, - witnesses: Vec>, + witnesses: Vec>, ) { - let joined_patterns = joined_uncovered_patterns(&witnesses); + let joined_patterns = joined_uncovered_patterns(cx, &witnesses); cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| { let mut lint = build.build("some variants are not matched explicitly"); lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); @@ -1162,57 +781,52 @@ fn is_useful<'p, 'tcx>( assert!(rows.iter().all(|r| r.len() == v.len())); - // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476). - let ty = matrix.heads().next().map_or(v.head().ty, |r| r.ty); + let ty = v.head().ty(); let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); - let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level, is_non_exhaustive }; + let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; // If the first pattern is an or-pattern, expand it. - let ret = if is_or_pat(v.head()) { + let mut ret = Usefulness::new_not_useful(witness_preference); + if v.head().is_or_pat() { debug!("expanding or-pattern"); - let v_head = v.head(); - let vs: Vec<_> = v.expand_or_pat().collect(); - let alt_count = vs.len(); // We try each or-pattern branch in turn. let mut matrix = matrix.clone(); - let usefulnesses = vs.into_iter().enumerate().map(|(i, v)| { + for v in v.expand_or_pat() { let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false); + ret.extend(usefulness); // If pattern has a guard don't add it to the matrix. if !is_under_guard { // We push the already-seen patterns into the matrix in order to detect redundant // branches like `Some(_) | Some(0)`. matrix.push(v); } - usefulness.unsplit_or_pat(i, alt_count, v_head) - }); - Usefulness::merge(witness_preference, usefulnesses) + } } else { - let v_ctor = v.head_ctor(cx); + let v_ctor = v.head().ctor(); if let Constructor::IntRange(ctor_range) = &v_ctor { // Lint on likely incorrect range patterns (#63987) ctor_range.lint_overlapping_range_endpoints( pcx, - matrix.head_ctors_and_spans(cx), + matrix.heads(), matrix.column_count().unwrap_or(0), hir_id, ) } // We split the head constructor of `v`. - let split_ctors = v_ctor.split(pcx, matrix.head_ctors(cx)); + let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); let is_non_exhaustive_and_wild = is_non_exhaustive && v_ctor.is_wildcard(); // For each constructor, we compute whether there's a value that starts with it that would // witness the usefulness of `v`. let start_matrix = &matrix; - let usefulnesses = split_ctors.into_iter().map(|ctor| { + for ctor in split_ctors { debug!("specialize({:?})", ctor); // We cache the result of `Fields::wildcards` because it is used a lot. - let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); - let spec_matrix = - start_matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); - let v = v.pop_head_constructor(&ctor_wild_subpatterns); + let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); + let v = v.pop_head_constructor(cx, &ctor); let usefulness = is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false); + let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor); // When all the conditions are met we have a match with a `non_exhaustive` enum // that has the potential to trigger the `non_exhaustive_omitted_patterns` lint. @@ -1229,29 +843,31 @@ fn is_useful<'p, 'tcx>( { let patterns = { let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, matrix.head_ctors(pcx.cx)); + split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); // Construct for each missing constructor a "wild" version of this // constructor, that matches everything that can be built with // it. For example, if `ctor` is a `Constructor::Variant` for // `Option::Some`, we get the pattern `Some(_)`. split_wildcard .iter_missing(pcx) - // Filter out the `Constructor::NonExhaustive` variant it's meaningless - // to our lint + // Filter out the `NonExhaustive` because we want to list only real + // variants. .filter(|c| !c.is_non_exhaustive()) - .map(|missing_ctor| { - Fields::wildcards(pcx, missing_ctor).apply(pcx, missing_ctor) - }) + .cloned() + .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) .collect::>() }; lint_non_exhaustive_omitted_patterns(pcx.cx, pcx.ty, pcx.span, hir_id, patterns); } - usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns) - }); - Usefulness::merge(witness_preference, usefulnesses) - }; + ret.extend(usefulness); + } + } + + if ret.is_useful() { + v.head().set_reachable(); + } debug!(?ret); ret @@ -1261,7 +877,7 @@ fn is_useful<'p, 'tcx>( #[derive(Clone, Copy)] crate struct MatchArm<'p, 'tcx> { /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`. - crate pat: &'p Pat<'tcx>, + crate pat: &'p DeconstructedPat<'p, 'tcx>, crate hir_id: HirId, crate has_guard: bool, } @@ -1283,7 +899,7 @@ crate struct UsefulnessReport<'p, 'tcx> { crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>, /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of /// exhaustiveness. - crate non_exhaustiveness_witnesses: Vec>, + crate non_exhaustiveness_witnesses: Vec>, } /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which @@ -1303,27 +919,25 @@ crate fn compute_match_usefulness<'p, 'tcx>( .copied() .map(|arm| { let v = PatStack::from_pattern(arm.pat); - let usefulness = is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true); + is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true); if !arm.has_guard { matrix.push(v); } - let reachability = match usefulness { - NoWitnesses(subpats) if subpats.is_empty() => Reachability::Unreachable, - NoWitnesses(subpats) => { - Reachability::Reachable(subpats.list_unreachable_spans().unwrap()) - } - WithWitnesses(..) => bug!(), + let reachability = if arm.pat.is_reachable() { + Reachability::Reachable(arm.pat.unreachable_spans()) + } else { + Reachability::Unreachable }; (arm, reachability) }) .collect(); - let wild_pattern = cx.pattern_arena.alloc(Pat::wildcard_from_ty(scrut_ty)); + let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty)); let v = PatStack::from_pattern(wild_pattern); let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, scrut_hir_id, false, true); let non_exhaustiveness_witnesses = match usefulness { WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(), - NoWitnesses(_) => bug!(), + NoWitnesses { .. } => bug!(), }; UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses } } diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 81d84f80ad4c1..158ba1b942528 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -169,6 +169,7 @@ where } mir::Rvalue::Cast(..) + | mir::Rvalue::ShallowInitBox(..) | mir::Rvalue::Use(..) | mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::Repeat(..) diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 0039d3188d57a..3e2548845e20f 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -11,6 +11,37 @@ use crate::{AnalysisDomain, Backward, GenKill, GenKillAnalysis}; /// exist. See [this `mir-dataflow` test][flow-test] for an example. You almost never want to use /// this analysis without also looking at the results of [`MaybeBorrowedLocals`]. /// +/// ## Field-(in)sensitivity +/// +/// As the name suggests, this analysis is field insensitive. If a projection of a variable `x` is +/// assigned to (e.g. `x.0 = 42`), it does not "define" `x` as far as liveness is concerned. In fact, +/// such an assignment is currently marked as a "use" of `x` in an attempt to be maximally +/// conservative. +/// +/// ## Enums and `SetDiscriminant` +/// +/// Assigning a literal value to an `enum` (e.g. `Option`), does not result in a simple +/// assignment of the form `_1 = /*...*/` in the MIR. For example, the following assignment to `x`: +/// +/// ``` +/// x = Some(4); +/// ``` +/// +/// compiles to this MIR +/// +/// ``` +/// ((_1 as Some).0: i32) = const 4_i32; +/// discriminant(_1) = 1; +/// ``` +/// +/// However, `MaybeLiveLocals` **does** mark `x` (`_1`) as "killed" after a statement like this. +/// That's because it treats the `SetDiscriminant` operation as a definition of `x`, even though +/// the writes that actually initialized the locals happened earlier. +/// +/// This makes `MaybeLiveLocals` unsuitable for certain classes of optimization normally associated +/// with a live variables analysis, notably dead-store elimination. It's a dirty hack, but it works +/// okay for the generator state transform (currently the main consumuer of this analysis). +/// /// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals /// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index 771ad90af28d6..474f4f2a79b2a 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -602,6 +602,7 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { type Idx = InitIndex; + #[instrument(skip(self, trans), level = "debug")] fn statement_effect( &self, trans: &mut impl GenKill, @@ -613,24 +614,19 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { let init_loc_map = &move_data.init_loc_map; let rev_lookup = &move_data.rev_lookup; - debug!( - "statement {:?} at loc {:?} initializes move_indexes {:?}", - stmt, location, &init_loc_map[location] - ); + debug!("initializes move_indexes {:?}", &init_loc_map[location]); trans.gen_all(init_loc_map[location].iter().copied()); if let mir::StatementKind::StorageDead(local) = stmt.kind { // End inits for StorageDead, so that an immutable variable can // be reinitialized on the next iteration of the loop. let move_path_index = rev_lookup.find_local(local); - debug!( - "stmt {:?} at loc {:?} clears the ever initialized status of {:?}", - stmt, location, &init_path_map[move_path_index] - ); + debug!("clears the ever initialized status of {:?}", init_path_map[move_path_index]); trans.kill_all(init_path_map[move_path_index].iter().copied()); } } + #[instrument(skip(self, trans, _terminator), level = "debug")] fn terminator_effect( &self, trans: &mut impl GenKill, @@ -640,10 +636,8 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { let (body, move_data) = (self.body, self.move_data()); let term = body[location.block].terminator(); let init_loc_map = &move_data.init_loc_map; - debug!( - "terminator {:?} at loc {:?} initializes move_indexes {:?}", - term, location, &init_loc_map[location] - ); + debug!(?term); + debug!("initializes move_indexes {:?}", init_loc_map[location]); trans.gen_all( init_loc_map[location] .iter() diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 72c4e27cbeabf..402391b87eaa9 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -2,7 +2,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(const_panic)] +#![cfg_attr(bootstrap, feature(const_panic))] #![feature(exact_size_is_empty)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 407ba73946301..e404b49ecb931 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -327,6 +327,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { Rvalue::Use(ref operand) | Rvalue::Repeat(ref operand, _) | Rvalue::Cast(_, ref operand, _) + | Rvalue::ShallowInitBox(ref operand, _) | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand), Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => { diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 699ec4bbff80f..f2b341593826b 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -1,6 +1,5 @@ -use core::slice::Iter; use rustc_data_structures::fx::FxHashMap; -use rustc_index::vec::{Enumerated, IndexVec}; +use rustc_index::vec::IndexVec; use rustc_middle::mir::*; use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; use rustc_span::Span; @@ -337,7 +336,9 @@ impl MovePathLookup { /// An enumerated iterator of `local`s and their associated /// `MovePathIndex`es. - pub fn iter_locals_enumerated(&self) -> Enumerated> { + pub fn iter_locals_enumerated( + &self, + ) -> impl DoubleEndedIterator + ExactSizeIterator { self.locals.iter_enumerated() } } diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index bde4e215a2a61..e85d74ef3eaef 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -19,6 +19,7 @@ rustc_index = { path = "../rustc_index" } rustc_middle = { path = "../rustc_middle" } rustc_const_eval = { path = "../rustc_const_eval" } rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } +rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 71b3a555587f7..17790ec91c8a3 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -723,6 +723,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | Rvalue::Repeat(..) | Rvalue::Len(..) | Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) | Rvalue::Discriminant(..) | Rvalue::NullaryOp(..) => {} } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index b9e3c058ad7ec..1c946bd2d8af2 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -21,7 +21,6 @@ use rustc_data_structures::sync::Lrc; use rustc_index::vec::IndexVec; use rustc_middle::hir; use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::ich::StableHashingContext; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::*; use rustc_middle::mir::dump_enabled; @@ -30,6 +29,7 @@ use rustc_middle::mir::{ TerminatorKind, }; use rustc_middle::ty::TyCtxt; +use rustc_query_system::ich::StableHashingContext; use rustc_span::def_id::DefId; use rustc_span::source_map::SourceMap; use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol}; diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index dd95f00142309..790d9243fbaec 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -967,6 +967,7 @@ impl<'tcx> Visitor<'tcx> for BorrowCollector { } Rvalue::Cast(..) + | Rvalue::ShallowInitBox(..) | Rvalue::Use(..) | Rvalue::Repeat(..) | Rvalue::Len(..) diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index d96a067fdda79..996c158c062fb 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type. fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option> { if let ty::PredicateKind::Trait(predicate) = bound { - if self.tcx.is_diagnostic_item(sym::pointer_trait, predicate.def_id()) { + if self.tcx.is_diagnostic_item(sym::Pointer, predicate.def_id()) { Some(predicate.trait_ref.self_ty()) } else { None diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 06366b6fc31d5..bc72e9d94a953 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -342,7 +342,7 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { let source_info = data.terminator().source_info; // We must assign the value first in case it gets declared dead below data.statements.extend(self.make_state(state_idx, v, source_info)); - let state = if let Some((resume, resume_arg)) = resume { + let state = if let Some((resume, mut resume_arg)) = resume { // Yield let state = 3 + self.suspension_points.len(); @@ -350,7 +350,8 @@ impl MutVisitor<'tcx> for TransformVisitor<'tcx> { // live across a yield. let resume_arg = if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) { - self.make_field(variant, idx, ty) + replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx); + resume_arg } else { resume_arg }; diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index d43528a1cf098..ee4e91ecb62b0 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -147,7 +147,7 @@ impl Inliner<'tcx> { self.check_mir_body(callsite, callee_body, callee_attrs)?; if !self.tcx.consider_optimizing(|| { - format!("Inline {:?} into {}", callee_body.span, callsite.callee) + format!("Inline {:?} into {:?}", callsite.callee, caller_body.source) }) { return Err("optimization fuel exhausted"); } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index bfd0de85438d1..9b11c8f0b24c0 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,7 +1,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] -#![feature(const_panic)] +#![cfg_attr(bootstrap, feature(const_panic))] #![feature(in_band_lifetimes)] #![feature(iter_zip)] #![feature(map_try_insert)] @@ -58,6 +58,7 @@ mod lower_intrinsics; mod lower_slice_len; mod match_branches; mod multiple_return_terminators; +mod normalize_array_len; mod nrvo; mod remove_noop_landing_pads; mod remove_storage_markers; @@ -133,7 +134,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet { let mut set = FxHashSet::default(); // All body-owners have MIR associated with them. - set.extend(tcx.body_owners()); + set.extend(tcx.hir().body_owners()); // Additionally, tuple struct/variant constructors have MIR, but // they don't have a BodyId, so we need to build them separately. @@ -160,9 +161,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet { NestedVisitorMap::None } } - tcx.hir() - .krate() - .visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor()); + tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor()); set } @@ -490,6 +489,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // machine than on MIR with async primitives. let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[ &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, &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"), diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs new file mode 100644 index 0000000000000..60e71130cd1db --- /dev/null +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -0,0 +1,287 @@ +//! 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::MirPass; +use rustc_data_structures::fx::FxIndexMap; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::IndexVec; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, TyCtxt}; + +const MAX_NUM_BLOCKS: usize = 800; +const MAX_NUM_LOCALS: usize = 3000; + +pub struct NormalizeArrayLen; + +impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.mir_opt_level() < 4 { + return; + } + + // 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; + } + normalize_array_len_calls(tcx, body) + } +} + +pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); + + // 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(); + } +} + +struct Patcher<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + patches_scratchpad: &'a FxIndexMap, + replacements_scratchpad: &'a mut FxIndexMap, + local_decls: &'a mut IndexVec>, + statement_idx: usize, +} + +impl<'a, 'tcx> Patcher<'a, 'tcx> { + fn patch_expand_statement( + &mut self, + statement: &mut Statement<'tcx>, + ) -> Option>> { + 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.clone()); + 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 (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") + } + } + + 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 (*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(); + } + _ => { + unreachable!("it's a bug in the implementation") + } + } + + self.statement_idx += 1; + + Some(statements.into_iter()) + } else { + self.statement_idx += 1; + None + } + } +} + +fn normalize_array_len_call<'tcx>( + tcx: TyCtxt<'tcx>, + block: &mut BasicBlockData<'tcx>, + local_decls: &mut IndexVec>, + interesting_locals: &BitSet, + state: &mut FxIndexMap, + patches_scratchpad: &mut FxIndexMap, + replacements_scratchpad: &mut FxIndexMap, +) { + 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 local = if let Some(local) = place.as_local() { local } else { return }; + match operand { + Operand::Copy(place) | Operand::Move(place) => { + let operand_local = + if let Some(local) = place.local_or_deref_local() { + 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( + ty::RegionKind::ReErased, + operand_ty, + Mutability::Not, + ), + ty::Ref(ty::RegionKind::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 local = if let Some(local) = place.local_or_deref_local() { + 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); + } + } + } + _ => {} + } + } + + let mut patcher = Patcher { + tcx, + patches_scratchpad: &*patches_scratchpad, + replacements_scratchpad, + local_decls, + statement_idx: 0, + }; + + block.expand_statements(|st| patcher.patch_expand_statement(st)); +} diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 1945e551485d8..3002e7041b024 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -204,6 +204,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< | Rvalue::AddressOf(_, _) | Rvalue::Cast(_, Operand::Constant(_), _) | Rvalue::NullaryOp(_, _) + | Rvalue::ShallowInitBox(_, _) | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true, // These rvalues make things ambiguous @@ -301,6 +302,7 @@ fn find_determining_place<'tcx>( | Rvalue::ThreadLocalRef(_) | Rvalue::AddressOf(_, _) | Rvalue::NullaryOp(_, _) + | Rvalue::ShallowInitBox(_, _) | Rvalue::UnaryOp(_, Operand::Constant(_)) | Rvalue::Cast(_, Operand::Constant(_), _) => return None, diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 4d350fc87cb3a..f2ea5fedc625c 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -53,7 +53,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' ty::InstanceDef::ReifyShim(def_id) => { build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } - ty::InstanceDef::ClosureOnceShim { call_once: _ } => { + ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => { let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); let call_mut = tcx .associated_items(fn_mut) diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs index fd36671b36f54..e436d73226a55 100644 --- a/compiler/rustc_mir_transform/src/simplify_try.rs +++ b/compiler/rustc_mir_transform/src/simplify_try.rs @@ -544,6 +544,12 @@ 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.debugging_opts.unsound_mir_opts { + return; + } + trace!("Running SimplifyBranchSame on {:?}", body.source); let finder = SimplifyBranchSameOptimizationFinder { body, tcx }; let opts = finder.find(); @@ -706,12 +712,24 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { 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.variants[*variant_index].fields.is_empty(); if !variant_is_fieldless { trace!("NO: variant {:?} was not fieldless", variant_index); @@ -740,20 +758,28 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { ( StatementKind::Assign(box (_, rhs)), StatementKind::SetDiscriminant { place, variant_index }, - ) - // we need to make sure that the switch value that targets the bb with SetDiscriminant (y), is the same as the variant index - if Some(variant_index.index() as u128) == y_target_and_value.value => { + ) if y_target_and_value.value.is_some() => { // choose basic block of x, as that has the assign - helper(rhs, place, variant_index, x_target_and_value.target) + helper( + rhs, + place, + variant_index, + y_target_and_value.value.unwrap(), + x_target_and_value.target, + ) } ( StatementKind::SetDiscriminant { place, variant_index }, StatementKind::Assign(box (_, rhs)), - ) - // we need to make sure that the switch value that targets the bb with SetDiscriminant (x), is the same as the variant index - if Some(variant_index.index() as u128) == x_target_and_value.value => { + ) if x_target_and_value.value.is_some() => { // choose basic block of y, as that has the assign - helper(rhs, place, variant_index, y_target_and_value.target) + 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); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1e39b1bd5e80e..f06426308a228 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -330,7 +330,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec Parser<'a> { self.struct_span_err(sp, &msg) .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl) .emit(); - return Ok(false); + return Ok(true); } else if self.look_ahead(0, |t| { t == &token::CloseDelim(token::Brace) || ( @@ -295,7 +295,7 @@ impl<'a> Parser<'a> { .span_label(self.token.span, "unexpected token") .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl) .emit(); - return Ok(false); + return Ok(true); } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index fe0468c69568a..79f46be73f6c2 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1568,6 +1568,20 @@ impl<'a> Parser<'a> { pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { self.parse_opt_lit().ok_or_else(|| { + if let token::Interpolated(inner) = &self.token.kind { + let expr = match inner.as_ref() { + token::NtExpr(expr) => Some(expr), + token::NtLiteral(expr) => Some(expr), + _ => None, + }; + if let Some(expr) = expr { + if matches!(expr.kind, ExprKind::Err) { + self.diagnostic() + .delay_span_bug(self.token.span, &"invalid interpolated expression"); + return self.diagnostic().struct_dummy(); + } + } + } let msg = format!("unexpected token: {}", super::token_descr(&self.token)); self.struct_span_err(self.token.span, &msg) }) @@ -2308,7 +2322,24 @@ impl<'a> Parser<'a> { None }; let arrow_span = this.token.span; - this.expect(&token::FatArrow)?; + if let Err(mut err) = this.expect(&token::FatArrow) { + // We might have a `=>` -> `=` or `->` typo (issue #89396). + if TokenKind::FatArrow + .similar_tokens() + .map_or(false, |similar_tokens| similar_tokens.contains(&this.token.kind)) + { + err.span_suggestion( + this.token.span, + "try using a fat arrow here", + "=>".to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + this.bump(); + } else { + return Err(err); + } + } let arm_start_span = this.token.span; let expr = this.parse_expr_res(Restrictions::STMT_EXPR, None).map_err(|mut err| { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 0e2222bf84093..624390a406ff2 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1547,6 +1547,20 @@ impl<'a> Parser<'a> { self.expect(&token::Not)?; // `!` let ident = self.parse_ident()?; + + if self.eat(&token::Not) { + // Handle macro_rules! foo! + let span = self.prev_token.span; + self.struct_span_err(span, "macro names aren't followed by a `!`") + .span_suggestion( + span, + "remove the `!`", + "".to_owned(), + Applicability::MachineApplicable, + ) + .emit(); + } + let body = self.parse_mac_args()?; self.eat_semi_for_macro_if_needed(&body); self.complain_if_pub_macro(vis, true); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 953c6915068af..c7d080a80fe6f 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -495,20 +495,28 @@ impl<'a> Parser<'a> { None => { let after_eq = eq.shrink_to_hi(); let before_next = self.token.span.shrink_to_lo(); - self.struct_span_err(after_eq.to(before_next), "missing type to the right of `=`") - .span_suggestion( + let mut err = self + .struct_span_err(after_eq.to(before_next), "missing type to the right of `=`"); + if matches!(self.token.kind, token::Comma | token::Gt) { + err.span_suggestion( self.sess.source_map().next_point(eq).to(before_next), "to constrain the associated type, add a type after `=`", " TheType".to_string(), Applicability::HasPlaceholders, - ) - .span_suggestion( + ); + err.span_suggestion( eq.to(before_next), &format!("remove the `=` if `{}` is a type", ident), String::new(), Applicability::MaybeIncorrect, ) - .emit(); + } else { + err.span_label( + self.token.span, + &format!("expected type, found {}", super::token_descr(&self.token)), + ) + }; + return Err(err); } } Ok(self.mk_ty(span, ast::TyKind::Err)) @@ -572,6 +580,25 @@ impl<'a> Parser<'a> { return self.recover_const_arg(start, err).map(Some); } } + } else if self.eat_keyword_noexpect(kw::Const) { + // Detect and recover from the old, pre-RFC2000 syntax for const generics. + let mut err = self.struct_span_err( + start, + "expected lifetime, type, or constant, found keyword `const`", + ); + if self.check_const_arg() { + err.span_suggestion_verbose( + start.until(self.token.span), + "the `const` keyword is only needed in the definition of the type", + String::new(), + Applicability::MaybeIncorrect, + ); + err.emit(); + GenericArg::Const(self.parse_const_arg()?) + } else { + let after_kw_const = self.token.span; + return self.recover_const_arg(after_kw_const, err).map(Some); + } } else { return Ok(None); }; diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 67695dc285092..2aa20d02c8830 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -4,7 +4,7 @@ use crate::parse_in; use rustc_ast::tokenstream::{DelimSpan, TokenTree}; use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind}; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP}; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_session::parse::ParseSess; @@ -91,69 +91,11 @@ pub fn check_builtin_attribute( // Some special attributes like `cfg` must be checked // before the generic check, so we skip them here. let should_skip = |name| name == sym::cfg; - // Some of previously accepted forms were used in practice, - // report them as warnings for now. - let should_warn = |name| { - name == sym::doc - || name == sym::ignore - || name == sym::inline - || name == sym::link - || name == sym::test - || name == sym::bench - }; match parse_meta(sess, attr) { Ok(meta) => { if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) { - let error_msg = format!("malformed `{}` attribute input", name); - let mut msg = "attribute must be of the form ".to_owned(); - let mut suggestions = vec![]; - let mut first = true; - if template.word { - first = false; - let code = format!("#[{}]", name); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.list { - if !first { - msg.push_str(" or "); - } - first = false; - let code = format!("#[{}({})]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.name_value_str { - if !first { - msg.push_str(" or "); - } - let code = format!("#[{} = \"{}\"]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if should_warn(name) { - sess.buffer_lint( - &ILL_FORMED_ATTRIBUTE_INPUT, - meta.span, - ast::CRATE_NODE_ID, - &msg, - ); - } else { - sess.span_diagnostic - .struct_span_err(meta.span, &error_msg) - .span_suggestions( - meta.span, - if suggestions.len() == 1 { - "must be of the form" - } else { - "the following are the possible correct uses" - }, - suggestions.into_iter(), - Applicability::HasPlaceholders, - ) - .emit(); - } + emit_malformed_attribute(sess, attr, name, template); } } Err(mut err) => { @@ -161,3 +103,74 @@ pub fn check_builtin_attribute( } } } + +fn emit_malformed_attribute( + sess: &ParseSess, + attr: &Attribute, + name: Symbol, + template: AttributeTemplate, +) { + // Some of previously accepted forms were used in practice, + // report them as warnings for now. + let should_warn = |name| { + matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench) + }; + + let error_msg = format!("malformed `{}` attribute input", name); + let mut msg = "attribute must be of the form ".to_owned(); + let mut suggestions = vec![]; + let mut first = true; + let inner = if attr.style == ast::AttrStyle::Inner { "!" } else { "" }; + if template.word { + first = false; + let code = format!("#{}[{}]", inner, name); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.list { + if !first { + msg.push_str(" or "); + } + first = false; + let code = format!("#{}[{}({})]", inner, name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.name_value_str { + if !first { + msg.push_str(" or "); + } + let code = format!("#{}[{} = \"{}\"]", inner, name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if should_warn(name) { + sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, attr.span, ast::CRATE_NODE_ID, &msg); + } else { + sess.span_diagnostic + .struct_span_err(attr.span, &error_msg) + .span_suggestions( + attr.span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are the possible correct uses" + }, + suggestions.into_iter(), + Applicability::HasPlaceholders, + ) + .emit(); + } +} + +pub fn emit_fatal_malformed_builtin_attribute( + sess: &ParseSess, + attr: &Attribute, + name: Symbol, +) -> ! { + let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2; + emit_malformed_attribute(sess, attr, name, template); + // This is fatal, otherwise it will likely cause a cascade of other errors + // (and an error here is expected to be very rare). + FatalError.raise() +} diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3e59fc4f55159..1815302101f0e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem}; -use rustc_data_structures::stable_set::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; @@ -66,6 +66,7 @@ impl CheckAttrVisitor<'tcx> { target: Target, item: Option>, ) { + let mut doc_aliases = FxHashMap::default(); let mut is_valid = true; let mut specified_inline = None; let mut seen = FxHashSet::default(); @@ -79,7 +80,13 @@ impl CheckAttrVisitor<'tcx> { sym::track_caller => { self.check_track_caller(hir_id, &attr.span, attrs, span, target) } - sym::doc => self.check_doc_attrs(attr, hir_id, target, &mut specified_inline), + sym::doc => self.check_doc_attrs( + attr, + hir_id, + target, + &mut specified_inline, + &mut doc_aliases, + ), sym::no_link => self.check_no_link(hir_id, &attr, span, target), sym::export_name => self.check_export_name(hir_id, &attr, span, target), sym::rustc_layout_scalar_valid_range_start @@ -512,6 +519,7 @@ impl CheckAttrVisitor<'tcx> { hir_id: HirId, target: Target, is_list: bool, + aliases: &mut FxHashMap, ) -> bool { let tcx = self.tcx; let err_fn = move |span: Span, msg: &str| { @@ -582,17 +590,38 @@ impl CheckAttrVisitor<'tcx> { if &*item_name.as_str() == doc_alias { return err_fn(meta.span(), "is the same as the item's name"); } + let span = meta.span(); + if let Err(entry) = aliases.try_insert(doc_alias.to_owned(), span) { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| { + lint.build("doc alias is duplicated") + .span_label(*entry.entry.get(), "first defined here") + .emit(); + }); + } true } - fn check_doc_alias(&self, meta: &NestedMetaItem, hir_id: HirId, target: Target) -> bool { + fn check_doc_alias( + &self, + meta: &NestedMetaItem, + hir_id: HirId, + target: Target, + aliases: &mut FxHashMap, + ) -> bool { if let Some(values) = meta.meta_item_list() { let mut errors = 0; for v in values { match v.literal() { Some(l) => match l.kind { LitKind::Str(s, _) => { - if !self.check_doc_alias_value(v, &s.as_str(), hir_id, target, true) { + if !self.check_doc_alias_value( + v, + &s.as_str(), + hir_id, + target, + true, + aliases, + ) { errors += 1; } } @@ -621,7 +650,7 @@ impl CheckAttrVisitor<'tcx> { } errors == 0 } else if let Some(doc_alias) = meta.value_str().map(|s| s.to_string()) { - self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false) + self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false, aliases) } else { self.tcx .sess @@ -858,6 +887,7 @@ impl CheckAttrVisitor<'tcx> { hir_id: HirId, target: Target, specified_inline: &mut Option<(bool, Span)>, + aliases: &mut FxHashMap, ) -> bool { let mut is_valid = true; @@ -867,7 +897,7 @@ impl CheckAttrVisitor<'tcx> { match i_meta.name_or_empty() { sym::alias if !self.check_attr_not_crate_level(&meta, hir_id, "alias") - || !self.check_doc_alias(&meta, hir_id, target) => + || !self.check_doc_alias(&meta, hir_id, target, aliases) => { is_valid = false } @@ -908,6 +938,7 @@ impl CheckAttrVisitor<'tcx> { // plugins: removed, but rustdoc warns about it itself sym::alias | sym::cfg + | sym::cfg_hide | sym::hidden | sym::html_favicon_url | sym::html_logo_url diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 0a3093757166a..772791324019a 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -243,46 +243,15 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { /// will be ignored for the purposes of dead code analysis (see PR #85200 /// for discussion). fn should_ignore_item(&self, def_id: DefId) -> bool { - if !self.tcx.has_attr(def_id, sym::automatically_derived) - && !self - .tcx - .impl_of_method(def_id) - .map_or(false, |impl_id| self.tcx.has_attr(impl_id, sym::automatically_derived)) - { - return false; - } - - let has_attr = |def_id| self.tcx.has_attr(def_id, sym::rustc_trivial_field_reads); - - if has_attr(def_id) { - return true; - } - if let Some(impl_of) = self.tcx.impl_of_method(def_id) { - if has_attr(impl_of) { - return true; + if !self.tcx.has_attr(impl_of, sym::automatically_derived) { + return false; } if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) { - if has_attr(trait_of) { + if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) { return true; } - - if let Some(method_ident) = self.tcx.opt_item_name(def_id) { - if let Some(trait_method) = self - .tcx - .associated_items(trait_of) - .find_by_name_and_kind(self.tcx, method_ident, ty::AssocKind::Fn, trait_of) - { - if has_attr(trait_method.def_id) { - return true; - } - } - } - } - } else if let Some(trait_of) = self.tcx.trait_of_item(def_id) { - if has_attr(trait_of) { - return true; } } @@ -291,10 +260,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn visit_node(&mut self, node: Node<'tcx>) { if let Some(item_def_id) = match node { - Node::Item(hir::Item { def_id, .. }) - | Node::ForeignItem(hir::ForeignItem { def_id, .. }) - | Node::TraitItem(hir::TraitItem { def_id, .. }) - | Node::ImplItem(hir::ImplItem { def_id, .. }) => Some(def_id.to_def_id()), + Node::ImplItem(hir::ImplItem { def_id, .. }) => Some(def_id.to_def_id()), _ => None, } { if self.should_ignore_item(item_def_id) { @@ -510,15 +476,14 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { // or // 2) We are not sure to be live or not // * Implementations of traits and trait methods -struct LifeSeeder<'k, 'tcx> { +struct LifeSeeder<'tcx> { worklist: Vec, - krate: &'k hir::Crate<'k>, tcx: TyCtxt<'tcx>, // see `MarkSymbolVisitor::struct_constructors` struct_constructors: FxHashMap, } -impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { +impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> { fn visit_item(&mut self, item: &hir::Item<'_>) { let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id()); if allow_dead_code { @@ -545,7 +510,7 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { self.worklist.push(item.def_id); } for impl_item_ref in items { - let impl_item = self.krate.impl_item(impl_item_ref.id); + let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); if of_trait.is_some() || has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id()) { @@ -589,7 +554,6 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { fn create_and_seed_worklist<'tcx>( tcx: TyCtxt<'tcx>, access_levels: &privacy::AccessLevels, - krate: &hir::Crate<'_>, ) -> (Vec, FxHashMap) { let worklist = access_levels .map @@ -604,9 +568,8 @@ fn create_and_seed_worklist<'tcx>( .collect::>(); // Seed implemented trait items - let mut life_seeder = - LifeSeeder { worklist, krate, tcx, struct_constructors: Default::default() }; - krate.visit_all_item_likes(&mut life_seeder); + let mut life_seeder = LifeSeeder { worklist, tcx, struct_constructors: Default::default() }; + tcx.hir().visit_all_item_likes(&mut life_seeder); (life_seeder.worklist, life_seeder.struct_constructors) } @@ -614,9 +577,8 @@ fn create_and_seed_worklist<'tcx>( fn find_live<'tcx>( tcx: TyCtxt<'tcx>, access_levels: &privacy::AccessLevels, - krate: &hir::Crate<'_>, ) -> FxHashSet { - let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate); + let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels); let mut symbol_visitor = MarkSymbolVisitor { worklist, tcx, @@ -834,8 +796,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> { pub fn check_crate(tcx: TyCtxt<'_>) { let access_levels = &tcx.privacy_access_levels(()); - let krate = tcx.hir().krate(); - let live_symbols = find_live(tcx, access_levels, krate); + let live_symbols = find_live(tcx, access_levels); let mut visitor = DeadVisitor { tcx, live_symbols }; tcx.hir().walk_toplevel_module(&mut visitor); } diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 3f12a744be0e8..30a0071f0f2e5 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -10,8 +10,8 @@ //! * Compiler internal types like `Ty` and `TyCtxt` use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -19,9 +19,8 @@ use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; struct DiagnosticItemCollector<'tcx> { - // items from this crate - items: FxHashMap, tcx: TyCtxt<'tcx>, + diagnostic_items: DiagnosticItems, } impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { @@ -44,7 +43,7 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { impl<'tcx> DiagnosticItemCollector<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> { - DiagnosticItemCollector { tcx, items: Default::default() } + DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() } } fn observe_item(&mut self, def_id: LocalDefId) { @@ -52,19 +51,14 @@ impl<'tcx> DiagnosticItemCollector<'tcx> { let attrs = self.tcx.hir().attrs(hir_id); if let Some(name) = extract(attrs) { // insert into our table - collect_item(self.tcx, &mut self.items, name, def_id.to_def_id()); + collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id()); } } } -fn collect_item( - tcx: TyCtxt<'_>, - items: &mut FxHashMap, - name: Symbol, - item_def_id: DefId, -) { - // Check for duplicates. - if let Some(original_def_id) = items.insert(name, item_def_id) { +fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item_def_id: DefId) { + items.id_to_name.insert(item_def_id, name); + if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) { if original_def_id != item_def_id { let mut err = match tcx.hir().span_if_local(item_def_id) { Some(span) => tcx.sess.struct_span_err( @@ -98,31 +92,31 @@ fn extract(attrs: &[ast::Attribute]) -> Option { } /// Traverse and collect the diagnostic items in the current -fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap { +fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems { assert_eq!(cnum, LOCAL_CRATE); // Initialize the collector. let mut collector = DiagnosticItemCollector::new(tcx); // Collect diagnostic items in this crate. - tcx.hir().krate().visit_all_item_likes(&mut collector); + tcx.hir().visit_all_item_likes(&mut collector); - collector.items + collector.diagnostic_items } /// Traverse and collect all the diagnostic items in all crates. -fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashMap { +fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> DiagnosticItems { // Initialize the collector. - let mut collector = FxHashMap::default(); + let mut items = DiagnosticItems::default(); // Collect diagnostic items in other crates. for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { - for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() { - collect_item(tcx, &mut collector, name, def_id); + for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id { + collect_item(tcx, &mut items, name, def_id); } } - collector + items } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index e881a855bbcfa..63f9b3ed6b15c 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,6 +1,6 @@ use rustc_ast::entry::EntryPointType; use rustc_errors::struct_span_err; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID}; use rustc_middle::hir::map::Map; @@ -68,7 +68,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { non_main_fns: Vec::new(), }; - tcx.hir().krate().visit_all_item_likes(&mut ctxt); + tcx.hir().visit_all_item_likes(&mut ctxt); configure_main(tcx, &ctxt) } @@ -183,7 +183,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(De } fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { - let sp = tcx.hir().krate().module().inner; + let sp = tcx.def_span(CRATE_DEF_ID); if *tcx.sess.parse_sess.reached_eof.borrow() { // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about // the missing `fn main()` then as it might have been hidden inside an unclosed block. diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 77ff8dc5b4aee..388c33917c64f 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -10,9 +10,6 @@ use crate::check_attr::target_from_impl_item; use crate::weak_lang_items; -use rustc_middle::middle::cstore::ExternCrate; -use rustc_middle::ty::TyCtxt; - use rustc_ast::Attribute; use rustc_errors::{pluralize, struct_span_err}; use rustc_hir as hir; @@ -20,6 +17,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS}; use rustc_hir::{HirId, LangItem, LanguageItems, Target}; +use rustc_middle::ty::TyCtxt; +use rustc_session::cstore::ExternCrate; use rustc_span::Span; use rustc_middle::ty::query::Providers; @@ -262,7 +261,7 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { } // Collect lang items in this crate. - tcx.hir().krate().visit_all_item_likes(&mut collector); + tcx.hir().visit_all_item_likes(&mut collector); // Extract out the found lang items. let LanguageItemCollector { mut items, .. } = collector; diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index aa78fcfb4b373..558d8958b1358 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -12,7 +12,7 @@ use rustc_target::abi::{HasDataLayout, TargetDataLayout}; pub fn test_layout(tcx: TyCtxt<'_>) { if tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing layout - tcx.hir().krate().visit_all_item_likes(&mut LayoutTest { tcx }); + tcx.hir().visit_all_item_likes(&mut LayoutTest { tcx }); } } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index f583a5d58d540..4adec3c4f608d 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -9,8 +9,9 @@ #![feature(in_band_lifetimes)] #![feature(format_args_capture)] #![feature(iter_zip)] -#![feature(nll)] +#![feature(map_try_insert)] #![feature(min_specialization)] +#![feature(nll)] #![feature(try_blocks)] #![recursion_limit = "256"] diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 0d7abeba1a703..3d7a215754aca 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -265,12 +265,13 @@ impl IrMaps<'tcx> { self.capture_info_map.insert(hir_id, Rc::new(cs)); } - fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) { + fn collect_shorthand_field_ids(&self, pat: &hir::Pat<'tcx>) -> HirIdSet { // For struct patterns, take note of which fields used shorthand // (`x` rather than `x: x`). let mut shorthand_field_ids = HirIdSet::default(); let mut pats = VecDeque::new(); pats.push_back(pat); + while let Some(pat) = pats.pop_front() { use rustc_hir::PatKind::*; match &pat.kind { @@ -278,8 +279,10 @@ impl IrMaps<'tcx> { pats.extend(inner_pat.iter()); } Struct(_, fields, _) => { - let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id); - shorthand_field_ids.extend(ids); + let (short, not_short): (Vec<&_>, Vec<&_>) = + fields.iter().partition(|f| f.is_shorthand); + shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id)); + pats.extend(not_short.iter().map(|f| f.pat)); } Ref(inner_pat, _) | Box(inner_pat) => { pats.push_back(inner_pat); @@ -296,6 +299,12 @@ impl IrMaps<'tcx> { } } + return shorthand_field_ids; + } + + fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) { + let shorthand_field_ids = self.collect_shorthand_field_ids(pat); + pat.each_binding(|_, hir_id, _, ident| { self.add_live_node_for_node(hir_id, VarDefNode(ident.span, hir_id)); self.add_variable(Local(LocalInfo { @@ -373,15 +382,13 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { + let shorthand_field_ids = self.collect_shorthand_field_ids(param.pat); param.pat.each_binding(|_bm, hir_id, _x, ident| { let var = match param.pat.kind { - rustc_hir::PatKind::Struct(_, fields, _) => Local(LocalInfo { + rustc_hir::PatKind::Struct(..) => Local(LocalInfo { id: hir_id, name: ident.name, - is_shorthand: fields - .iter() - .find(|f| f.ident == ident) - .map_or(false, |f| f.is_shorthand), + is_shorthand: shorthand_field_ids.contains(&hir_id), }), _ => Param(hir_id, ident.name), }; diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 23f43233b79ca..bd1e9520ee9fe 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -427,7 +427,7 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet { access_levels, worklist: &mut reachable_context.worklist, }; - tcx.hir().krate().visit_all_item_likes(&mut collect_private_impl_items); + tcx.hir().visit_all_item_likes(&mut collect_private_impl_items); } // Step 2: Mark all symbols that the symbols on the worklist touch. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index d7c354aeb490f..8c9f04bef1376 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -906,11 +906,10 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let access_levels = &tcx.privacy_access_levels(()); if tcx.stability().staged_api[&LOCAL_CRATE] { - let krate = tcx.hir().krate(); let mut missing = MissingStabilityAnnotations { tcx, access_levels }; missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID)); tcx.hir().walk_toplevel_module(&mut missing); - krate.visit_all_item_likes(&mut missing.as_deep_visitor()); + tcx.hir().visit_all_item_likes(&mut missing.as_deep_visitor()); } let declared_lang_features = &tcx.features().declared_lang_features; diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 3a662a9bab2f6..c6c32e69aab77 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -33,7 +33,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem { let mut cx = Context { tcx, items }; - tcx.hir().krate().visit_all_item_likes(&mut cx.as_deep_visitor()); + tcx.hir().visit_all_item_likes(&mut cx.as_deep_visitor()); } verify(tcx, items); } @@ -66,8 +66,8 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { tcx.sess.err("`#[panic_handler]` function required, but not found"); } else if item == LangItem::Oom { if !tcx.features().default_alloc_error_handler { - tcx.sess.err("`#[alloc_error_handler]` function required, but not found."); - tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler."); + tcx.sess.err("`#[alloc_error_handler]` function required, but not found"); + tcx.sess.note_without_error("Use `#![feature(default_alloc_error_handler)]` for a default error handler"); } } else { tcx.sess.err(&format!("language item required, but not found: `{}`", name)); diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs index 51cf85f794b8a..c21075a443c0b 100644 --- a/compiler/rustc_plugin_impl/src/load.rs +++ b/compiler/rustc_plugin_impl/src/load.rs @@ -4,7 +4,7 @@ use crate::Registry; use rustc_ast::Crate; use rustc_errors::struct_span_err; use rustc_metadata::locator; -use rustc_middle::middle::cstore::MetadataLoader; +use rustc_session::cstore::MetadataLoader; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index e14f758ddae79..ae3a9c71c5968 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -470,7 +470,7 @@ impl EmbargoVisitor<'tcx> { let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); let attrs = self.tcx.hir().attrs(hir_id); - if attr::find_transparency(&attrs, md.macro_rules).0 != Transparency::Opaque { + if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque { return; } @@ -797,7 +797,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> { // Re-exports are handled in `visit_mod`. However, in order to avoid looping over // all of the items of a mod in `visit_mod` looking for use statements, we handle // making sure that intermediate use statements have their visibilities updated here. - hir::ItemKind::Use(ref path, _) => { + hir::ItemKind::Use(path, _) => { if item_level.is_some() { self.update_visibility_of_intermediate_use_statements(path.segments.as_ref()); } @@ -1099,11 +1099,11 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Struct(ref qpath, fields, ref base) = expr.kind { + if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap(); let variant = adt.variant_of_res(res); - if let Some(ref base) = *base { + if let Some(base) = *base { // If the expression uses FRU we need to make sure all the unmentioned fields // are checked for privacy (RFC 736). Rather than computing the set of // unmentioned fields, just check them all. @@ -1312,7 +1312,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { return; } match expr.kind { - hir::ExprKind::Assign(_, ref rhs, _) | hir::ExprKind::Match(ref rhs, ..) => { + hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => { // Do not report duplicate errors for `x = y` and `match x { ... }`. if self.check_expr_pat_type(rhs.hir_id, rhs.span) { return; @@ -1397,7 +1397,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { } fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { - if let Some(ref init) = local.init { + if let Some(init) = local.init { if self.check_expr_pat_type(init.hir_id, init.span) { // Do not report duplicate errors for `let x = y`. return; @@ -1474,7 +1474,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // .. and it corresponds to a private type in the AST (this returns // `None` for type parameters). match self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(did)) { - Some(Node::Item(ref item)) => !item.vis.node.is_pub(), + Some(Node::Item(item)) => !item.vis.node.is_pub(), Some(_) | None => false, } } else { @@ -1490,7 +1490,7 @@ impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) { if let hir::GenericBound::Trait(ref trait_ref, _) = *bound { - if self.path_is_private_type(&trait_ref.trait_ref.path) { + if self.path_is_private_type(trait_ref.trait_ref.path) { self.old_error_set.insert(trait_ref.trait_ref.hir_ref_id); } } @@ -1517,7 +1517,7 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a } fn visit_ty(&mut self, ty: &hir::Ty<'_>) { - if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = ty.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind { if self.inner.path_is_private_type(path) { self.contains_private = true; // Found what we're looking for, so let's stop working. @@ -1556,7 +1556,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // namespace (the contents have their own privacies). hir::ItemKind::ForeignMod { .. } => {} - hir::ItemKind::Trait(.., ref bounds, _) => { + hir::ItemKind::Trait(.., bounds, _) => { if !self.trait_is_public(item.def_id) { return; } @@ -1586,7 +1586,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { at_outer_type: true, outer_type_is_public_path: false, }; - visitor.visit_ty(&impl_.self_ty); + visitor.visit_ty(impl_.self_ty); self_contains_private = visitor.contains_private; self_is_public_path = visitor.outer_type_is_public_path; } @@ -1664,12 +1664,12 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { // // Those in 2. are warned via walk_generics and this // call here. - intravisit::walk_path(self, &tr.path); + intravisit::walk_path(self, tr.path); // Those in 3. are warned with this call. for impl_item_ref in impl_.items { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); - if let hir::ImplItemKind::TyAlias(ref ty) = impl_item.kind { + if let hir::ImplItemKind::TyAlias(ty) = impl_item.kind { self.visit_ty(ty); } } @@ -1739,7 +1739,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } hir::WherePredicate::RegionPredicate(_) => {} hir::WherePredicate::EqPredicate(eq_pred) => { - self.visit_ty(&eq_pred.rhs_ty); + self.visit_ty(eq_pred.rhs_ty); } } } @@ -1752,7 +1752,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { - if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = t.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = t.kind { if self.path_is_private_type(path) { self.old_error_set.insert(t.hir_id); } @@ -2189,11 +2189,9 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels { fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { let access_levels = tcx.privacy_access_levels(()); - let krate = tcx.hir().krate(); - let mut visitor = ObsoleteVisiblePrivateTypesVisitor { tcx, - access_levels: &access_levels, + access_levels, in_variant: false, old_error_set: Default::default(), }; @@ -2230,5 +2228,5 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id)) .collect(), }; - krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); + tcx.hir().visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index bb0e65111596c..e50a8c191ad40 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -20,10 +20,10 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::DiagnosticBuilder; use rustc_middle::dep_graph; -use rustc_middle::ich::StableHashingContext; use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values}; use rustc_middle::ty::query::{Providers, QueryEngine}; use rustc_middle::ty::{self, TyCtxt}; +use rustc_query_system::ich::StableHashingContext; use rustc_span::Span; #[macro_use] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 90a6ba474b405..b71a172203612 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -36,7 +36,6 @@ impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { impl HasDepContext for QueryCtxt<'tcx> { type DepKind = rustc_middle::dep_graph::DepKind; - type StableHashingContext = rustc_middle::ich::StableHashingContext<'tcx>; type DepContext = TyCtxt<'tcx>; #[inline] @@ -253,17 +252,17 @@ macro_rules! handle_cycle_error { $error.emit(); Value::from_cycle_error($tcx) }}; - ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{ + ([(fatal_cycle) $($rest:tt)*][$tcx:expr, $error:expr]) => {{ $error.emit(); $tcx.sess.abort_if_errors(); unreachable!() }}; - ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{ + ([(cycle_delay_bug) $($rest:tt)*][$tcx:expr, $error:expr]) => {{ $error.delay_as_bug(); Value::from_cycle_error($tcx) }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { - handle_cycle_error!([$($($modifiers)*)*][$($args)*]) + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + handle_cycle_error!([$($modifiers)*][$($args)*]) }; } @@ -271,11 +270,11 @@ macro_rules! is_anon { ([]) => {{ false }}; - ([anon $($rest:tt)*]) => {{ + ([(anon) $($rest:tt)*]) => {{ true }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => { - is_anon!([$($($modifiers)*)*]) + ([$other:tt $($modifiers:tt)*]) => { + is_anon!([$($modifiers)*]) }; } @@ -283,11 +282,11 @@ macro_rules! is_eval_always { ([]) => {{ false }}; - ([eval_always $($rest:tt)*]) => {{ + ([(eval_always) $($rest:tt)*]) => {{ true }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => { - is_eval_always!([$($($modifiers)*)*]) + ([$other:tt $($modifiers:tt)*]) => { + is_eval_always!([$($modifiers)*]) }; } @@ -295,11 +294,11 @@ macro_rules! hash_result { ([][$hcx:expr, $result:expr]) => {{ dep_graph::hash_result($hcx, &$result) }}; - ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{ + ([(no_hash) $($rest:tt)*][$hcx:expr, $result:expr]) => {{ None }}; - ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => { - hash_result!([$($($modifiers)*)*][$($args)*]) + ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { + hash_result!([$($modifiers)*][$($args)*]) }; } @@ -321,10 +320,13 @@ macro_rules! define_queries { pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryStackFrame { let kind = dep_graph::DepKind::$name; let name = stringify!($name); - let description = ty::print::with_forced_impl_filename_line( + // Disable visible paths printing for performance reasons. + // Showing visible path instead of any path is not that important in production. + let description = ty::print::with_no_visible_paths( + || ty::print::with_forced_impl_filename_line( // Force filename-line mode to avoid invoking `type_of` query. || queries::$name::describe(tcx, key) - ); + )); let description = if tcx.sess.verbose() { format!("{} [{}]", description, name) } else { diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 11c18a497e5e6..898a8caa3ca35 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -10,12 +10,16 @@ doctest = false rustc_arena = { path = "../rustc_arena" } tracing = "0.1" rustc-rayon-core = "0.3.1" +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } -rustc_macros = { path = "../rustc_macros" } +rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } parking_lot = "0.11" smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index 46dc0c720ce7f..dd5000153745a 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -43,10 +43,10 @@ //! lost during fingerprint computation. use super::{DepContext, DepKind}; +use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - use std::fmt; use std::hash::Hash; @@ -119,7 +119,7 @@ pub trait DepNodeParams: fmt::Debug + Sized { impl DepNodeParams for T where - T: HashStable + fmt::Debug, + T: for<'a> HashStable> + fmt::Debug, { #[inline] default fn can_reconstruct_query_key() -> bool { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 23a4377184272..114d12fb90b0a 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1,3 +1,4 @@ +use parking_lot::Mutex; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerRef}; @@ -7,8 +8,6 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; use rustc_index::vec::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; - -use parking_lot::Mutex; use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; use std::fmt::Debug; @@ -19,6 +18,7 @@ use std::sync::atomic::Ordering::Relaxed; use super::query::DepGraphQuery; use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId}; +use crate::ich::StableHashingContext; use crate::query::{QueryContext, QuerySideEffects}; #[cfg(debug_assertions)] @@ -96,9 +96,9 @@ struct DepGraphData { dep_node_debug: Lock, String>>, } -pub fn hash_result(hcx: &mut HashCtxt, result: &R) -> Option +pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option where - R: HashStable, + R: for<'a> HashStable>, { let mut stable_hasher = StableHasher::new(); result.hash_stable(hcx, &mut stable_hasher); @@ -215,7 +215,7 @@ impl DepGraph { cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, - hash_result: fn(&mut Ctxt::StableHashingContext, &R) -> Option, + hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option, ) -> (R, DepNodeIndex) { if self.is_fully_enabled() { self.with_task_impl(key, cx, arg, task, hash_result) @@ -234,7 +234,7 @@ impl DepGraph { cx: Ctxt, arg: A, task: fn(Ctxt, A) -> R, - hash_result: fn(&mut Ctxt::StableHashingContext, &R) -> Option, + hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option, ) -> (R, DepNodeIndex) { // This function is only called when the graph is enabled. let data = self.data.as_ref().unwrap(); diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index b5be1192ce73f..2afef21025419 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -9,6 +9,7 @@ pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, Wor pub use query::DepGraphQuery; pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; +use crate::ich::StableHashingContext; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; use rustc_serialize::{opaque::FileEncoder, Encodable}; @@ -19,10 +20,9 @@ use std::hash::Hash; pub trait DepContext: Copy { type DepKind: self::DepKind; - type StableHashingContext; /// Create a hashing context for hashing new results. - fn create_stable_hashing_context(&self) -> Self::StableHashingContext; + fn create_stable_hashing_context(&self) -> StableHashingContext<'_>; /// Access the DepGraph. fn dep_graph(&self) -> &DepGraph; @@ -36,18 +36,13 @@ pub trait DepContext: Copy { pub trait HasDepContext: Copy { type DepKind: self::DepKind; - type StableHashingContext; - type DepContext: self::DepContext< - DepKind = Self::DepKind, - StableHashingContext = Self::StableHashingContext, - >; + type DepContext: self::DepContext; fn dep_context(&self) -> &Self::DepContext; } impl HasDepContext for T { type DepKind = T::DepKind; - type StableHashingContext = T::StableHashingContext; type DepContext = Self; fn dep_context(&self) -> &Self::DepContext { diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs similarity index 73% rename from compiler/rustc_middle/src/ich/hcx.rs rename to compiler/rustc_query_system/src/ich/hcx.rs index c7f58ce5b1337..f2e935c59fce2 100644 --- a/compiler/rustc_middle/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -1,22 +1,17 @@ use crate::ich; -use crate::middle::cstore::CrateStore; -use crate::ty::{fast_reject, TyCtxt}; - use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::definitions::{DefPathHash, Definitions}; +use rustc_session::cstore::CrateStore; use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData}; -use smallvec::SmallVec; -use std::cmp::Ord; - fn compute_ignored_attr_names() -> FxHashSet { debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty()); ich::IGNORED_ATTRIBUTES.iter().copied().collect() @@ -182,42 +177,15 @@ impl<'a> StableHashingContext<'a> { } } -/// Something that can provide a stable hashing context. -pub trait StableHashingContextProvider<'a> { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a>; -} - -impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b T { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { - (**self).get_stable_hashing_context() - } -} - -impl<'a, 'b, T: StableHashingContextProvider<'a>> StableHashingContextProvider<'a> for &'b mut T { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { - (**self).get_stable_hashing_context() - } -} - -impl StableHashingContextProvider<'tcx> for TyCtxt<'tcx> { - fn get_stable_hashing_context(&self) -> StableHashingContext<'tcx> { - (*self).create_stable_hashing_context() - } -} - -impl<'a> StableHashingContextProvider<'a> for StableHashingContext<'a> { - fn get_stable_hashing_context(&self) -> StableHashingContext<'a> { - self.clone() - } -} - impl<'a> HashStable> for ast::NodeId { + #[inline] fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) { panic!("Node IDs should not appear in incremental state"); } } impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { + #[inline] fn hash_spans(&self) -> bool { self.hash_spans } @@ -232,6 +200,7 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { self.definitions.def_span(def_id) } + #[inline] fn span_data_to_lines_and_cols( &mut self, span: &SpanData, @@ -240,40 +209,4 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { } } -impl rustc_session::HashStableContext for StableHashingContext<'a> {} - -pub fn hash_stable_trait_impls<'a>( - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher, - blanket_impls: &[DefId], - non_blanket_impls: &FxHashMap>, -) { - { - let mut blanket_impls: SmallVec<[_; 8]> = - blanket_impls.iter().map(|&def_id| hcx.def_path_hash(def_id)).collect(); - - if blanket_impls.len() > 1 { - blanket_impls.sort_unstable(); - } - - blanket_impls.hash_stable(hcx, hasher); - } - - { - let mut keys: SmallVec<[_; 8]> = - non_blanket_impls.keys().map(|k| (k, k.map_def(|d| hcx.def_path_hash(d)))).collect(); - keys.sort_unstable_by(|&(_, ref k1), &(_, ref k2)| k1.cmp(k2)); - keys.len().hash_stable(hcx, hasher); - for (key, ref stable_key) in keys { - stable_key.hash_stable(hcx, hasher); - let mut impls: SmallVec<[_; 8]> = - non_blanket_impls[key].iter().map(|&impl_id| hcx.def_path_hash(impl_id)).collect(); - - if impls.len() > 1 { - impls.sort_unstable(); - } - - impls.hash_stable(hcx, hasher); - } - } -} +impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {} diff --git a/compiler/rustc_middle/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs similarity index 80% rename from compiler/rustc_middle/src/ich/impls_hir.rs rename to compiler/rustc_query_system/src/ich/impls_hir.rs index 5dfd00bc6d42c..04eb263a97718 100644 --- a/compiler/rustc_middle/src/ich/impls_hir.rs +++ b/compiler/rustc_query_system/src/ich/impls_hir.rs @@ -2,7 +2,6 @@ //! types in no particular order. use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use rustc_attr as attr; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_hir as hir; @@ -27,6 +26,7 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { } } + #[inline] fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) { let hcx = self; if hcx.hash_bodies() { @@ -34,6 +34,7 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { } } + #[inline] fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher) { let hcx = self; @@ -42,6 +43,7 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { }) } + #[inline] fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) { let hcx = self; let hir::Mod { inner: ref inner_span, ref item_ids } = *module; @@ -104,6 +106,7 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { } } + #[inline] fn hash_hir_item_like(&mut self, f: F) { let prev_hash_node_ids = self.node_id_hashing_mode; self.node_id_hashing_mode = NodeIdHashingMode::Ignore; @@ -114,16 +117,8 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { } } -impl<'a> ToStableHashKey> for hir::ItemLocalId { - type KeyType = hir::ItemLocalId; - - #[inline] - fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> hir::ItemLocalId { - *self - } -} - impl<'a> HashStable> for hir::Body<'_> { + #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Body { params, value, generator_kind } = self; @@ -135,19 +130,6 @@ impl<'a> HashStable> for hir::Body<'_> { } } -impl<'a> ToStableHashKey> for hir::BodyId { - type KeyType = (DefPathHash, hir::ItemLocalId); - - #[inline] - fn to_stable_hash_key( - &self, - hcx: &StableHashingContext<'a>, - ) -> (DefPathHash, hir::ItemLocalId) { - let hir::BodyId { hir_id } = *self; - hir_id.to_stable_hash_key(hcx) - } -} - impl<'a> HashStable> for hir::TraitCandidate { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { @@ -171,21 +153,3 @@ impl<'a> ToStableHashKey> for hir::TraitCandidate { ) } } - -impl<'hir> HashStable> for attr::InlineAttr { - fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - } -} - -impl<'hir> HashStable> for attr::InstructionSetAttr { - fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - } -} - -impl<'hir> HashStable> for attr::OptimizeAttr { - fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - } -} diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs similarity index 100% rename from compiler/rustc_middle/src/ich/impls_syntax.rs rename to compiler/rustc_query_system/src/ich/impls_syntax.rs diff --git a/compiler/rustc_middle/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs similarity index 74% rename from compiler/rustc_middle/src/ich/mod.rs rename to compiler/rustc_query_system/src/ich/mod.rs index c8fb2bf39cc80..54416902e5fb6 100644 --- a/compiler/rustc_middle/src/ich/mod.rs +++ b/compiler/rustc_query_system/src/ich/mod.rs @@ -1,15 +1,11 @@ //! ICH - Incremental Compilation Hash -pub use self::hcx::{ - hash_stable_trait_impls, NodeIdHashingMode, StableHashingContext, StableHashingContextProvider, -}; +pub use self::hcx::{NodeIdHashingMode, StableHashingContext}; use rustc_span::symbol::{sym, Symbol}; mod hcx; - mod impls_hir; mod impls_syntax; -mod impls_ty; pub const IGNORED_ATTRIBUTES: &[Symbol] = &[ sym::cfg, diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index c205f0fb531ae..bc23de069b0d9 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(assert_matches)] #![feature(bool_to_option)] #![feature(core_intrinsics)] #![feature(hash_raw_entry)] @@ -14,4 +15,5 @@ extern crate rustc_macros; pub mod cache; pub mod dep_graph; +pub mod ich; pub mod query; diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index d1e527dff9840..76a165ed8e6bc 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -2,6 +2,7 @@ use crate::dep_graph::DepNode; use crate::dep_graph::SerializedDepNodeIndex; +use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; use crate::query::{QueryCacheStore, QueryContext, QueryState}; @@ -23,7 +24,7 @@ pub(crate) struct QueryVtable { pub dep_kind: CTX::DepKind, pub eval_always: bool, - pub hash_result: fn(&mut CTX::StableHashingContext, &V) -> Option, + pub hash_result: fn(&mut StableHashingContext<'_>, &V) -> Option, pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V, pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool, pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option, @@ -39,7 +40,7 @@ impl QueryVtable { pub(crate) fn hash_result( &self, - hcx: &mut CTX::StableHashingContext, + hcx: &mut StableHashingContext<'_>, value: &V, ) -> Option { (self.hash_result)(hcx, value) @@ -74,10 +75,8 @@ pub trait QueryAccessors: QueryConfig { // Don't use this method to compute query results, instead use the methods on TyCtxt fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value; - fn hash_result( - hcx: &mut CTX::StableHashingContext, - result: &Self::Value, - ) -> Option; + fn hash_result(hcx: &mut StableHashingContext<'_>, result: &Self::Value) + -> Option; fn handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value; } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 55f2b04c4f1c1..2a562a06cb3cd 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -9,11 +9,9 @@ use crate::def_collector::collect_definitions; use crate::imports::{Import, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::Namespace::{self, MacroNS, TypeNS, ValueNS}; -use crate::{CrateLint, Determinacy, PathResult, ResolutionError, VisResolutionError}; -use crate::{ - ExternPreludeEntry, ModuleOrUniformRoot, ParentScope, PerNS, Resolver, ResolverArenas, -}; -use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; +use crate::{CrateLint, Determinacy, ExternPreludeEntry, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError}; +use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError}; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; @@ -29,8 +27,8 @@ use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_metadata::creader::LoadedMacro; use rustc_middle::bug; use rustc_middle::hir::exports::Export; -use rustc_middle::middle::cstore::CrateStore; use rustc_middle::ty; +use rustc_session::cstore::CrateStore; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -95,100 +93,96 @@ impl<'a> Resolver<'a> { } /// Walks up the tree of definitions starting at `def_id`, - /// stopping at the first `DefKind::Mod` encountered - fn nearest_parent_mod(&mut self, def_id: DefId) -> Module<'a> { - let def_key = self.cstore().def_key(def_id); - - let mut parent_id = DefId { - krate: def_id.krate, - index: def_key.parent.expect("failed to get parent for module"), - }; - // The immediate parent may not be a module - // (e.g. `const _: () = { #[path = "foo.rs"] mod foo; };`) - // Walk up the tree until we hit a module or the crate root. - while parent_id.index != CRATE_DEF_INDEX - && self.cstore().def_kind(parent_id) != DefKind::Mod - { - let parent_def_key = self.cstore().def_key(parent_id); - parent_id.index = parent_def_key.parent.expect("failed to get parent for module"); + /// stopping at the first encountered module. + /// Parent block modules for arbitrary def-ids are not recorded for the local crate, + /// and are not preserved in metadata for foreign crates, so block modules are never + /// returned by this function. + /// + /// For the local crate ignoring block modules may be incorrect, so use this method with care. + /// + /// For foreign crates block modules can be ignored without introducing observable differences, + /// moreover they has to be ignored right now because they are not kept in metadata. + /// Foreign parent modules are used for resolving names used by foreign macros with def-site + /// hygiene, therefore block module ignorability relies on macros with def-site hygiene and + /// block module parents being unreachable from other crates. + /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`, + /// but they cannot use def-site hygiene, so the assumption holds + /// (). + fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> { + loop { + match self.get_module(def_id) { + Some(module) => return module, + None => { + def_id.index = + self.def_key(def_id).parent.expect("non-root `DefId` without parent") + } + } } - self.get_module(parent_id) } - pub fn get_module(&mut self, def_id: DefId) -> Module<'a> { - // If this is a local module, it will be in `module_map`, no need to recalculate it. - if let Some(def_id) = def_id.as_local() { - return self.module_map[&def_id]; - } + pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> { + self.get_module(def_id).expect("argument `DefId` is not a module") + } - // Cache module resolution - if let Some(&module) = self.extern_module_map.get(&def_id) { - return module; + /// If `def_id` refers to a module (in resolver's sense, i.e. a module item, crate root, enum, + /// or trait), then this function returns that module's resolver representation, otherwise it + /// returns `None`. + crate fn get_module(&mut self, def_id: DefId) -> Option> { + if let module @ Some(..) = self.module_map.get(&def_id) { + return module.copied(); } - let (name, parent) = if def_id.index == CRATE_DEF_INDEX { - // This is the crate root - (self.cstore().crate_name(def_id.krate), None) - } else { - let def_key = self.cstore().def_key(def_id); - let name = def_key - .disambiguated_data - .data - .get_opt_name() - .expect("given a DefId that wasn't a module"); - - let parent = Some(self.nearest_parent_mod(def_id)); - (name, parent) - }; + if !def_id.is_local() { + let def_kind = self.cstore().def_kind(def_id); + match def_kind { + DefKind::Mod | DefKind::Enum | DefKind::Trait => { + let def_key = self.cstore().def_key(def_id); + let parent = def_key.parent.map(|index| { + self.get_nearest_non_block_module(DefId { index, krate: def_id.krate }) + }); + let name = if def_id.index == CRATE_DEF_INDEX { + self.cstore().crate_name(def_id.krate) + } else { + def_key.disambiguated_data.data.get_opt_name().expect("module without name") + }; + let expn_id = if def_kind == DefKind::Mod { + self.cstore().module_expansion_untracked(def_id, &self.session) + } else { + // FIXME: Parent expansions for enums and traits are not kept in metadata. + ExpnId::root() + }; - // Allocate and return a new module with the information we found - let kind = ModuleKind::Def(DefKind::Mod, def_id, name); - let module = self.arenas.alloc_module(ModuleData::new( - parent, - kind, - def_id, - self.cstore().module_expansion_untracked(def_id, &self.session), - self.cstore().get_span_untracked(def_id, &self.session), - )); - self.extern_module_map.insert(def_id, module); - module + Some(self.new_module( + parent, + ModuleKind::Def(def_kind, def_id, name), + expn_id, + self.cstore().get_span_untracked(def_id, &self.session), + // FIXME: Account for `#[no_implicit_prelude]` attributes. + parent.map_or(false, |module| module.no_implicit_prelude), + )) + } + _ => None, + } + } else { + None + } } - crate fn macro_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { - let def_id = match expn_id.expn_data().macro_def_id { - Some(def_id) => def_id, - None => { - return expn_id - .as_local() - .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id)) - .unwrap_or(&self.graph_root); - } - }; - self.macro_def_scope_from_def_id(def_id) + crate fn expn_def_scope(&mut self, expn_id: ExpnId) -> Module<'a> { + match expn_id.expn_data().macro_def_id { + Some(def_id) => self.macro_def_scope(def_id), + None => expn_id + .as_local() + .and_then(|expn_id| self.ast_transform_scopes.get(&expn_id)) + .unwrap_or(&self.graph_root), + } } - crate fn macro_def_scope_from_def_id(&mut self, def_id: DefId) -> Module<'a> { + crate fn macro_def_scope(&mut self, def_id: DefId) -> Module<'a> { if let Some(id) = def_id.as_local() { self.local_macro_def_scopes[&id] } else { - // This is not entirely correct - a `macro_rules!` macro may occur - // inside a 'block' module: - // - // ```rust - // const _: () = { - // #[macro_export] - // macro_rules! my_macro { - // () => {}; - // } - // ` - // We don't record this information for external crates, so - // the module we compute here will be the closest 'mod' item - // (not necesssarily the actual parent of the `macro_rules!` - // macro). `macro_rules!` macros can't use def-site hygiene, - // so this hopefully won't be a problem. - // - // See https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508 - self.nearest_parent_mod(def_id) + self.get_nearest_non_block_module(def_id) } } @@ -226,8 +220,7 @@ impl<'a> Resolver<'a> { } crate fn build_reduced_graph_external(&mut self, module: Module<'a>) { - let def_id = module.def_id().expect("unpopulated module without a def-id"); - for child in self.cstore().item_children_untracked(def_id, self.session) { + for child in self.cstore().item_children_untracked(module.def_id(), self.session) { let parent_scope = ParentScope::module(module, self); BuildReducedGraphVisitor { r: self, parent_scope } .build_reduced_graph_for_external_crate_res(child); @@ -274,7 +267,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.visibilities[&def_id.expect_local()] } // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod), + _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()), }) } ast::VisibilityKind::Restricted { ref path, id, .. } => { @@ -717,7 +710,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { local_def_id, ); self.r.extern_crate_map.insert(local_def_id, crate_id); - self.r.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) + self.r.expect_module(crate_id.as_def_id()) }; let used = self.process_macro_use_imports(item, module); @@ -768,21 +761,15 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } ItemKind::Mod(..) => { - let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name); - let module = self.r.arenas.alloc_module(ModuleData { - no_implicit_prelude: parent.no_implicit_prelude || { - self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude) - }, - ..ModuleData::new( - Some(parent), - module_kind, - def_id, - expansion.to_expn_id(), - item.span, - ) - }); + let module = self.r.new_module( + Some(parent), + ModuleKind::Def(DefKind::Mod, def_id, ident.name), + expansion.to_expn_id(), + item.span, + parent.no_implicit_prelude + || self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude), + ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.r.module_map.insert(local_def_id, module); // Descend into the module. self.parent_scope.module = module; @@ -813,13 +800,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } ItemKind::Enum(_, _) => { - let module_kind = ModuleKind::Def(DefKind::Enum, def_id, ident.name); let module = self.r.new_module( - parent, - module_kind, - parent.nearest_parent_mod, + Some(parent), + ModuleKind::Def(DefKind::Enum, def_id, ident.name), expansion.to_expn_id(), item.span, + parent.no_implicit_prelude, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.parent_scope.module = module; @@ -888,13 +874,12 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { ItemKind::Trait(..) => { // Add all the items within to a new module. - let module_kind = ModuleKind::Def(DefKind::Trait, def_id, ident.name); let module = self.r.new_module( - parent, - module_kind, - parent.nearest_parent_mod, + Some(parent), + ModuleKind::Def(DefKind::Trait, def_id, ident.name), expansion.to_expn_id(), item.span, + parent.no_implicit_prelude, ); self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.parent_scope.module = module; @@ -933,11 +918,11 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let expansion = self.parent_scope.expansion; if self.block_needs_anonymous_module(block) { let module = self.r.new_module( - parent, + Some(parent), ModuleKind::Block(block.id), - parent.nearest_parent_mod, expansion.to_expn_id(), block.span, + parent.no_implicit_prelude, ); self.r.block_map.insert(block.id, module); self.parent_scope.module = module; // Descend into the block. @@ -952,14 +937,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let expansion = self.parent_scope.expansion; // Record primary definitions. match res { - Res::Def(kind @ (DefKind::Mod | DefKind::Enum | DefKind::Trait), def_id) => { - let module = self.r.new_module( - parent, - ModuleKind::Def(kind, def_id, ident.name), - def_id, - expansion.to_expn_id(), - span, - ); + Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, def_id) => { + let module = self.r.expect_module(def_id); self.r.define(parent, ident, TypeNS, (module, vis, span, expansion)); } Res::Def( diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 0b1687d1bd8c3..dea47c25a8e0a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -198,7 +198,7 @@ impl<'a> Resolver<'a> { err.span_label(first_use_span, format!("first use of `{}`", name)); err } - ResolutionError::MethodNotMemberOfTrait(method, trait_) => { + ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => { let mut err = struct_span_err!( self.session, span, @@ -208,9 +208,17 @@ impl<'a> Resolver<'a> { trait_ ); err.span_label(span, format!("not a member of trait `{}`", trait_)); + if let Some(candidate) = candidate { + err.span_suggestion( + method.span, + "there is an associated function with a similar name", + candidate.to_ident_string(), + Applicability::MaybeIncorrect, + ); + } err } - ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { + ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => { let mut err = struct_span_err!( self.session, span, @@ -220,9 +228,17 @@ impl<'a> Resolver<'a> { trait_ ); err.span_label(span, format!("not a member of trait `{}`", trait_)); + if let Some(candidate) = candidate { + err.span_suggestion( + type_.span, + "there is an associated type with a similar name", + candidate.to_ident_string(), + Applicability::MaybeIncorrect, + ); + } err } - ResolutionError::ConstNotMemberOfTrait(const_, trait_) => { + ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => { let mut err = struct_span_err!( self.session, span, @@ -232,6 +248,14 @@ impl<'a> Resolver<'a> { trait_ ); err.span_label(span, format!("not a member of trait `{}`", trait_)); + if let Some(candidate) = candidate { + err.span_suggestion( + const_.span, + "there is an associated constant with a similar name", + candidate.to_ident_string(), + Applicability::MaybeIncorrect, + ); + } err } ResolutionError::VariableNotBoundInPattern(binding_error) => { @@ -777,7 +801,7 @@ impl<'a> Resolver<'a> { None => worklist_via_import.pop(), Some(x) => Some(x), } { - let in_module_is_extern = !in_module.def_id().unwrap().is_local(); + let in_module_is_extern = !in_module.def_id().is_local(); // We have to visit module children in deterministic order to avoid // instabilities in reported imports (#43552). in_module.for_each_child(self, |this, ident, ns, name_binding| { @@ -860,7 +884,7 @@ impl<'a> Resolver<'a> { if !is_extern_crate_that_also_appears_in_prelude { // add the module to the lookup - if seen_modules.insert(module.def_id().unwrap()) { + if seen_modules.insert(module.def_id()) { if via_import { &mut worklist_via_import } else { &mut worklist } .push((module, path_segments, child_accessible)); } @@ -915,8 +939,7 @@ impl<'a> Resolver<'a> { continue; } if let Some(crate_id) = self.crate_loader.maybe_process_path_extern(ident.name) { - let crate_root = - self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); + let crate_root = self.expect_module(crate_id.as_def_id()); suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, namespace, @@ -950,7 +973,15 @@ impl<'a> Resolver<'a> { let import_suggestions = self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); - show_candidates(err, None, &import_suggestions, false, true); + show_candidates( + &self.definitions, + self.session, + err, + None, + &import_suggestions, + false, + true, + ); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident); @@ -1690,6 +1721,8 @@ fn find_span_immediately_after_crate_name( /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way crate fn show_candidates( + definitions: &rustc_hir::definitions::Definitions, + session: &Session, err: &mut DiagnosticBuilder<'_>, // This is `None` if all placement locations are inside expansions use_placement_span: Option, @@ -1701,40 +1734,111 @@ crate fn show_candidates( return; } + let mut accessible_path_strings: Vec<(String, &str, Option)> = Vec::new(); + let mut inaccessible_path_strings: Vec<(String, &str, Option)> = Vec::new(); + + candidates.iter().for_each(|c| { + (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings }) + .push((path_names_to_string(&c.path), c.descr, c.did)) + }); + // we want consistent results across executions, but candidates are produced // by iterating through a hash map, so make sure they are ordered: - let mut path_strings: Vec<_> = - candidates.iter().map(|c| path_names_to_string(&c.path)).collect(); + for path_strings in [&mut accessible_path_strings, &mut inaccessible_path_strings] { + path_strings.sort_by(|a, b| a.0.cmp(&b.0)); + let core_path_strings = + path_strings.drain_filter(|p| p.0.starts_with("core::")).collect::>(); + path_strings.extend(core_path_strings); + path_strings.dedup_by(|a, b| a.0 == b.0); + } - path_strings.sort(); - path_strings.dedup(); + if !accessible_path_strings.is_empty() { + let (determiner, kind) = if accessible_path_strings.len() == 1 { + ("this", accessible_path_strings[0].1) + } else { + ("one of these", "items") + }; - let (determiner, kind) = if candidates.len() == 1 { - ("this", candidates[0].descr) - } else { - ("one of these", "items") - }; - - let instead = if instead { " instead" } else { "" }; - let mut msg = format!("consider importing {} {}{}", determiner, kind, instead); - - if let Some(span) = use_placement_span { - for candidate in &mut path_strings { - // produce an additional newline to separate the new use statement - // from the directly following item. - let additional_newline = if found_use { "" } else { "\n" }; - *candidate = format!("use {};\n{}", candidate, additional_newline); - } + let instead = if instead { " instead" } else { "" }; + let mut msg = format!("consider importing {} {}{}", determiner, kind, instead); - err.span_suggestions(span, &msg, path_strings.into_iter(), Applicability::Unspecified); - } else { - msg.push(':'); + if let Some(span) = use_placement_span { + for candidate in &mut accessible_path_strings { + // produce an additional newline to separate the new use statement + // from the directly following item. + let additional_newline = if found_use { "" } else { "\n" }; + candidate.0 = format!("use {};\n{}", &candidate.0, additional_newline); + } + + err.span_suggestions( + span, + &msg, + accessible_path_strings.into_iter().map(|a| a.0), + Applicability::Unspecified, + ); + } else { + msg.push(':'); + + for candidate in accessible_path_strings { + msg.push('\n'); + msg.push_str(&candidate.0); + } - for candidate in path_strings { - msg.push('\n'); - msg.push_str(&candidate); + err.note(&msg); } + } else { + assert!(!inaccessible_path_strings.is_empty()); + + if inaccessible_path_strings.len() == 1 { + let (name, descr, def_id) = &inaccessible_path_strings[0]; + let msg = format!("{} `{}` exists but is inaccessible", descr, name); + + if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) { + let span = definitions.def_span(local_def_id); + let span = session.source_map().guess_head_span(span); + let mut multi_span = MultiSpan::from_span(span); + multi_span.push_span_label(span, "not accessible".to_string()); + err.span_note(multi_span, &msg); + } else { + err.note(&msg); + } + } else { + let (_, descr_first, _) = &inaccessible_path_strings[0]; + let descr = if inaccessible_path_strings + .iter() + .skip(1) + .all(|(_, descr, _)| descr == descr_first) + { + format!("{}", descr_first) + } else { + "item".to_string() + }; + + let mut msg = format!("these {}s exist but are inaccessible", descr); + let mut has_colon = false; - err.note(&msg); + let mut spans = Vec::new(); + for (name, _, def_id) in &inaccessible_path_strings { + if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) { + let span = definitions.def_span(local_def_id); + let span = session.source_map().guess_head_span(span); + spans.push((name, span)); + } else { + if !has_colon { + msg.push(':'); + has_colon = true; + } + msg.push('\n'); + msg.push_str(name); + } + } + + let mut multi_span = MultiSpan::from_spans(spans.iter().map(|(_, sp)| *sp).collect()); + for (name, span) in spans { + multi_span.push_span_label(span, format!("`{}`: not accessible", name)); + } + + err.span_note(multi_span, &msg); + } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d4782edbc1346..9be568b2cf145 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -427,7 +427,7 @@ impl<'a> Resolver<'a> { match ident.span.glob_adjust(module.expansion, glob_import.span) { Some(Some(def)) => { tmp_parent_scope = - ParentScope { module: self.macro_def_scope(def), ..*parent_scope }; + ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; adjusted_parent_scope = &tmp_parent_scope; } Some(None) => {} @@ -585,7 +585,7 @@ impl<'a> Resolver<'a> { for import in module.glob_importers.borrow_mut().iter() { let mut ident = key.ident; let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) { - Some(Some(def)) => self.macro_def_scope(def), + Some(Some(def)) => self.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, }; @@ -989,7 +989,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } if let ModuleOrUniformRoot::Module(module) = module { - if module.def_id() == import.parent_scope.module.def_id() { + if ptr::eq(module, import.parent_scope.module) { // Importing a module into itself is not allowed. return Some(UnresolvedImportError { span: import.span, @@ -1339,9 +1339,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }; if module.is_trait() { - self.r.session.span_err(import.span, "items in traits are not importable."); + self.r.session.span_err(import.span, "items in traits are not importable"); return; - } else if module.def_id() == import.parent_scope.module.def_id() { + } else if ptr::eq(module, import.parent_scope.module) { return; } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind { self.r.prelude = Some(module); @@ -1364,7 +1364,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { .collect::>(); for (mut key, binding) in bindings { let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) { - Some(Some(def)) => self.r.macro_def_scope(def), + Some(Some(def)) => self.r.expn_def_scope(def), Some(None) => import.parent_scope.module, None => continue, }; @@ -1400,7 +1400,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { }); if !reexports.is_empty() { - if let Some(def_id) = module.def_id() { + if let Some(def_id) = module.opt_def_id() { // Call to `expect_local` should be fine because current // code is only called for local modules. self.r.export_map.insert(def_id.expect_local(), reexports); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c0b52d21fa639..9563325796538 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -799,9 +799,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } fn with_scope(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { - let id = self.r.local_def_id(id); - let module = self.r.module_map.get(&id).cloned(); // clones a reference - if let Some(module) = module { + if let Some(module) = self.r.get_module(self.r.local_def_id(id).to_def_id()) { // Move down in the graph. let orig_module = replace(&mut self.parent_scope.module, module); self.with_rib(ValueNS, ModuleRibKind(module), |this| { @@ -1311,14 +1309,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { use crate::ResolutionError::*; match &item.kind { AssocItemKind::Const(_default, _ty, _expr) => { - debug!("resolve_implementation AssocItemKind::Const",); + debug!("resolve_implementation AssocItemKind::Const"); // If this is a trait impl, ensure the const // exists in trait this.check_trait_item( item.ident, + &item.kind, ValueNS, item.span, - |n, s| ConstNotMemberOfTrait(n, s), + |i, s, c| ConstNotMemberOfTrait(i, s, c), ); // We allow arbitrary const expressions inside of associated consts, @@ -1340,6 +1339,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); } AssocItemKind::Fn(box FnKind(.., generics, _)) => { + debug!("resolve_implementation AssocItemKind::Fn"); // We also need a new scope for the impl item type parameters. this.with_generic_param_rib( generics, @@ -1349,9 +1349,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // exists in trait this.check_trait_item( item.ident, + &item.kind, ValueNS, item.span, - |n, s| MethodNotMemberOfTrait(n, s), + |i, s, c| MethodNotMemberOfTrait(i, s, c), ); visit::walk_assoc_item( @@ -1368,6 +1369,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { _, _, )) => { + debug!("resolve_implementation AssocItemKind::TyAlias"); // We also need a new scope for the impl item type parameters. this.with_generic_param_rib( generics, @@ -1377,9 +1379,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // exists in trait this.check_trait_item( item.ident, + &item.kind, TypeNS, item.span, - |n, s| TypeNotMemberOfTrait(n, s), + |i, s, c| TypeNotMemberOfTrait(i, s, c), ); visit::walk_assoc_item( @@ -1403,9 +1406,15 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); } - fn check_trait_item(&mut self, ident: Ident, ns: Namespace, span: Span, err: F) - where - F: FnOnce(Symbol, &str) -> ResolutionError<'_>, + fn check_trait_item( + &mut self, + ident: Ident, + kind: &AssocItemKind, + ns: Namespace, + span: Span, + err: F, + ) where + F: FnOnce(Ident, &str, Option) -> ResolutionError<'_>, { // If there is a TraitRef in scope for an impl, then the method must be in the // trait. @@ -1422,8 +1431,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ) .is_err() { + let candidate = self.find_similarly_named_assoc_item(ident.name, kind); let path = &self.current_trait_ref.as_ref().unwrap().1.path; - self.report_error(span, err(ident.name, &path_names_to_string(path))); + self.report_error(span, err(ident, &path_names_to_string(path), candidate)); } } } @@ -1872,7 +1882,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if this.should_report_errs() { let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); - let def_id = this.parent_scope.module.nearest_parent_mod; + let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); let suggestion = if res.is_none() { this.report_missing_type_error(path) } else { None }; @@ -1940,7 +1950,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { drop(parent_err); - let def_id = this.parent_scope.module.nearest_parent_mod; + let def_id = this.parent_scope.module.nearest_parent_mod(); if this.should_report_errs() { this.r.use_injections.push(UseError { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 19136c6ceeb1f..7b0dd82f0e6d1 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -7,8 +7,8 @@ use crate::{PathResult, PathSource, Segment}; use rustc_ast::visit::FnKind; use rustc_ast::{ - self as ast, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, NodeId, Path, Ty, - TyKind, + self as ast, AssocItemKind, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, + NodeId, Path, Ty, TyKind, }; use rustc_ast_pretty::pprust::path_segment_to_string; use rustc_data_structures::fx::FxHashSet; @@ -1026,9 +1026,15 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { self.suggest_using_enum_variant(err, source, def_id, span); } - (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { + (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => { let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() { + if let PathSource::Expr(Some(parent)) = source { + if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind { + bad_struct_syntax_suggestion(def_id); + return true; + } + } struct_ctor } else { bad_struct_syntax_suggestion(def_id); @@ -1144,6 +1150,40 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { true } + /// Given the target `ident` and `kind`, search for the similarly named associated item + /// in `self.current_trait_ref`. + crate fn find_similarly_named_assoc_item( + &mut self, + ident: Symbol, + kind: &AssocItemKind, + ) -> Option { + let module = if let Some((module, _)) = self.current_trait_ref { + module + } else { + return None; + }; + if ident == kw::Underscore { + // We do nothing for `_`. + return None; + } + + let resolutions = self.r.resolutions(module); + let targets = resolutions + .borrow() + .iter() + .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res()))) + .filter(|(_, res)| match (kind, res) { + (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true, + (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true, + (AssocItemKind::TyAlias(..), Res::Def(DefKind::AssocTy, _)) => true, + _ => false, + }) + .map(|(key, _)| key.ident.name) + .collect::>(); + + find_best_match_for_name(&targets, ident, None) + } + fn lookup_assoc_candidate( &mut self, ident: Ident, @@ -1451,7 +1491,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id().unwrap(); + let module_def_id = module.def_id(); if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments, tokens: None }; diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 84e7c68713f23..eb6f302a11da8 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -2740,6 +2740,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { for input in inputs { gather.visit_ty(input); } + trace!(?gather.anon_count); let late_bound_vars = self.map.late_bound_vars.entry(hir_id).or_default(); let named_late_bound_vars = late_bound_vars.len() as u32; late_bound_vars.extend( @@ -3028,6 +3029,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { NestedVisitorMap::None } + #[instrument(skip(self), level = "trace")] fn visit_ty(&mut self, ty: &hir::Ty<'_>) { // If we enter a `BareFn`, then we enter a *new* binding scope if let hir::TyKind::BareFn(_) = ty.kind { @@ -3048,6 +3050,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { intravisit::walk_generic_args(self, path_span, generic_args) } + #[instrument(skip(self), level = "trace")] fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { if lifetime_ref.is_elided() { self.anon_count += 1; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d76ba80e42eab..3e7783033efa5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,6 +10,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(box_patterns)] +#![feature(drain_filter)] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(format_args_capture)] @@ -19,6 +20,9 @@ #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] +#[macro_use] +extern crate tracing; + pub use rustc_hir::def::{Namespace, PerNS}; use Determinacy::*; @@ -40,16 +44,17 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::TraitCandidate; use rustc_index::vec::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; -use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_middle::span_bug; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs}; +use rustc_session::cstore::{CrateStore, MetadataLoaderDyn}; use rustc_session::lint; use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::Session; @@ -201,11 +206,11 @@ enum ResolutionError<'a> { /// parameter list. NameAlreadyUsedInParameterList(Symbol, Span), /// Error E0407: method is not a member of trait. - MethodNotMemberOfTrait(Symbol, &'a str), + MethodNotMemberOfTrait(Ident, &'a str, Option), /// Error E0437: type is not a member of trait. - TypeNotMemberOfTrait(Symbol, &'a str), + TypeNotMemberOfTrait(Ident, &'a str, Option), /// Error E0438: const is not a member of trait. - ConstNotMemberOfTrait(Symbol, &'a str), + ConstNotMemberOfTrait(Ident, &'a str, Option), /// Error E0408: variable `{}` is not bound in all patterns. VariableNotBoundInPattern(&'a BindingError), /// Error E0409: variable `{}` is bound in inconsistent ways within the same match arm. @@ -408,7 +413,7 @@ impl ModuleOrUniformRoot<'_> { fn same_def(lhs: Self, rhs: Self) -> bool { match (lhs, rhs) { (ModuleOrUniformRoot::Module(lhs), ModuleOrUniformRoot::Module(rhs)) => { - lhs.def_id() == rhs.def_id() + ptr::eq(lhs, rhs) } ( ModuleOrUniformRoot::CrateRootAndExternPrelude, @@ -505,10 +510,6 @@ pub struct ModuleData<'a> { /// What kind of module this is, because this may not be a `mod`. kind: ModuleKind, - /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module). - /// This may be the crate root. - nearest_parent_mod: DefId, - /// Mapping between names and their (possibly in-progress) resolutions in this module. /// Resolutions in modules from other crates are not populated until accessed. lazy_resolutions: Resolutions<'a>, @@ -539,18 +540,21 @@ impl<'a> ModuleData<'a> { fn new( parent: Option>, kind: ModuleKind, - nearest_parent_mod: DefId, expansion: ExpnId, span: Span, + no_implicit_prelude: bool, ) -> Self { + let is_foreign = match kind { + ModuleKind::Def(_, def_id, _) => !def_id.is_local(), + ModuleKind::Block(_) => false, + }; ModuleData { parent, kind, - nearest_parent_mod, lazy_resolutions: Default::default(), - populate_on_access: Cell::new(!nearest_parent_mod.is_local()), + populate_on_access: Cell::new(is_foreign), unexpanded_invocations: Default::default(), - no_implicit_prelude: false, + no_implicit_prelude, glob_importers: RefCell::new(Vec::new()), globs: RefCell::new(Vec::new()), traits: RefCell::new(None), @@ -598,7 +602,11 @@ impl<'a> ModuleData<'a> { } } - fn def_id(&self) -> Option { + fn def_id(&self) -> DefId { + self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") + } + + fn opt_def_id(&self) -> Option { match self.kind { ModuleKind::Def(_, def_id, _) => Some(def_id), _ => None, @@ -623,6 +631,15 @@ impl<'a> ModuleData<'a> { } } + /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module). + /// This may be the crate root. + fn nearest_parent_mod(&self) -> DefId { + match self.kind { + ModuleKind::Def(DefKind::Mod, def_id, _) => def_id, + _ => self.parent.expect("non-root module without parent").nearest_parent_mod(), + } + } + fn is_ancestor_of(&self, mut other: &Self) -> bool { while !ptr::eq(self, other) { if let Some(parent) = other.parent { @@ -934,8 +951,7 @@ pub struct Resolver<'a> { /// some AST passes can generate identifiers that only resolve to local or /// language items. empty_module: Module<'a>, - module_map: FxHashMap>, - extern_module_map: FxHashMap>, + module_map: FxHashMap>, binding_parent_modules: FxHashMap>, Module<'a>>, underscore_disambiguator: u32, @@ -1052,11 +1068,24 @@ pub struct ResolverArenas<'a> { } impl<'a> ResolverArenas<'a> { - fn alloc_module(&'a self, module: ModuleData<'a>) -> Module<'a> { - let module = self.modules.alloc(module); - if module.def_id().map_or(true, |def_id| def_id.is_local()) { + fn new_module( + &'a self, + parent: Option>, + kind: ModuleKind, + expn_id: ExpnId, + span: Span, + no_implicit_prelude: bool, + module_map: &mut FxHashMap>, + ) -> Module<'a> { + let module = + self.modules.alloc(ModuleData::new(parent, kind, expn_id, span, no_implicit_prelude)); + let def_id = module.opt_def_id(); + if def_id.map_or(true, |def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); } + if let Some(def_id) = def_id { + module_map.insert(def_id, module); + } module } fn local_modules(&'a self) -> std::cell::Ref<'a, Vec>> { @@ -1132,7 +1161,7 @@ impl ResolverAstLowering for Resolver<'_> { self.legacy_const_generic_args(expr) } - fn get_partial_res(&mut self, id: NodeId) -> Option { + fn get_partial_res(&self, id: NodeId) -> Option { self.partial_res_map.get(&id).cloned() } @@ -1255,32 +1284,30 @@ impl<'a> Resolver<'a> { metadata_loader: Box, arenas: &'a ResolverArenas<'a>, ) -> Resolver<'a> { - let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX }; - let root_def_id = root_local_def_id.to_def_id(); - let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); - let graph_root = arenas.alloc_module(ModuleData { - no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude), - ..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span) - }); - let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty); - let empty_module = arenas.alloc_module(ModuleData { - no_implicit_prelude: true, - ..ModuleData::new( - Some(graph_root), - empty_module_kind, - root_def_id, - ExpnId::root(), - DUMMY_SP, - ) - }); + let root_def_id = CRATE_DEF_ID.to_def_id(); let mut module_map = FxHashMap::default(); - module_map.insert(root_local_def_id, graph_root); + let graph_root = arenas.new_module( + None, + ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), + ExpnId::root(), + krate.span, + session.contains_name(&krate.attrs, sym::no_implicit_prelude), + &mut module_map, + ); + let empty_module = arenas.new_module( + None, + ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty), + ExpnId::root(), + DUMMY_SP, + true, + &mut FxHashMap::default(), + ); let definitions = Definitions::new(session.local_stable_crate_id(), krate.span); let root = definitions.get_root_def(); let mut visibilities = FxHashMap::default(); - visibilities.insert(root_local_def_id, ty::Visibility::Public); + visibilities.insert(CRATE_DEF_ID, ty::Visibility::Public); let mut def_id_to_node_id = IndexVec::default(); assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root); @@ -1341,7 +1368,6 @@ impl<'a> Resolver<'a> { empty_module, module_map, block_map: Default::default(), - extern_module_map: FxHashMap::default(), binding_parent_modules: FxHashMap::default(), ast_transform_scopes: FxHashMap::default(), @@ -1418,6 +1444,18 @@ impl<'a> Resolver<'a> { resolver } + fn new_module( + &mut self, + parent: Option>, + kind: ModuleKind, + expn_id: ExpnId, + span: Span, + no_implicit_prelude: bool, + ) -> Module<'a> { + let module_map = &mut self.module_map; + self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude, module_map) + } + fn create_stable_hashing_context(&self) -> ExpandHasher<'_, 'a> { ExpandHasher { source_map: CachingSourceMapView::new(self.session.source_map()), @@ -1554,7 +1592,7 @@ impl<'a> Resolver<'a> { if let Some(module) = current_trait { if self.trait_may_have_item(Some(module), assoc_item) { - let def_id = module.def_id().unwrap(); + let def_id = module.def_id(); found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] }); } } @@ -1632,18 +1670,6 @@ impl<'a> Resolver<'a> { import_ids } - fn new_module( - &self, - parent: Module<'a>, - kind: ModuleKind, - nearest_parent_mod: DefId, - expn_id: ExpnId, - span: Span, - ) -> Module<'a> { - let module = ModuleData::new(Some(parent), kind, nearest_parent_mod, expn_id, span); - self.arenas.alloc_module(module) - } - fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { let ident = ident.normalize_to_macros_2_0(); let disambiguator = if ident.name == kw::Underscore { @@ -2016,7 +2042,7 @@ impl<'a> Resolver<'a> { derive_fallback_lint_id: Option, ) -> Option<(Module<'a>, Option)> { if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some((self.macro_def_scope(ctxt.remove_mark()), None)); + return Some((self.expn_def_scope(ctxt.remove_mark()), None)); } if let ModuleKind::Block(..) = module.kind { @@ -2085,7 +2111,7 @@ impl<'a> Resolver<'a> { ModuleOrUniformRoot::Module(m) => { if let Some(def) = ident.span.normalize_to_macros_2_0_and_adjust(m.expansion) { tmp_parent_scope = - ParentScope { module: self.macro_def_scope(def), ..*parent_scope }; + ParentScope { module: self.expn_def_scope(def), ..*parent_scope }; adjusted_parent_scope = &tmp_parent_scope; } } @@ -2158,7 +2184,7 @@ impl<'a> Resolver<'a> { ctxt.adjust(ExpnId::root()) }; let module = match mark { - Some(def) => self.macro_def_scope(def), + Some(def) => self.expn_def_scope(def), None => { debug!( "resolve_crate_root({:?}): found no mark (ident.span = {:?})", @@ -2167,7 +2193,9 @@ impl<'a> Resolver<'a> { return self.graph_root; } }; - let module = self.get_module(DefId { index: CRATE_DEF_INDEX, ..module.nearest_parent_mod }); + let module = self.expect_module( + module.opt_def_id().map_or(LOCAL_CRATE, |def_id| def_id.krate).as_def_id(), + ); debug!( "resolve_crate_root({:?}): got module {:?} ({:?}) (ident.span = {:?})", ident, @@ -2179,10 +2207,10 @@ impl<'a> Resolver<'a> { } fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> { - let mut module = self.get_module(module.nearest_parent_mod); + let mut module = self.expect_module(module.nearest_parent_mod()); while module.span.ctxt().normalize_to_macros_2_0() != *ctxt { - let parent = module.parent.unwrap_or_else(|| self.macro_def_scope(ctxt.remove_mark())); - module = self.get_module(parent.nearest_parent_mod); + let parent = module.parent.unwrap_or_else(|| self.expn_def_scope(ctxt.remove_mark())); + module = self.expect_module(parent.nearest_parent_mod()); } module } @@ -2896,7 +2924,7 @@ impl<'a> Resolver<'a> { } fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { - vis.is_accessible_from(module.nearest_parent_mod, self) + vis.is_accessible_from(module.nearest_parent_mod(), self) } fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) { @@ -2920,7 +2948,7 @@ impl<'a> Resolver<'a> { self.binding_parent_modules.get(&PtrKey(modularized)), ) { (Some(macro_rules), Some(modularized)) => { - macro_rules.nearest_parent_mod == modularized.nearest_parent_mod + macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod() && modularized.is_ancestor_of(macro_rules) } _ => false, @@ -2964,7 +2992,15 @@ impl<'a> Resolver<'a> { (None, false) }; if !candidates.is_empty() { - diagnostics::show_candidates(&mut err, span, &candidates, instead, found_use); + diagnostics::show_candidates( + &self.definitions, + self.session, + &mut err, + span, + &candidates, + instead, + found_use, + ); } else if let Some((span, msg, sugg, appl)) = suggestion { err.span_suggestion(span, msg, sugg, appl); } @@ -2986,7 +3022,7 @@ impl<'a> Resolver<'a> { } let container = match parent.kind { - ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id().unwrap()), + ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()), ModuleKind::Block(..) => "block", }; @@ -3265,7 +3301,7 @@ impl<'a> Resolver<'a> { } else { self.crate_loader.maybe_process_path_extern(ident.name)? }; - let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); + let crate_root = self.expect_module(crate_id.as_def_id()); Some( (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT) .to_name_binding(self.arenas), @@ -3306,7 +3342,7 @@ impl<'a> Resolver<'a> { tokens: None, } }; - let module = self.get_module(module_id); + let module = self.expect_module(module_id); let parent_scope = &ParentScope::module(module, self); let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?; Ok((path, res)) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4dbac47c3cc8e..4f6e23d8f84f0 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -225,7 +225,8 @@ impl<'a> ResolverExpand for Resolver<'a> { features: &[Symbol], parent_module_id: Option, ) -> LocalExpnId { - let parent_module = parent_module_id.map(|module_id| self.local_def_id(module_id)); + let parent_module = + parent_module_id.map(|module_id| self.local_def_id(module_id).to_def_id()); let expn_id = LocalExpnId::fresh( ExpnData::allow_unstable( ExpnKind::AstPass(pass), @@ -233,13 +234,13 @@ impl<'a> ResolverExpand for Resolver<'a> { self.session.edition(), features.into(), None, - parent_module.map(LocalDefId::to_def_id), + parent_module, ), self.create_stable_hashing_context(), ); - let parent_scope = parent_module - .map_or(self.empty_module, |parent_def_id| self.module_map[&parent_def_id]); + let parent_scope = + parent_module.map_or(self.empty_module, |def_id| self.expect_module(def_id)); self.ast_transform_scopes.insert(expn_id, parent_scope); expn_id @@ -298,51 +299,18 @@ impl<'a> ResolverExpand for Resolver<'a> { )?; let span = invoc.span(); + let def_id = res.opt_def_id(); invoc_id.set_expn_data( ext.expn_data( parent_scope.expansion, span, fast_print_path(path), - res.opt_def_id(), - res.opt_def_id().map(|macro_def_id| { - self.macro_def_scope_from_def_id(macro_def_id).nearest_parent_mod - }), + def_id, + def_id.map(|def_id| self.macro_def_scope(def_id).nearest_parent_mod()), ), self.create_stable_hashing_context(), ); - if let Res::Def(_, _) = res { - // Gate macro attributes in `#[derive]` output. - if !self.session.features_untracked().macro_attributes_in_derive_output - && kind == MacroKind::Attr - && ext.builtin_name != Some(sym::derive) - { - let mut expn_id = parent_scope.expansion; - loop { - // Helper attr table is a quick way to determine whether the attr is `derive`. - if self.helper_attrs.contains_key(&expn_id) { - feature_err( - &self.session.parse_sess, - sym::macro_attributes_in_derive_output, - path.span, - "macro attributes in `#[derive]` output are unstable", - ) - .emit(); - break; - } else { - let expn_data = expn_id.expn_data(); - match expn_data.kind { - ExpnKind::Root - | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { - break; - } - _ => expn_id = expn_data.parent.expect_local(), - } - } - } - } - } - Ok(ext) } @@ -1169,7 +1137,7 @@ impl<'a> Resolver<'a> { } if let Some(depr) = &ext.deprecation { let path = pprust::path_to_string(&path); - let (message, lint) = stability::deprecation_message(depr, "macro", &path); + let (message, lint) = stability::deprecation_message_and_lint(depr, "macro", &path); stability::early_report_deprecation( &mut self.lint_buffer, &message, diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 3e99f4e29ef36..f4567b334836a 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -18,7 +18,7 @@ use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res}; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir_pretty::{bounds_to_string, fn_to_string, generic_params_to_string, ty_to_string}; use rustc_middle::hir::map::Map; @@ -128,7 +128,7 @@ impl<'tcx> DumpVisitor<'tcx> { self.save_ctxt.lookup_def_id(ref_id) } - pub fn dump_crate_info(&mut self, name: &str, krate: &hir::Crate<'_>) { + pub fn dump_crate_info(&mut self, name: &str) { let source_file = self.tcx.sess.local_crate_source_file.as_ref(); let crate_root = source_file.map(|source_file| { let source_file = Path::new(source_file); @@ -146,7 +146,7 @@ impl<'tcx> DumpVisitor<'tcx> { }, crate_root: crate_root.unwrap_or_else(|| "".to_owned()), external_crates: self.save_ctxt.get_external_crates(), - span: self.span_from_span(krate.module().inner), + span: self.span_from_span(self.tcx.def_span(CRATE_DEF_ID)), }; self.dumper.crate_prelude(data); @@ -682,7 +682,7 @@ impl<'tcx> DumpVisitor<'tcx> { ); } - // super-traits + // supertraits for super_bound in trait_refs.iter() { let (def_id, sub_span) = match *super_bound { hir::GenericBound::Trait(ref trait_ref, _) => ( @@ -1090,13 +1090,13 @@ impl<'tcx> DumpVisitor<'tcx> { } } - pub(crate) fn process_crate(&mut self, krate: &'tcx hir::Crate<'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 sm = self.tcx.sess.source_map(); - let krate_mod = krate.module(); + let krate_mod = self.tcx.hir().root_module(); let filename = sm.span_to_filename(krate_mod.inner); let data_id = id_from_hir_id(id, &self.save_ctxt); let children = diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 0f9257809fea7..543cd0247a53d 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -19,11 +19,11 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string}; use rustc_middle::hir::map::Map; -use rustc_middle::middle::cstore::ExternCrate; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, Input, OutputType}; +use rustc_session::cstore::ExternCrate; use rustc_session::output::{filename_for_metadata, out_filename}; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; @@ -1003,9 +1003,9 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( let mut visitor = DumpVisitor::new(save_ctxt); - visitor.dump_crate_info(cratename, tcx.hir().krate()); + visitor.dump_crate_info(cratename); visitor.dump_compilation_options(input, cratename); - visitor.process_crate(tcx.hir().krate()); + visitor.process_crate(); handler.save(&visitor.save_ctxt, &visitor.analysis()) }) diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 4cff21bee3dc3..37cfc4a0dc3c2 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -9,6 +9,7 @@ rustc_macros = { path = "../rustc_macros" } tracing = "0.1" rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } rustc_target = { path = "../rustc_target" } rustc_serialize = { path = "../rustc_serialize" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_session/src/cstore.rs similarity index 89% rename from compiler/rustc_middle/src/middle/cstore.rs rename to compiler/rustc_session/src/cstore.rs index 81c44b27033ec..9d6bd20103989 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -2,15 +2,12 @@ //! are *mostly* used as a part of that interface, but these should //! probably get a better home if someone can find one. -use crate::ty::TyCtxt; - +use crate::search_paths::PathKind; +use crate::utils::NativeLibKind; use rustc_ast as ast; use rustc_data_structures::sync::{self, MetadataRef}; use rustc_hir::def_id::{CrateNum, DefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; -use rustc_macros::HashStable; -use rustc_session::search_paths::PathKind; -use rustc_session::utils::NativeLibKind; use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -23,7 +20,7 @@ use std::path::{Path, PathBuf}; /// Where a crate came from on the local filesystem. One of these three options /// must be non-None. -#[derive(PartialEq, Clone, Debug, HashStable, Encodable, Decodable)] +#[derive(PartialEq, Clone, Debug, HashStable_Generic, Encodable, Decodable)] pub struct CrateSource { pub dylib: Option<(PathBuf, PathKind)>, pub rlib: Option<(PathBuf, PathKind)>, @@ -31,13 +28,14 @@ pub struct CrateSource { } impl CrateSource { + #[inline] pub fn paths(&self) -> impl Iterator { self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0) } } #[derive(Encodable, Decodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] -#[derive(HashStable)] +#[derive(HashStable_Generic)] pub enum CrateDepKind { /// A dependency that is only used for its macros. MacrosOnly, @@ -50,6 +48,7 @@ pub enum CrateDepKind { } impl CrateDepKind { + #[inline] pub fn macros_only(self) -> bool { match self { CrateDepKind::MacrosOnly => true, @@ -58,13 +57,13 @@ impl CrateDepKind { } } -#[derive(Copy, Debug, PartialEq, Clone, Encodable, Decodable, HashStable)] +#[derive(Copy, Debug, PartialEq, Clone, Encodable, Decodable, HashStable_Generic)] pub enum LinkagePreference { RequireDynamic, RequireStatic, } -#[derive(Debug, Encodable, Decodable, HashStable)] +#[derive(Debug, Encodable, Decodable, HashStable_Generic)] pub struct NativeLib { pub kind: NativeLibKind, pub name: Option, @@ -75,7 +74,7 @@ pub struct NativeLib { pub dll_imports: Vec, } -#[derive(Clone, Debug, Encodable, Decodable, HashStable)] +#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] pub struct DllImport { pub name: Symbol, pub ordinal: Option, @@ -92,7 +91,7 @@ pub struct DllImport { /// /// The usize value, where present, indicates the size of the function's argument list /// in bytes. -#[derive(Clone, PartialEq, Debug, Encodable, Decodable, HashStable)] +#[derive(Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)] pub enum DllCallingConvention { C, Stdcall(usize), @@ -100,13 +99,13 @@ pub enum DllCallingConvention { Vectorcall(usize), } -#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Clone, Encodable, Decodable, HashStable_Generic, Debug)] pub struct ForeignModule { pub foreign_items: Vec, pub def_id: DefId, } -#[derive(Copy, Clone, Debug, HashStable)] +#[derive(Copy, Clone, Debug, HashStable_Generic)] pub struct ExternCrate { pub src: ExternCrateSource, @@ -125,10 +124,12 @@ impl ExternCrate { /// If true, then this crate is the crate named by the extern /// crate referenced above. If false, then this crate is a dep /// of the crate. + #[inline] pub fn is_direct(&self) -> bool { self.dependency_of == LOCAL_CRATE } + #[inline] pub fn rank(&self) -> impl PartialOrd { // Prefer: // - direct extern crate to indirect @@ -137,7 +138,7 @@ impl ExternCrate { } } -#[derive(Copy, Clone, Debug, HashStable)] +#[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum ExternCrateSource { /// Crate is loaded by `extern crate`. Extern( @@ -150,17 +151,6 @@ pub enum ExternCrateSource { Path, } -#[derive(Encodable, Decodable)] -pub struct EncodedMetadata { - pub raw_data: Vec, -} - -impl EncodedMetadata { - pub fn new() -> EncodedMetadata { - EncodedMetadata { raw_data: Vec::new() } - } -} - /// The backend's way to give the crate store access to the metadata in a library. /// Note that it returns the raw metadata bytes stored in the library file, whether /// it is compressed, uncompressed, some weird mix, etc. @@ -204,9 +194,6 @@ pub trait CrateStore: std::fmt::Debug { /// Fetch a DefId from a DefPathHash for a foreign crate. fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId; fn expn_hash_to_expn_id(&self, cnum: CrateNum, index_guess: u32, hash: ExpnHash) -> ExpnId; - - // utility functions - fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata; } pub type CrateStoreDyn = dyn CrateStore + sync::Sync; diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 9a82ae3fc1090..6c86f86ecd9bb 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,4 +1,5 @@ #![feature(crate_visibility_modifier)] +#![feature(min_specialization)] #![feature(once_cell)] #![recursion_limit = "256"] @@ -14,6 +15,7 @@ pub mod parse; mod code_stats; #[macro_use] pub mod config; +pub mod cstore; pub mod filesearch; mod options; pub mod search_paths; @@ -28,4 +30,4 @@ pub use getopts; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext {} +pub trait HashStableContext: rustc_ast::HashStableContext + rustc_hir::HashStableContext {} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 8110afe75fa92..8ecb7a031ad81 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1246,6 +1246,8 @@ options! { "enable queries of the dependency graph for regression testing (default: no)"), query_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about the query system (default: no)"), + randomize_layout: bool = (false, parse_bool, [TRACKED], + "randomize the layout of types (default: no)"), relax_elf_relocations: Option = (None, parse_opt_bool, [TRACKED], "whether ELF relocations can be relaxed"), relro_level: Option = (None, parse_relro_level, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 27215556045be..bf04154a3dafe 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -2,10 +2,9 @@ use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use crate::config::{self, CrateType, OutputType, SwitchWithOptPath}; -use crate::filesearch; -use crate::lint::{self, LintId}; use crate::parse::ParseSess; use crate::search_paths::{PathKind, SearchPath}; +use crate::{filesearch, lint}; pub use rustc_ast::attr::MarkedAttrs; pub use rustc_ast::Attribute; @@ -41,10 +40,6 @@ use std::str::FromStr; use std::sync::Arc; use std::time::Duration; -pub trait SessionLintStore: sync::Send + sync::Sync { - fn name_to_lint(&self, lint_name: &str) -> LintId; -} - pub struct OptimizationFuel { /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`. remaining: u64, @@ -153,8 +148,6 @@ pub struct Session { features: OnceCell, - lint_store: OnceCell>, - incr_comp_session: OneThread>, /// Used for incremental compilation tests. Will only be populated if /// `-Zquery-dep-graph` is specified. @@ -169,9 +162,6 @@ pub struct Session { /// Data about code being compiled, gathered during compilation. pub code_stats: CodeStats, - /// If `-zfuel=crate=n` is specified, `Some(crate)`. - optimization_fuel_crate: Option, - /// Tracks fuel info if `-zfuel=crate=n` is specified. optimization_fuel: Lock, @@ -591,13 +581,6 @@ impl Session { } } - pub fn init_lint_store(&self, lint_store: Lrc) { - self.lint_store - .set(lint_store) - .map_err(|_| ()) - .expect("`lint_store` was initialized twice"); - } - /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { // If our target has codegen requirements ignore the command line @@ -896,7 +879,7 @@ impl Session { /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { let mut ret = true; - if let Some(ref c) = self.optimization_fuel_crate { + if let Some((ref c, _)) = self.opts.debugging_opts.fuel { if c == crate_name { assert_eq!(self.threads(), 1); let mut fuel = self.optimization_fuel.lock(); @@ -1274,7 +1257,6 @@ pub fn build_session( let local_crate_source_file = local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0); - let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); let optimization_fuel = Lock::new(OptimizationFuel { remaining: sopts.debugging_opts.fuel.as_ref().map_or(0, |i| i.1), out_of_fuel: false, @@ -1315,7 +1297,6 @@ pub fn build_session( crate_types: OnceCell::new(), stable_crate_id: OnceCell::new(), features: OnceCell::new(), - lint_store: OnceCell::new(), incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), cgu_reuse_tracker, prof, @@ -1326,7 +1307,6 @@ pub fn build_session( normalize_projection_ty: AtomicUsize::new(0), }, code_stats: Default::default(), - optimization_fuel_crate, optimization_fuel, print_fuel, jobserver: jobserver::client(), @@ -1404,7 +1384,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // Cannot enable crt-static with sanitizers on Linux if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() { sess.err( - "Sanitizer is incompatible with statically linked libc, \ + "sanitizer is incompatible with statically linked libc, \ disable it using `-C target-feature=-crt-static`", ); } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index ef60608a27c8b..aa15febe8853d 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -601,7 +601,10 @@ pub fn debug_hygiene_data(verbose: bool) -> String { let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID"); debug_expn_data((&id.to_expn_id(), expn_data)) }); - data.foreign_expn_data.iter().for_each(debug_expn_data); + // Sort the hash map for more reproducible output. + let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect(); + foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id)); + foreign_expn_data.into_iter().for_each(debug_expn_data); s.push_str("\n\nSyntaxContexts:"); data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| { s.push_str(&format!( @@ -1098,6 +1101,7 @@ pub enum DesugaringKind { Await, ForLoop(ForLoopLoc), LetElse, + WhileLoop, } /// A location in the desugaring of a `for` loop @@ -1119,6 +1123,7 @@ impl DesugaringKind { DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::ForLoop(_) => "`for` loop", DesugaringKind::LetElse => "`let...else`", + DesugaringKind::WhileLoop => "`while` loop", } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 11ca6c7d81d22..382dbc377d63e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -169,6 +169,7 @@ symbols! { Default, Deref, DirBuilder, + Display, DoubleEndedIterator, Duration, Encodable, @@ -194,6 +195,7 @@ symbols! { Hasher, Implied, Input, + Into, IntoIterator, IoRead, IoWrite, @@ -204,6 +206,7 @@ symbols! { Left, LinkedList, LintPass, + Mutex, None, Ok, Option, @@ -219,6 +222,7 @@ symbols! { PathBuf, Pending, Pin, + Pointer, Poll, ProcMacro, ProcMacroHack, @@ -242,6 +246,7 @@ symbols! { Send, SeqCst, Some, + String, StructuralEq, StructuralPartialEq, Sync, @@ -249,12 +254,15 @@ symbols! { ToOwned, ToString, Try, + TryFrom, + TryInto, Ty, TyCtxt, TyKind, Unknown, UnsafeArg, Vec, + VecDeque, Yield, _DECLS, _Self, @@ -391,6 +399,7 @@ symbols! { cfg_attr_multi, cfg_doctest, cfg_eval, + cfg_hide, cfg_panic, cfg_sanitize, cfg_target_abi, @@ -408,6 +417,7 @@ symbols! { clone_from, closure, closure_to_fn_coercion, + closure_track_caller, cmp, cmp_max, cmp_min, @@ -506,7 +516,6 @@ symbols! { debug_assert_macro, debug_assertions, debug_struct, - debug_trait, debug_trait_builder, debug_tuple, decl_macro, @@ -539,6 +548,7 @@ symbols! { doc, doc_alias, doc_cfg, + doc_cfg_hide, doc_keyword, doc_masked, doc_notable_trait, @@ -652,7 +662,6 @@ symbols! { from_output, from_residual, from_size_align_unchecked, - from_trait, from_usize, fsub_fast, fundamental, @@ -675,8 +684,6 @@ symbols! { gt, half_open_range_patterns, hash, - hashmap_type, - hashset_type, hexagon_target_feature, hidden, homogeneous_aggregate, @@ -721,7 +728,6 @@ symbols! { instruction_set, intel, into_iter, - into_trait, intra_doc_pointers, intrinsics, irrefutable_let_patterns, @@ -912,7 +918,6 @@ symbols! { optin_builtin_traits, option, option_env, - option_type, options, or, or_patterns, @@ -954,7 +959,6 @@ symbols! { plugins, pointee_trait, pointer, - pointer_trait, pointer_trait_fmt, poll, position, @@ -1050,7 +1054,6 @@ symbols! { repr_transparent, residual, result, - result_type, rhs, rintf32, rintf64, @@ -1151,7 +1154,6 @@ symbols! { self_in_typedefs, self_struct_ctor, semitransparent, - send_trait, shl, shl_assign, should_panic, @@ -1261,7 +1263,6 @@ symbols! { store, str, str_alloc, - string_type, stringify, struct_field_attributes, struct_inherit, @@ -1276,7 +1277,6 @@ symbols! { suggestion, sym, sync, - sync_trait, t32, target_abi, target_arch, @@ -1322,9 +1322,7 @@ symbols! { truncf64, try_blocks, try_from, - try_from_trait, try_into, - try_into_trait, try_trait_v2, tt, tuple, @@ -1396,8 +1394,6 @@ symbols! { var, variant_count, vec, - vec_type, - vecdeque_type, version, vis, visible_private_types, @@ -1617,7 +1613,7 @@ impl fmt::Display for MacroRulesNormalizedIdent { pub struct Symbol(SymbolIndex); rustc_index::newtype_index! { - pub struct SymbolIndex { .. } + struct SymbolIndex { .. } } impl Symbol { @@ -1643,10 +1639,6 @@ impl Symbol { self.0.as_u32() } - pub fn len(self) -> usize { - with_session_globals(|session_globals| session_globals.symbol_interner.get(self).len()) - } - pub fn is_empty(self) -> bool { self == kw::Empty } diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index d5befa10e2363..b9751f0adb517 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -16,4 +16,5 @@ rustc_middle = { path = "../rustc_middle" } rustc_hir = { path = "../rustc_hir" } rustc_target = { path = "../rustc_target" } rustc_data_structures = { path = "../rustc_data_structures" } +rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index e236ef996bcc6..de18614360ef5 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -1,12 +1,12 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::ich::NodeIdHashingMode; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::print::{PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_middle::util::common::record_time; +use rustc_query_system::ich::NodeIdHashingMode; use tracing::debug; diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 183df96f31668..f7d68b5cc7061 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -23,7 +23,7 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) { tcx.dep_graph.with_ignore(|| { let mut visitor = SymbolNamesTest { tcx }; - tcx.hir().krate().visit_all_item_likes(&mut visitor); + tcx.hir().visit_all_item_likes(&mut visitor); }) } diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index e75c52555b903..23d5d575d9447 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -15,7 +15,6 @@ #![feature(exhaustive_patterns)] #![feature(min_specialization)] #![feature(step_trait)] -#![feature(unchecked_math)] use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs b/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs new file mode 100644 index 0000000000000..61e3be617e9c1 --- /dev/null +++ b/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs @@ -0,0 +1,19 @@ +use super::{RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + let base = super::solid_base::opts("asp3"); + Target { + llvm_target: "aarch64-unknown-none".to_string(), + pointer_width: 64, + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), + arch: "aarch64".to_string(), + options: TargetOptions { + linker: Some("aarch64-kmc-elf-gcc".to_owned()), + features: "+neon,+fp-armv8".to_string(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(128), + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs new file mode 100644 index 0000000000000..344c48022b2fa --- /dev/null +++ b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs @@ -0,0 +1,19 @@ +use super::{RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + let base = super::solid_base::opts("asp3"); + Target { + llvm_target: "armv7a-none-eabi".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + options: TargetOptions { + linker: Some("arm-kmc-eabi-gcc".to_owned()), + features: "+v7,+soft-float,+thumb2,-neon".to_string(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs new file mode 100644 index 0000000000000..375502478fe97 --- /dev/null +++ b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs @@ -0,0 +1,19 @@ +use super::{RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + let base = super::solid_base::opts("asp3"); + Target { + llvm_target: "armv7a-none-eabihf".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), + arch: "arm".to_string(), + options: TargetOptions { + linker: Some("arm-kmc-eabi-gcc".to_owned()), + features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + ..base + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index c947721d63d39..5276da1ba5a1c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -75,6 +75,7 @@ mod netbsd_base; mod openbsd_base; mod redox_base; mod solaris_base; +mod solid_base; mod thumb_base; mod uefi_msvc_base; mod vxworks_base; @@ -287,6 +288,7 @@ impl ToJson for MergeFunctions { pub enum RelocModel { Static, Pic, + Pie, DynamicNoPic, Ropi, Rwpi, @@ -300,6 +302,7 @@ impl FromStr for RelocModel { Ok(match s { "static" => RelocModel::Static, "pic" => RelocModel::Pic, + "pie" => RelocModel::Pie, "dynamic-no-pic" => RelocModel::DynamicNoPic, "ropi" => RelocModel::Ropi, "rwpi" => RelocModel::Rwpi, @@ -314,6 +317,7 @@ impl ToJson for RelocModel { match *self { RelocModel::Static => "static", RelocModel::Pic => "pic", + RelocModel::Pie => "pie", RelocModel::DynamicNoPic => "dynamic-no-pic", RelocModel::Ropi => "ropi", RelocModel::Rwpi => "rwpi", @@ -932,6 +936,10 @@ supported_targets! { ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe), ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks), + ("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3), + ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi), + ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf), + ("mipsel-sony-psp", mipsel_sony_psp), ("mipsel-unknown-none", mipsel_unknown_none), ("thumbv4t-none-eabi", thumbv4t_none_eabi), diff --git a/compiler/rustc_target/src/spec/solid_base.rs b/compiler/rustc_target/src/spec/solid_base.rs new file mode 100644 index 0000000000000..c6a279d92e839 --- /dev/null +++ b/compiler/rustc_target/src/spec/solid_base.rs @@ -0,0 +1,12 @@ +use super::FramePointer; +use crate::spec::TargetOptions; + +pub fn opts(kernel: &str) -> TargetOptions { + TargetOptions { + os: format!("solid_{}", kernel), + vendor: "kmc".to_string(), + frame_pointer: FramePointer::NonLeaf, + has_elf_tls: true, + ..Default::default() + } +} diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 9a9737362c6c8..d59bdae0332cb 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -17,7 +17,9 @@ rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } +rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 969962e55b0df..53afe4ca068c4 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; use rustc_middle::ty::{ToPredicate, TypeFoldable}; -use rustc_session::DiagnosticMessageId; +use rustc_session::{DiagnosticMessageId, Limit}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::Span; @@ -135,7 +135,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { let obligation = traits::Obligation::new( cause.clone(), self.param_env, - trait_ref.without_const().to_predicate(tcx), + ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), ); if !self.infcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); @@ -217,7 +217,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { // We've reached the recursion limit, error gracefully. - let suggested_limit = tcx.recursion_limit() * 2; + let suggested_limit = match tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; let msg = format!("reached the recursion limit while auto-dereferencing `{:?}`", ty); let error_id = (DiagnosticMessageId::ErrorId(55), Some(span), msg); let fresh = tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); @@ -231,7 +234,8 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa ) .span_label(span, "deref recursion limit reached") .help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", suggested_limit, tcx.crate_name(LOCAL_CRATE), )) diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 42cbed600d5bf..8fb4eb641c26a 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -120,7 +120,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { cause: traits::ObligationCause::dummy(), param_env, recursion_depth: 0, - predicate: trait_ref.without_const().to_predicate(self.tcx), + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx), }; self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr) } diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index c01faae5d6a51..c2205462680fc 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -517,6 +517,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { debug!(?id_substs); let map: FxHashMap, GenericArg<'tcx>> = substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); + debug!("map = {:#?}", map); // Convert the type from the function into a type valid outside // the function, by replacing invalid regions with 'static, @@ -672,6 +673,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { self.tcx } + #[instrument(skip(self), level = "debug")] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match r { // Ignore bound regions and `'static` regions that appear in the @@ -1062,11 +1064,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { /// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`), /// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`. /// For the above example, this function returns `true` for `f1` and `false` for `f2`. -pub fn may_define_opaque_type( - tcx: TyCtxt<'_>, - def_id: LocalDefId, - opaque_hir_id: hir::HirId, -) -> bool { +fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool { let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id); // Named opaque types can be defined by any siblings or children of siblings. @@ -1102,18 +1100,17 @@ pub fn may_define_opaque_type( /// /// Requires that trait definitions have been processed so that we can /// elaborate predicates and walk supertraits. +#[instrument(skip(tcx, predicates), level = "debug")] crate fn required_region_bounds( tcx: TyCtxt<'tcx>, erased_self_ty: Ty<'tcx>, predicates: impl Iterator>, ) -> Vec> { - debug!("required_region_bounds(erased_self_ty={:?})", erased_self_ty); - assert!(!erased_self_ty.has_escaping_bound_vars()); traits::elaborate_predicates(tcx, predicates) .filter_map(|obligation| { - debug!("required_region_bounds(obligation={:?})", obligation); + debug!(?obligation); match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Projection(..) | ty::PredicateKind::Trait(..) diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs index 9c962d30ce0e8..ec62ee400688c 100644 --- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -7,16 +7,21 @@ use crate::traits::{ ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, PredicateObligation, SelectionError, TraitEngine, }; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_middle::ty::{self, Ty}; pub struct FulfillmentContext<'tcx> { obligations: FxIndexSet>, + + relationships: FxHashMap, } impl FulfillmentContext<'tcx> { crate fn new() -> Self { - FulfillmentContext { obligations: FxIndexSet::default() } + FulfillmentContext { + obligations: FxIndexSet::default(), + relationships: FxHashMap::default(), + } } } @@ -39,6 +44,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { assert!(!infcx.is_in_snapshot()); let obligation = infcx.resolve_vars_if_possible(obligation); + super::relationships::update(self, infcx, &obligation); + self.obligations.insert(obligation); } @@ -146,4 +153,8 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn pending_obligations(&self) -> Vec> { self.obligations.iter().cloned().collect() } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 24fa5007f1ecd..25ec9682d8407 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -236,16 +236,27 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.body.exprs[self.body_id].span } - fn error(&mut self, span: Option, msg: &str) -> Result { + fn error(&mut self, span: Span, msg: &str) -> Result { self.tcx .sess .struct_span_err(self.root_span(), "overly complex generic constant") - .span_label(span.unwrap_or(self.root_span()), msg) + .span_label(span, msg) .help("consider moving this anonymous constant into a `const` function") .emit(); Err(ErrorReported) } + fn maybe_supported_error(&mut self, span: Span, msg: &str) -> Result { + self.tcx + .sess + .struct_span_err(self.root_span(), "overly complex generic constant") + .span_label(span, msg) + .help("consider moving this anonymous constant into a `const` function") + .note("this operation may be supported in the future") + .emit(); + + Err(ErrorReported) + } fn new( tcx: TyCtxt<'tcx>, @@ -337,14 +348,14 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { Ok(match &node.kind { // I dont know if handling of these 3 is correct &ExprKind::Scope { value, .. } => self.recurse_build(value)?, - &ExprKind::PlaceTypeAscription { source, .. } | - &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, + &ExprKind::PlaceTypeAscription { source, .. } + | &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?, // subtle: associated consts are literals this arm handles // `::ASSOC` as well as `12` &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)), - ExprKind::Call { fun, args, .. } => { + ExprKind::Call { fun, args, .. } => { let fun = self.recurse_build(*fun)?; let mut new_args = Vec::::with_capacity(args.len()); @@ -353,7 +364,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } let new_args = self.tcx.arena.alloc_slice(&new_args); self.nodes.push(Node::FunctionCall(fun, new_args)) - }, + } &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => { let lhs = self.recurse_build(lhs)?; let rhs = self.recurse_build(rhs)?; @@ -362,7 +373,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { &ExprKind::Unary { op, arg } if Self::check_unop(op) => { let arg = self.recurse_build(arg)?; self.nodes.push(Node::UnaryOp(op, arg)) - }, + } // This is necessary so that the following compiles: // // ``` @@ -370,60 +381,100 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { // bar::<{ N + 1 }>(); // } // ``` - ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?, + ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => { + self.recurse_build(*e)? + } // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a // "coercion cast" i.e. using a coercion or is a no-op. // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested) &ExprKind::Use { source } => { let arg = self.recurse_build(source)?; self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty)) - }, + } &ExprKind::Cast { source } => { let arg = self.recurse_build(source)?; self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty)) - }, + } // FIXME(generic_const_exprs): We may want to support these. ExprKind::AddressOf { .. } | ExprKind::Borrow { .. } - | ExprKind::Deref { .. } - | ExprKind::Repeat { .. } - | ExprKind::Array { .. } - | ExprKind::Block { .. } - | ExprKind::NeverToAny { .. } - | ExprKind::Tuple { .. } - | ExprKind::Index { .. } - | ExprKind::Field { .. } - | ExprKind::ConstBlock { .. } - | ExprKind::Adt(_) => self.error( - Some(node.span), - "unsupported operation in generic constant, this may be supported in the future", + | ExprKind::Deref { .. } => self.maybe_supported_error( + node.span, + "dereferencing is not supported in generic constants", + )?, + ExprKind::Repeat { .. } | ExprKind::Array { .. } => self.maybe_supported_error( + node.span, + "array construction is not supported in generic constants", + )?, + ExprKind::Block { .. } => self.maybe_supported_error( + node.span, + "blocks are not supported in generic constant", + )?, + ExprKind::NeverToAny { .. } => self.maybe_supported_error( + node.span, + "converting nevers to any is not supported in generic constant", + )?, + ExprKind::Tuple { .. } => self.maybe_supported_error( + node.span, + "tuple construction is not supported in generic constants", + )?, + ExprKind::Index { .. } => self.maybe_supported_error( + node.span, + "indexing is not supported in generic constant", + )?, + ExprKind::Field { .. } => self.maybe_supported_error( + node.span, + "field access is not supported in generic constant", + )?, + ExprKind::ConstBlock { .. } => self.maybe_supported_error( + node.span, + "const blocks are not supported in generic constant", + )?, + ExprKind::Adt(_) => self.maybe_supported_error( + node.span, + "struct/enum construction is not supported in generic constants", + )?, + // dont know if this is correct + ExprKind::Pointer { .. } => + self.error(node.span, "pointer casts are not allowed in generic constants")?, + ExprKind::Yield { .. } => + self.error(node.span, "generator control flow is not allowed in generic constants")?, + ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Loop { .. } => self + .error( + node.span, + "loops and loop control flow are not supported in generic constants", )?, + ExprKind::Box { .. } => + self.error(node.span, "allocations are not allowed in generic constants")?, + + ExprKind::Unary { .. } => unreachable!(), + // we handle valid unary/binary ops above + ExprKind::Binary { .. } => + self.error(node.span, "unsupported binary operation in generic constants")?, + ExprKind::LogicalOp { .. } => + self.error(node.span, "unsupported operation in generic constants, short-circuiting operations would imply control flow")?, + ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { + self.error(node.span, "assignment is not supported in generic constants")? + } + ExprKind::Closure { .. } | ExprKind::Return { .. } => self.error( + node.span, + "closures and function keywords are not supported in generic constants", + )?, + // let expressions imply control flow + ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } => + self.error(node.span, "control flow is not supported in generic constants")?, + ExprKind::LlvmInlineAsm { .. } | ExprKind::InlineAsm { .. } => { + self.error(node.span, "assembly is not supported in generic constants")? + } - ExprKind::Match { .. } // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen - | ExprKind::VarRef { .. } + ExprKind::VarRef { .. } | ExprKind::UpvarRef { .. } - | ExprKind::Closure { .. } - | ExprKind::Let { .. } // let expressions imply control flow - | ExprKind::Loop { .. } - | ExprKind::Assign { .. } | ExprKind::StaticRef { .. } - | ExprKind::LogicalOp { .. } - // we handle valid unary/binary ops above - | ExprKind::Unary { .. } - | ExprKind::Binary { .. } - | ExprKind::Break { .. } - | ExprKind::Continue { .. } - | ExprKind::If { .. } - | ExprKind::Pointer { .. } // dont know if this is correct - | ExprKind::ThreadLocalRef(_) - | ExprKind::LlvmInlineAsm { .. } - | ExprKind::Return { .. } - | ExprKind::Box { .. } // allocations not allowed in constants - | ExprKind::AssignOp { .. } - | ExprKind::InlineAsm { .. } - | ExprKind::Yield { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?, + | ExprKind::ThreadLocalRef(_) => { + self.error(node.span, "unsupported operation in generic constant")? + } }) } } 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 e435154d9318e..88e8df81488e6 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -516,12 +516,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); let unit_obligation = obligation.with(predicate.to_predicate(tcx)); if self.predicate_may_hold(&unit_obligation) { - err.note("this trait is implemented for `()`."); + err.note("this trait is implemented for `()`"); err.note( "this error might have been caused by changes to \ Rust's type-inference algorithm (see issue #48950 \ \ - for more information).", + for more information)", ); err.help("did you intend to use the type `()` here instead?"); } @@ -533,9 +533,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // example). let trait_is_debug = - self.tcx.is_diagnostic_item(sym::debug_trait, trait_ref.def_id()); + self.tcx.is_diagnostic_item(sym::Debug, trait_ref.def_id()); let trait_is_display = - self.tcx.is_diagnostic_item(sym::display_trait, trait_ref.def_id()); + self.tcx.is_diagnostic_item(sym::Display, trait_ref.def_id()); let in_std_macro = match obligation.cause.span.ctxt().outer_expn_data().macro_def_id { @@ -1195,13 +1195,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { false } + #[instrument(skip(self), level = "debug")] fn report_fulfillment_error( &self, error: &FulfillmentError<'tcx>, body_id: Option, fallback_has_occurred: bool, ) { - debug!("report_fulfillment_error({:?})", error); match error.code { FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { self.report_selection_error( @@ -1528,6 +1528,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ) } + #[instrument(skip(self), level = "debug")] fn maybe_report_ambiguity( &self, obligation: &PredicateObligation<'tcx>, @@ -1542,8 +1543,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let span = obligation.cause.span; debug!( - "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})", - predicate, obligation, body_id, obligation.cause.code, + ?predicate, ?obligation.cause.code, ); // Ambiguity errors are often caused as fallout from earlier @@ -1556,7 +1556,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let mut err = match bound_predicate.skip_binder() { ty::PredicateKind::Trait(data) => { let trait_ref = bound_predicate.rebind(data.trait_ref); - debug!("trait_ref {:?}", trait_ref); + debug!(?trait_ref); if predicate.references_error() { return; 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 ae61988928f78..a73d2285d4576 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -10,7 +10,9 @@ use crate::traits::normalize_projection_type; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; -use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style}; +use rustc_errors::{ + error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, +}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -22,6 +24,7 @@ use rustc_middle::ty::{ Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; +use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, ForLoopLoc, MultiSpan, Span, DUMMY_SP}; @@ -675,7 +678,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>, + poly_trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>, has_custom_message: bool, ) -> bool { let span = obligation.cause.span; @@ -701,10 +704,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok()) .collect(); - never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::send_trait).unwrap()); + never_suggest_borrow.push(self.tcx.get_diagnostic_item(sym::Send).unwrap()); let param_env = obligation.param_env; - let trait_ref = trait_ref.skip_binder(); + let trait_ref = poly_trait_ref.skip_binder(); let found_ty = trait_ref.self_ty(); let found_ty_str = found_ty.to_string(); @@ -714,22 +717,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]); // Try to apply the original trait binding obligation by borrowing. - let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>, - expected_trait_ref: ty::TraitRef<'tcx>, - mtbl: bool, + let mut try_borrowing = |new_imm_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + new_mut_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, blacklist: &[DefId]| -> bool { - if blacklist.contains(&expected_trait_ref.def_id) { + if blacklist.contains(&expected_trait_ref.def_id()) { return false; } - let new_obligation = Obligation::new( + let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new( ObligationCause::dummy(), param_env, - new_trait_ref.without_const().to_predicate(self.tcx), - ); + new_imm_trait_ref.without_const().to_predicate(self.tcx), + )); - if self.predicate_must_hold_modulo_regions(&new_obligation) { + let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new( + ObligationCause::dummy(), + param_env, + new_mut_trait_ref.without_const().to_predicate(self.tcx), + )); + + if imm_result || mut_result { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { // We have a very specific type of error, where just borrowing this argument // might solve the problem. In cases like this, the important part is the @@ -773,15 +782,24 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // } // ``` - err.span_suggestion( - span, - &format!( - "consider{} borrowing here", - if mtbl { " mutably" } else { "" } - ), - format!("&{}{}", if mtbl { "mut " } else { "" }, snippet), - Applicability::MaybeIncorrect, - ); + if imm_result && mut_result { + err.span_suggestions( + span.shrink_to_lo(), + "consider borrowing here", + ["&".to_string(), "&mut ".to_string()].into_iter(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "consider{} borrowing here", + if mut_result { " mutably" } else { "" } + ), + format!("&{}", if mut_result { "mut " } else { "" }), + Applicability::MaybeIncorrect, + ); + } } return true; } @@ -790,34 +808,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code { - let expected_trait_ref = obligation.parent_trait_ref.skip_binder(); - let new_imm_trait_ref = - ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs); - let new_mut_trait_ref = - ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs); - if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) { - return true; - } else { - return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]); - } + let expected_trait_ref = obligation.parent_trait_ref; + let new_imm_trait_ref = poly_trait_ref + .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs)); + let new_mut_trait_ref = poly_trait_ref + .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs)); + return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]); } else if let ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ItemObligation(_) = &*code { - if try_borrowing( - ty::TraitRef::new(trait_ref.def_id, imm_substs), - trait_ref, - false, + return try_borrowing( + poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, imm_substs)), + poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, mut_substs)), + *poly_trait_ref, &never_suggest_borrow[..], - ) { - return true; - } else { - return try_borrowing( - ty::TraitRef::new(trait_ref.def_id, mut_substs), - trait_ref, - true, - &never_suggest_borrow[..], - ); - } + ); } else { false } @@ -1631,12 +1636,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Special case the primary error message when send or sync is the trait that was // not implemented. - let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id); - let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id); let hir = self.tcx.hir(); - let trait_explanation = if is_send || is_sync { + let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) = + self.tcx.get_diagnostic_name(trait_ref.def_id) + { let (trait_name, trait_verb) = - if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; + if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; err.clear_code(); err.set_primary_message(format!( @@ -2270,7 +2275,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { parent_trait_ref = child_trait_ref; } if count > 0 { - err.note(&format!("{} redundant requirements hidden", count)); + err.note(&format!( + "{} redundant requirement{} hidden", + count, + pluralize!(count) + )); err.note(&format!( "required because of the requirements on the impl of `{}` for `{}`", parent_trait_ref.print_only_trait_path(), @@ -2424,10 +2433,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { - let current_limit = self.tcx.recursion_limit(); - let suggested_limit = current_limit * 2; + let suggested_limit = match self.tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", + "consider increasing the recursion limit by adding a \ + `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", suggested_limit, self.tcx.crate_name(LOCAL_CRATE), )); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index b376f42929249..465d1465d5d35 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,4 +1,5 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; @@ -53,6 +54,9 @@ pub struct FulfillmentContext<'tcx> { // A list of all obligations that have been registered with this // fulfillment context. predicates: ObligationForest>, + + relationships: FxHashMap, + // Should this fulfillment context register type-lives-for-region // obligations on its parent infcx? In some cases, region // obligations are either already known to hold (normalization) or @@ -97,6 +101,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: true, usable_in_snapshot: false, } @@ -105,6 +110,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { pub fn new_in_snapshot() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: true, usable_in_snapshot: true, } @@ -113,6 +119,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), + relationships: FxHashMap::default(), register_region_obligations: false, usable_in_snapshot: false, } @@ -210,6 +217,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); + super::relationships::update(self, infcx, &obligation); + self.predicates .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } @@ -265,6 +274,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn pending_obligations(&self) -> Vec> { self.predicates.map_pending_obligations(|o| o.obligation.clone()) } + + fn relationships(&mut self) -> &mut FxHashMap { + &mut self.relationships + } } struct FulfillProcessor<'a, 'b, 'tcx> { @@ -405,7 +418,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { | ty::PredicateKind::Coerce(_) | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) => { - let pred = infcx.replace_bound_vars_with_placeholders(binder); + let pred = + ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder)); ProcessResult::Changed(mk_pending(vec![ obligation.with(pred.to_predicate(self.selcx.tcx())), ])) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index ef208c44471cb..b31d6d68b0a24 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -15,6 +15,7 @@ mod object_safety; mod on_unimplemented; mod project; pub mod query; +pub(crate) mod relationships; mod select; mod specialize; mod structural_match; @@ -63,7 +64,9 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; pub use self::structural_match::search_for_structural_match_violation; pub use self::structural_match::NonStructuralMatchTy; -pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; +pub use self::util::{ + elaborate_obligations, elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs, +}; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{ get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, @@ -139,7 +142,8 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( infcx.tcx.def_path_str(def_id) ); - let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; + let trait_ref = + ty::Binder::dummy(ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }); let obligation = Obligation { param_env, cause: ObligationCause::misc(span, hir::CRATE_HIR_ID), @@ -621,7 +625,7 @@ fn dump_vtable_entries<'tcx>( trait_ref: ty::PolyTraitRef<'tcx>, entries: &[VtblEntry<'tcx>], ) { - let msg = format!("Vtable entries for `{}`: {:#?}", trait_ref, entries); + let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries); tcx.sess.struct_span_err(sp, &msg).emit(); } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 4922cf45a4a10..0bb00dfeb43ad 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -250,7 +250,7 @@ fn predicates_reference_self( trait_def_id: DefId, supertraits_only: bool, ) -> SmallVec<[Span; 1]> { - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); + let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); let predicates = if supertraits_only { tcx.super_predicates_of(trait_def_id) } else { @@ -554,11 +554,11 @@ fn object_ty_for_trait<'tcx>( let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); - let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait( - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), - )); + let trait_predicate = trait_ref.map_bound(|trait_ref| { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) + }); - let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) + let mut associated_types = traits::supertraits(tcx, trait_ref) .flat_map(|super_trait_ref| { tcx.associated_items(super_trait_ref.def_id()) .in_definition_order() @@ -671,10 +671,10 @@ fn receiver_is_dispatchable<'tcx>( let param_env = tcx.param_env(method.def_id); // Self: Unsize - let unsize_predicate = ty::TraitRef { + let unsize_predicate = ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), - } + }) .without_const() .to_predicate(tcx); @@ -689,7 +689,9 @@ fn receiver_is_dispatchable<'tcx>( } }); - ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate(tcx) + ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs }) + .without_const() + .to_predicate(tcx) }; let caller_bounds: Vec> = param_env @@ -703,10 +705,10 @@ fn receiver_is_dispatchable<'tcx>( // Receiver: DispatchFromDyn U]> let obligation = { - let predicate = ty::TraitRef { + let predicate = ty::Binder::dummy(ty::TraitRef { def_id: dispatch_from_dyn_did, substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), - } + }) .without_const() .to_predicate(tcx); @@ -789,8 +791,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // Compute supertraits of current trait lazily. if self.supertraits.is_none() { - let trait_ref = - ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id)); + let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id); self.supertraits = Some( traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(), ); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 58589e556f270..47b006985ec56 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -27,7 +27,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; use rustc_span::symbol::sym; use std::collections::BTreeMap; @@ -388,15 +388,15 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // to make sure we don't forget to fold the substs regardless. match *ty.kind() { - ty::Opaque(def_id, substs) => { + // This is really important. While we *can* handle this, this has + // severe performance implications for large opaque types with + // late-bound regions. See `issue-88862` benchmark. + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), Reveal::All => { - // N.b. there is an assumption here all this code can handle - // escaping bound vars. - let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { let obligation = Obligation::with_depth( @@ -1028,7 +1028,7 @@ fn normalize_to_error<'a, 'tcx>( cause: ObligationCause<'tcx>, depth: usize, ) -> NormalizedTy<'tcx> { - let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref(); + let trait_ref = ty::Binder::dummy(projection_ty.trait_ref(selcx.tcx())); let trait_obligation = Obligation { cause, recursion_depth: depth, @@ -1290,7 +1290,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref(); + let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx())); let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); let _ = selcx.infcx().commit_if_ok(|_| { let impl_source = match selcx.select(&trait_obligation) { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index ed5fe466c69f7..1364cf1c99535 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -206,15 +206,15 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // Wrap this in a closure so we don't accidentally return from the outer function let res = (|| match *ty.kind() { - ty::Opaque(def_id, substs) => { + // This is really important. While we *can* handle this, this has + // severe performance implications for large opaque types with + // late-bound regions. See `issue-88862` benchmark. + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), Reveal::All => { - // N.b. there is an assumption here all this code can handle - // escaping bound vars. - let substs = substs.super_fold_with(self); let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { diff --git a/compiler/rustc_trait_selection/src/traits/relationships.rs b/compiler/rustc_trait_selection/src/traits/relationships.rs new file mode 100644 index 0000000000000..7751dd84f4cac --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/relationships.rs @@ -0,0 +1,69 @@ +use crate::infer::InferCtxt; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{ObligationCause, PredicateObligation}; +use rustc_infer::traits::TraitEngine; +use rustc_middle::ty::{self, ToPredicate}; + +pub(crate) fn update<'tcx, T>( + engine: &mut T, + infcx: &InferCtxt<'_, 'tcx>, + obligation: &PredicateObligation<'tcx>, +) where + T: TraitEngine<'tcx>, +{ + // (*) binder skipped + if let ty::PredicateKind::Trait(predicate) = obligation.predicate.kind().skip_binder() { + if let Some(ty) = + infcx.shallow_resolve(predicate.self_ty()).ty_vid().map(|t| infcx.root_var(t)) + { + if infcx + .tcx + .lang_items() + .sized_trait() + .map_or(false, |st| st != predicate.trait_ref.def_id) + { + let new_self_ty = infcx.tcx.types.unit; + + let trait_ref = ty::TraitRef { + substs: infcx + .tcx + .mk_substs_trait(new_self_ty, &predicate.trait_ref.substs[1..]), + ..predicate.trait_ref + }; + + // Then contstruct a new obligation with Self = () added + // to the ParamEnv, and see if it holds. + let o = rustc_infer::traits::Obligation::new( + ObligationCause::dummy(), + obligation.param_env, + obligation + .predicate + .kind() + .map_bound(|_| { + // (*) binder moved here + ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref, + constness: predicate.constness, + }) + }) + .to_predicate(infcx.tcx), + ); + // Don't report overflow errors. Otherwise equivalent to may_hold. + if let Ok(result) = infcx.probe(|_| infcx.evaluate_obligation(&o)) { + if result.may_apply() { + engine.relationships().entry(ty).or_default().self_in_trait = true; + } + } + } + } + } + + if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() { + // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, + // we need to make it into one. + if let Some(vid) = predicate.ty.ty_vid() { + debug!("relationship: {:?}.output = true", vid); + engine.relationships().entry(vid).or_default().output = true; + } + } +} 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 6d64dc8254bb4..f3706aa6e71aa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -6,12 +6,17 @@ //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::traits::TraitEngine; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness}; use rustc_target::spec::abi::Abi; +use crate::traits; use crate::traits::coherence::Conflict; +use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{util, SelectionResult}; use crate::traits::{Overflow, Unimplemented}; @@ -220,6 +225,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation) } + #[instrument(skip(self, stack), level = "debug")] pub(super) fn assemble_candidates<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -475,7 +481,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .. } = self_ty.fn_sig(self.tcx()).skip_binder() { - candidates.vec.push(FnPointerCandidate); + candidates.vec.push(FnPointerCandidate { is_const: false }); } } // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). @@ -488,7 +494,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } = self_ty.fn_sig(self.tcx()).skip_binder() { if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { - candidates.vec.push(FnPointerCandidate); + candidates + .vec + .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); } } } @@ -669,6 +677,55 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } + /// Temporary migration for #89190 + fn need_migrate_deref_output_trait_object( + &mut self, + ty: Ty<'tcx>, + cause: &traits::ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Option<(Ty<'tcx>, DefId)> { + let tcx = self.tcx(); + if tcx.features().trait_upcasting { + return None; + } + + // + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().deref_trait()?, + substs: tcx.mk_substs_trait(ty, &[]), + }; + + let obligation = traits::Obligation::new( + cause.clone(), + param_env, + ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + ); + if !self.infcx.predicate_may_hold(&obligation) { + return None; + } + + let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); + let normalized_ty = fulfillcx.normalize_projection_type( + &self.infcx, + param_env, + ty::ProjectionTy { + item_def_id: tcx.lang_items().deref_target()?, + substs: trait_ref.substs, + }, + cause.clone(), + ); + + let data = if let ty::Dynamic(ref data, ..) = normalized_ty.kind() { + data + } else { + return None; + }; + + let def_id = data.principal_def_id()?; + + return Some((normalized_ty, def_id)); + } + /// Searches for unsizing that might apply to `obligation`. fn assemble_candidates_for_unsizing( &mut self, @@ -729,6 +786,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let principal_a = data_a.principal().unwrap(); let target_trait_did = principal_def_id_b.unwrap(); let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); + if let Some((deref_output_ty, deref_output_trait_did)) = self + .need_migrate_deref_output_trait_object( + source, + &obligation.cause, + obligation.param_env, + ) + { + if deref_output_trait_did == target_trait_did { + self.tcx().struct_span_lint_hir( + DEREF_INTO_DYN_SUPERTRAIT, + obligation.cause.body_id, + obligation.cause.span, + |lint| { + lint.build(&format!( + "`{}` implements `Deref` with supertrait `{}` as output", + source, + deref_output_ty + )).emit(); + }, + ); + return; + } + } + for (idx, upcast_trait_ref) in util::supertraits(self.tcx(), source_trait_ref).enumerate() { diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3b6555de912e9..a36cb1358b64c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -92,7 +92,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(ImplSource::Generator(vtable_generator)) } - FnPointerCandidate => { + FnPointerCandidate { .. } => { let data = self.confirm_fn_pointer_candidate(obligation)?; Ok(ImplSource::FnPointer(data)) } @@ -141,6 +141,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let placeholder_trait_predicate = self.infcx().replace_bound_vars_with_placeholders(trait_predicate); let placeholder_self_ty = placeholder_trait_predicate.self_ty(); + let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); let (def_id, substs) = match *placeholder_self_ty.kind() { ty::Projection(proj) => (proj.item_def_id, proj.substs), ty::Opaque(def_id, substs) => (def_id, substs), @@ -164,7 +165,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.extend(self.infcx.commit_if_ok(|_| { self.infcx .at(&obligation.cause, obligation.param_env) - .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate.value) + .sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value) .map(|InferOk { obligations, .. }| obligations) .map_err(|_| Unimplemented) })?); @@ -600,12 +601,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(ImplSourceGeneratorData { generator_def_id, substs, nested: obligations }) } + #[instrument(skip(self), level = "debug")] fn confirm_closure_candidate( &mut self, obligation: &TraitObligation<'tcx>, ) -> Result>, SelectionError<'tcx>> { - debug!(?obligation, "confirm_closure_candidate"); - let kind = self .tcx() .fn_trait_kind_from_lang_item(obligation.predicate.def_id()) @@ -646,7 +646,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.push(Obligation::new( obligation.cause.clone(), obligation.param_env, - ty::PredicateKind::ClosureKind(closure_def_id, substs, kind) + ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)) .to_predicate(self.tcx()), )); } @@ -679,6 +679,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// because these output type parameters should not affect the /// selection of the impl. Therefore, if there is a mismatch, we /// report an error to the user. + #[instrument(skip(self), level = "trace")] fn confirm_poly_trait_refs( &mut self, obligation_cause: ObligationCause<'tcx>, @@ -898,10 +899,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); // We can only make objects from sized types. - let tr = ty::TraitRef::new( + let tr = ty::Binder::dummy(ty::TraitRef::new( tcx.require_lang_item(LangItem::Sized, None), tcx.mk_substs_trait(source, &[]), - ); + )); nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx))); // If the type is `Foo + 'a`, ensure that the type diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 50d6f82ae18fa..e191654210a43 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -451,6 +451,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Evaluates the predicates in `predicates` recursively. Note that /// this applies projections in the predicates, and therefore /// is run within an inference probe. + #[instrument(skip(self, stack), level = "debug")] fn evaluate_predicates_recursively<'o, I>( &mut self, stack: TraitObligationStackList<'o, 'tcx>, @@ -460,7 +461,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { I: IntoIterator> + std::fmt::Debug, { let mut result = EvaluatedToOk; - debug!(?predicates, "evaluate_predicates_recursively"); for obligation in predicates { let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; if let EvaluatedToErr = eval { @@ -683,13 +683,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { result } + #[instrument(skip(self, previous_stack), level = "debug")] fn evaluate_trait_predicate_recursively<'o>( &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>, ) -> Result { - debug!(?obligation, "evaluate_trait_predicate_recursively"); - if !self.intercrate && obligation.is_global(self.tcx()) && obligation @@ -701,7 +700,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If a param env has no global bounds, global obligations do not // depend on its particular value in order to work, so we can clear // out the param env and get better caching. - debug!("evaluate_trait_predicate_recursively - in global"); + debug!("in global"); obligation.param_env = obligation.param_env.without_caller_bounds(); } @@ -753,7 +752,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else { debug!(?result, "PROVISIONAL"); debug!( - "evaluate_trait_predicate_recursively: caching provisionally because {:?} \ + "caching provisionally because {:?} \ is a cycle participant (at depth {}, reached depth {})", fresh_trait_ref, stack.depth, reached_depth, ); @@ -1113,6 +1112,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // generator, this will raise error in other places // or ignore error with const_async_blocks feature GeneratorCandidate => {} + // FnDef where the function is const + FnPointerCandidate { is_const: true } => {} ConstDropCandidate => {} _ => { // reject all other types of candidates @@ -1540,6 +1541,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + // Drop otherwise equivalent non-const fn pointer candidates + (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true, + // Global bounds from the where clause should be ignored // here (see issue #50825). Otherwise, we have a where // clause so don't go around looking for impls. @@ -1550,7 +1554,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(..) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1568,7 +1572,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(_) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1598,7 +1602,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(..) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1610,7 +1614,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(..) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1691,7 +1695,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(_) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -1700,7 +1704,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(_) | ClosureCandidate | GeneratorCandidate - | FnPointerCandidate + | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) @@ -2124,13 +2128,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Returns `Ok` if `poly_trait_ref` being true implies that the /// obligation is satisfied. + #[instrument(skip(self), level = "debug")] fn match_poly_trait_ref( &mut self, obligation: &TraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result>, ()> { - debug!(?obligation, ?poly_trait_ref, "match_poly_trait_ref"); - self.infcx .at(&obligation.cause, obligation.param_env) .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) @@ -2174,12 +2177,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn closure_trait_ref_unnormalized( &mut self, obligation: &TraitObligation<'tcx>, substs: SubstsRef<'tcx>, ) -> ty::PolyTraitRef<'tcx> { - debug!(?obligation, ?substs, "closure_trait_ref_unnormalized"); let closure_sig = substs.as_closure().sig(); debug!(?closure_sig); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 2ecc169e1cf1d..ec7dcd4a419be 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -50,7 +50,7 @@ impl ChildrenExt for Children { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); - self.nonblanket_impls.entry(st).or_default().push(impl_def_id) + self.non_blanket_impls.entry(st).or_default().push(impl_def_id) } else { debug!("insert_blindly: impl_def_id={:?} st=None", impl_def_id); self.blanket_impls.push(impl_def_id) @@ -65,7 +65,7 @@ impl ChildrenExt for Children { let vec: &mut Vec; if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); - vec = self.nonblanket_impls.get_mut(&st).unwrap(); + vec = self.non_blanket_impls.get_mut(&st).unwrap(); } else { debug!("remove_existing: impl_def_id={:?} st=None", impl_def_id); vec = &mut self.blanket_impls; @@ -218,7 +218,7 @@ impl ChildrenExt for Children { } fn iter_children(children: &mut Children) -> impl Iterator + '_ { - let nonblanket = children.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter()); + let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter()); children.blanket_impls.iter().chain(nonblanket).cloned() } @@ -226,7 +226,7 @@ fn filtered_children( children: &mut Children, st: SimplifiedType, ) -> impl Iterator + '_ { - let nonblanket = children.nonblanket_impls.entry(st).or_default().iter(); + let nonblanket = children.non_blanket_impls.entry(st).or_default().iter(); children.blanket_impls.iter().chain(nonblanket).cloned() } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index b108d85bb20c9..ed49abbbedc92 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -248,7 +248,7 @@ pub fn predicate_for_trait_ref<'tcx>( cause, param_env, recursion_depth, - predicate: trait_ref.without_const().to_predicate(tcx), + predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 611ff26d65227..cb47ba9c360da 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -349,7 +349,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { new_cause, depth, param_env, - ty::PredicateKind::WellFormed(arg).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx), ) }), ); @@ -399,7 +399,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause.clone(), depth, param_env, - ty::PredicateKind::WellFormed(arg).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx), ) }), ); @@ -416,7 +416,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, self.param_env, - trait_ref.without_const().to_predicate(self.infcx.tcx), + ty::Binder::dummy(trait_ref).without_const().to_predicate(self.infcx.tcx), )); } } @@ -443,9 +443,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(uv.def.did, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable( + let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable( ty::Unevaluated::new(uv.def, substs), - ) + )) .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::with_depth( @@ -469,8 +469,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, self.param_env, - ty::PredicateKind::WellFormed(resolved_constant.into()) - .to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed( + resolved_constant.into(), + )) + .to_predicate(self.tcx()), )); } } @@ -556,8 +558,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, depth, param_env, - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(rty, r)) - .to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(rty, r), + )) + .to_predicate(self.tcx()), )); } } @@ -646,7 +650,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause.clone(), depth, param_env, - ty::PredicateKind::ObjectSafe(did).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did)) + .to_predicate(tcx), ) })); } @@ -673,7 +678,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { cause, self.recursion_depth, param_env, - ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())) + .to_predicate(self.tcx()), )); } else { // Yes, resolved, proceed with the result. diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 48c46c3069328..8612499623be6 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -19,7 +19,7 @@ mod normalize_erasing_regions; mod normalize_projection_ty; mod type_op; -pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span}; +pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; use rustc_middle::ty::query::Providers; diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index a76fb84261615..cc0b7d5817b43 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -156,7 +156,8 @@ impl AscribeUserTypeCx<'me, 'tcx> { self.relate(self_ty, Variance::Invariant, impl_self_ty)?; self.prove_predicate( - ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into())) + .to_predicate(self.tcx()), span, ); } @@ -173,7 +174,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... self.prove_predicate( - ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()), + ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()), span, ); Ok(()) @@ -256,7 +257,7 @@ fn type_op_prove_predicate<'tcx>( canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { - type_op_prove_predicate_with_span(infcx, fulfill_cx, key, None); + type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy()); Ok(()) }) } @@ -264,17 +265,12 @@ fn type_op_prove_predicate<'tcx>( /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors, /// this query can be re-run to better track the span of the obligation cause, and improve the error /// message. Do not call directly unless you're in that very specific context. -pub fn type_op_prove_predicate_with_span<'a, 'tcx: 'a>( +pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>( infcx: &'a InferCtxt<'a, 'tcx>, fulfill_cx: &'a mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>, - span: Option, + cause: ObligationCause<'tcx>, ) { - let cause = if let Some(span) = span { - ObligationCause::dummy_with_span(span) - } else { - ObligationCause::dummy() - }; let (param_env, ProvePredicate { predicate }) = key.into_parts(); fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate)); } diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 313571274c3de..60f8e196bcba1 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,8 +6,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(control_flow_enum)] -#![feature(half_open_range_patterns)] -#![feature(exclusive_range_pattern)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 32d271d94c8ea..98415a84c569b 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::Limit; @@ -12,7 +13,7 @@ type NeedsDropResult = Result; fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { let adt_components = - move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); + move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter()); // If we don't know a type doesn't need drop, for example if it's a type // parameter without a `Copy` bound, then we conservatively return that it @@ -28,8 +29,9 @@ fn has_significant_drop_raw<'tcx>( tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> bool { - let significant_drop_fields = - move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter()); + let significant_drop_fields = move |adt_def: &ty::AdtDef, _| { + tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter()) + }; let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields) .next() .is_some(); @@ -74,7 +76,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> { impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F> where - F: Fn(&ty::AdtDef) -> NeedsDropResult, + F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult, I: Iterator>, { type Item = NeedsDropResult>; @@ -138,7 +140,7 @@ where // `ManuallyDrop`. If it's a struct or enum without a `Drop` // impl then check whether the field types need `Drop`. ty::Adt(adt_def, substs) => { - let tys = match (self.adt_components)(adt_def) { + let tys = match (self.adt_components)(adt_def, substs) { Err(e) => return Some(Err(e)), Ok(tys) => tys, }; @@ -171,22 +173,44 @@ where } } +enum DtorType { + /// Type has a `Drop` but it is considered insignificant. + /// Check the query `adt_significant_drop_tys` for understanding + /// "significant" / "insignificant". + Insignificant, + + /// Type has a `Drop` implentation. + Significant, +} + // This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`. // Depending on the implentation of `adt_has_dtor`, it is used to check if the // ADT has a destructor or if the ADT only has a significant destructor. For // understanding significant destructor look at `adt_significant_drop_tys`. -fn adt_drop_tys_helper( - tcx: TyCtxt<'_>, +fn adt_drop_tys_helper<'tcx>( + tcx: TyCtxt<'tcx>, def_id: DefId, - adt_has_dtor: impl Fn(&ty::AdtDef) -> bool, -) -> Result<&ty::List>, AlwaysRequiresDrop> { - let adt_components = move |adt_def: &ty::AdtDef| { + adt_has_dtor: impl Fn(&ty::AdtDef) -> Option, +) -> Result<&ty::List>, AlwaysRequiresDrop> { + let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| { if adt_def.is_manually_drop() { debug!("adt_drop_tys: `{:?}` is manually drop", adt_def); return Ok(Vec::new().into_iter()); - } else if adt_has_dtor(adt_def) { - debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); - return Err(AlwaysRequiresDrop); + } else if let Some(dtor_info) = adt_has_dtor(adt_def) { + match dtor_info { + DtorType::Significant => { + debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def); + return Err(AlwaysRequiresDrop); + } + DtorType::Insignificant => { + debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def); + + // Since the destructor is insignificant, we just want to make sure all of + // the passed in type parameters are also insignificant. + // Eg: Vec dtor is insignificant when T=i32 but significant when T=Mutex. + return Ok(substs.types().collect::>>().into_iter()); + } + } } else if adt_def.is_union() { debug!("adt_drop_tys: `{:?}` is a union", adt_def); return Ok(Vec::new().into_iter()); @@ -204,7 +228,10 @@ fn adt_drop_tys_helper( } fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List>, AlwaysRequiresDrop> { - let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).is_some(); + // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are + // significant. + let adt_has_dtor = + |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant); adt_drop_tys_helper(tcx, def_id, adt_has_dtor) } @@ -213,10 +240,22 @@ fn adt_significant_drop_tys( def_id: DefId, ) -> Result<&ty::List>, AlwaysRequiresDrop> { let adt_has_dtor = |adt_def: &ty::AdtDef| { - adt_def - .destructor(tcx) - .map(|dtor| !tcx.has_attr(dtor.did, sym::rustc_insignificant_dtor)) - .unwrap_or(false) + let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor); + if is_marked_insig { + // In some cases like `std::collections::HashMap` where the struct is a wrapper around + // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies + // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with + // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl. + Some(DtorType::Insignificant) + } else if adt_def.destructor(tcx).is_some() { + // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be + // significant. + Some(DtorType::Significant) + } else { + // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we + // treat this as the simple case of Drop impl for type. + None + } }; adt_drop_tys_helper(tcx, def_id, adt_has_dtor) } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index d9ce169efc15c..91dbbec782f89 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -437,6 +437,7 @@ impl EqUnifyValue for IntVarValue {} impl UnifyKey for IntVid { type Value = Option; + #[inline] // make this function eligible for inlining - it is quite hot. fn index(&self) -> u32 { self.index } diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index 695132281c6ba..ec75e4a55d4e5 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -199,7 +199,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// When there are any missing associated types, emit an E0191 error and attempt to supply a /// reasonable suggestion on how to write it. For the case of multiple associated types in the - /// same trait bound have the same name (as they come from different super-traits), we instead + /// same trait bound have the same name (as they come from different supertraits), we instead /// emit a generic note suggesting using a `where` clause to constraint instead. pub(crate) fn complain_about_missing_associated_types( &self, @@ -340,7 +340,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { using the fully-qualified path to the associated types"; if !where_constraints.is_empty() && suggestions.is_empty() { // If there are duplicates associated type names and a single trait bound do not - // use structured suggestion, it means that there are multiple super-traits with + // use structured suggestion, it means that there are multiple supertraits with // the same associated type name. err.help(where_msg); } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index fd0544a47bb7c..5befe44802f54 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -132,7 +132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } let kind_ord = param.kind.to_ord(tcx); - let arg_ord = arg.to_ord(&tcx.features()); + let arg_ord = arg.to_ord(tcx.features()); // This note is only true when generic parameters are strictly ordered by their kind. if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal { @@ -423,7 +423,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { is_method_call: IsMethodCall, ) -> GenericArgCountResult { let empty_args = hir::GenericArgs::none(); - let suppress_mismatch = Self::check_impl_trait(tcx, seg, &generics); + let suppress_mismatch = Self::check_impl_trait(tcx, seg, generics); let gen_args = seg.args.unwrap_or(&empty_args); let gen_pos = if is_method_call == IsMethodCall::Yes { @@ -441,6 +441,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Checks that the correct number of generic arguments have been provided. /// This is used both for datatypes and function calls. + #[instrument(skip(tcx, gen_pos), level = "debug")] pub(crate) fn check_generic_arg_count( tcx: TyCtxt<'_>, span: Span, @@ -452,11 +453,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { has_self: bool, infer_args: bool, ) -> GenericArgCountResult { - debug!( - "check_generic_arg_count(span: {:?}, def_id: {:?}, seg: {:?}, gen_params: {:?}, gen_args: {:?})", - span, def_id, seg, gen_params, gen_args - ); - let default_counts = gen_params.own_defaults(); let param_counts = gen_params.own_counts(); @@ -556,9 +552,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut check_types_and_consts = |expected_min, expected_max, provided, params_offset, args_offset| { debug!( - "check_types_and_consts(expected_min: {:?}, expected_max: {:?}, \ - provided: {:?}, params_offset: {:?}, args_offset: {:?}", - expected_min, expected_max, provided, params_offset, args_offset + ?expected_min, + ?expected_max, + ?provided, + ?params_offset, + ?args_offset, + "check_types_and_consts" ); if (expected_min..=expected_max).contains(&provided) { return true; @@ -589,7 +588,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } }; - debug!("gen_args_info: {:?}", gen_args_info); + debug!(?gen_args_info); WrongNumberOfGenericArgs::new( tcx, @@ -601,7 +600,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id, ) .diagnostic() - .emit(); + .emit_unless(gen_args.has_err()); false }; @@ -614,8 +613,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - default_counts.types - default_counts.consts }; - debug!("expected_min: {:?}", expected_min); - debug!("arg_counts.lifetimes: {:?}", gen_args.num_lifetime_params()); + debug!(?expected_min); + debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params()); check_types_and_consts( expected_min, diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 33df541eb2ba8..889b68773c27b 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -352,8 +352,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, def_id, seg, - &generics, - &generic_args, + generics, + generic_args, GenericArgPosition::Type, self_ty.is_some(), infer_args, @@ -363,7 +363,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Traits always have `Self` as a generic parameter, which means they will not return early // here and so associated type bindings will be handled regardless of whether there are any // non-`Self` generic parameters. - if generics.params.len() == 0 { + if generics.params.is_empty() { return (tcx.intern_substs(&[]), arg_count); } @@ -417,7 +417,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let tcx = self.astconv.tcx(); match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.astconv.ast_region_to_region(<, Some(param)).into() + self.astconv.ast_region_to_region(lt, Some(param)).into() } (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { if has_default { @@ -441,7 +441,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.inferred_params.push(ty.span); tcx.ty_error().into() } else { - self.astconv.ast_ty_to_ty(&ty).into() + self.astconv.ast_ty_to_ty(ty).into() } } (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => { @@ -622,10 +622,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .iter() .map(|binding| { let kind = match binding.kind { - hir::TypeBindingKind::Equality { ref ty } => { + hir::TypeBindingKind::Equality { ty } => { ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty)) } - hir::TypeBindingKind::Constraint { ref bounds } => { + hir::TypeBindingKind::Constraint { bounds } => { ConvertedBindingKind::Constraint(bounds) } }; @@ -908,18 +908,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some((self_ty, where_clause)) = self_ty_where_predicates { let self_ty_def_id = tcx.hir().local_def_id(self_ty).to_def_id(); for clause in where_clause { - match clause { - hir::WherePredicate::BoundPredicate(pred) => { - match pred.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(_, path)) => match path.res { - Res::Def(DefKind::TyParam, def_id) if def_id == self_ty_def_id => {} - _ => continue, - }, + if let hir::WherePredicate::BoundPredicate(pred) = clause { + match pred.bounded_ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => match path.res { + Res::Def(DefKind::TyParam, def_id) if def_id == self_ty_def_id => {} _ => continue, - } - search_bounds(pred.bounds); + }, + _ => continue, } - _ => {} + search_bounds(pred.bounds); } } } @@ -1030,7 +1027,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { param_ty: Ty<'tcx>, ast_bounds: &[hir::GenericBound<'_>], ) -> Bounds<'tcx> { - self.compute_bounds_inner(param_ty, &ast_bounds) + self.compute_bounds_inner(param_ty, ast_bounds) } /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type @@ -1231,7 +1228,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } match binding.kind { - ConvertedBindingKind::Equality(ref ty) => { + ConvertedBindingKind::Equality(ty) => { // "Desugar" a constraint like `T: Iterator` this to // the "projection predicate" for: // @@ -1322,7 +1319,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); err.help(&format!( - "consider creating a new trait with all of these as super-traits and using that \ + "consider creating a new trait with all of these as supertraits and using that \ trait here instead: `trait NewTrait: {} {{}}`", regular_traits .iter() @@ -2207,7 +2204,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert_eq!(opt_self_ty, None); let path_segs = - self.def_ids_for_value_path_segments(&path.segments, None, kind, def_id); + self.def_ids_for_value_path_segments(path.segments, None, kind, def_id); let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); self.prohibit_generics(path.segments.iter().enumerate().filter_map( @@ -2304,34 +2301,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let tcx = self.tcx(); let result_ty = match ast_ty.kind { - hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(&ty)), + hir::TyKind::Slice(ref ty) => tcx.mk_slice(self.ast_ty_to_ty(ty)), hir::TyKind::Ptr(ref mt) => { - tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(&mt.ty), mutbl: mt.mutbl }) + tcx.mk_ptr(ty::TypeAndMut { ty: self.ast_ty_to_ty(mt.ty), mutbl: mt.mutbl }) } hir::TyKind::Rptr(ref region, ref mt) => { let r = self.ast_region_to_region(region, None); debug!(?r); - let t = self.ast_ty_to_ty_inner(&mt.ty, true); + let t = self.ast_ty_to_ty_inner(mt.ty, true); tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl }) } hir::TyKind::Never => tcx.types.never, - hir::TyKind::Tup(ref fields) => { - tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t))) - } - hir::TyKind::BareFn(ref bf) => { - require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); + hir::TyKind::Tup(fields) => tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(t))), + hir::TyKind::BareFn(bf) => { + require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span); tcx.mk_fn_ptr(self.ty_of_fn( ast_ty.hir_id, bf.unsafety, bf.abi, - &bf.decl, + bf.decl, &hir::Generics::empty(), None, Some(ast_ty), )) } - hir::TyKind::TraitObject(ref bounds, ref lifetime, _) => { + hir::TyKind::TraitObject(bounds, ref lifetime, _) => { self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed) } hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { @@ -2339,7 +2334,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself)); self.res_to_ty(opt_self_ty, path, false) } - hir::TyKind::OpaqueDef(item_id, ref lifetimes) => { + hir::TyKind::OpaqueDef(item_id, lifetimes) => { let opaque_ty = tcx.hir().item(item_id); let def_id = item_id.def_id.to_def_id(); @@ -2354,7 +2349,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!(?qself, ?segment); let ty = self.ast_ty_to_ty(qself); - let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind { + let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind { path.res } else { Res::Err @@ -2379,7 +2374,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::TyKind::Array(ref ty, ref length) => { let length_def_id = tcx.hir().local_def_id(length.hir_id); let length = ty::Const::from_anon_const(tcx, length_def_id); - let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); + let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length)); self.normalize_ty(ast_ty.span, array_ty) } hir::TyKind::Typeof(ref e) => { @@ -2485,7 +2480,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let input_tys = decl.inputs.iter().map(|a| self.ty_of_arg(a, None)); let output_ty = match decl.output { - hir::FnRetTy::Return(ref output) => { + hir::FnRetTy::Return(output) => { visitor.visit_ty(output); self.ast_ty_to_ty(output) } diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 01227cad334fc..6a231e719e664 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -524,13 +524,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for o in obligations { match o.predicate.kind().skip_binder() { ty::PredicateKind::Trait(t) => { - let pred = ty::PredicateKind::Trait(ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: t.def_id(), - substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]), - }, - constness: t.constness, - }); + let pred = + ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: t.def_id(), + substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]), + }, + constness: t.constness, + })); let obl = Obligation::new( o.cause.clone(), self.param_env, diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 1cc06b8c2e544..4ffb061f7b48e 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -246,12 +246,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if borrow { // Check for &self vs &mut self in the method signature. Since this is either // the Fn or FnMut trait, it should be one of those. - let (region, mutbl) = - if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind() { - (r, mutbl) - } else { - span_bug!(call_expr.span, "input to call/call_mut is not a ref?"); - }; + let (region, mutbl) = if let ty::Ref(r, _, mutbl) = + method.sig.inputs()[0].kind() + { + (r, mutbl) + } else { + // The `fn`/`fn_mut` lang item is ill-formed, which should have + // caused an error elsewhere. + self.tcx + .sess + .delay_span_bug(call_expr.span, "input to call/call_mut is not a ref?"); + return None; + }; let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, @@ -350,6 +356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + let callee_ty = self.resolve_vars_if_possible(callee_ty); let mut err = type_error_struct!( self.tcx.sess, callee_expr.span, diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 4ea7a8694c075..51c766fe57c10 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -351,7 +351,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ); let mut sugg = None; let mut sugg_mutref = false; - if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() { + if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() { if fcx .try_coerce( @@ -366,7 +366,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) .is_ok() { - sugg = Some(format!("&{}*", mutbl.prefix_str())); + sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty)); } } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() { if expr_mutbl == Mutability::Not @@ -400,7 +400,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) .is_ok() { - sugg = Some(format!("&{}", mutbl.prefix_str())); + sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() { if fcx @@ -416,19 +416,47 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) .is_ok() { - sugg = Some(format!("&{}", mutbl.prefix_str())); + sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } if sugg_mutref { err.span_label(self.span, "invalid cast"); err.span_note(self.expr.span, "this reference is immutable"); err.span_note(self.cast_span, "trying to cast to a mutable reference type"); - } else if let Some(sugg) = sugg { + } else if let Some((sugg, remove_cast)) = sugg { err.span_label(self.span, "invalid cast"); - err.span_suggestion_verbose( - self.expr.span.shrink_to_lo(), + + let has_parens = fcx + .tcx + .sess + .source_map() + .span_to_snippet(self.expr.span) + .map_or(false, |snip| snip.starts_with("(")); + + // Very crude check to see whether the expression must be wrapped + // in parentheses for the suggestion to work (issue #89497). + // Can/should be extended in the future. + let needs_parens = !has_parens + && match self.expr.kind { + hir::ExprKind::Cast(..) => true, + _ => false, + }; + + let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)]; + if needs_parens { + suggestion[0].1 += "("; + suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string())); + } + if remove_cast { + suggestion.push(( + self.expr.span.shrink_to_hi().to(self.cast_span), + String::new(), + )); + } + + err.multipart_suggestion_verbose( "consider borrowing the value", - sugg, + suggestion, Applicability::MachineApplicable, ); } else if !matches!( @@ -438,7 +466,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let mut label = true; // Check `impl From for self.cast_ty {}` for accurate suggestion: if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { - if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::from_trait) { + if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) { let ty = fcx.resolve_vars_if_possible(self.cast_ty); // Erase regions to avoid panic in `prove_value` when calling // `type_implements_trait`. diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index d6c59312c0bc8..db50c5d891e13 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -31,7 +31,7 @@ use std::ops::ControlFlow; pub fn check_wf_new(tcx: TyCtxt<'_>) { let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().krate().par_visit_all_item_likes(&visit); + tcx.hir().par_visit_all_item_likes(&visit); } pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { @@ -58,7 +58,7 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab tcx.sess, span, E0781, - "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers." + "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers" ) .emit() } @@ -70,6 +70,7 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab /// /// * ... /// * inherited: other fields inherited from the enclosing fn (if any) +#[instrument(skip(inherited, body), level = "debug")] pub(super) fn check_fn<'a, 'tcx>( inherited: &'a Inherited<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -82,8 +83,6 @@ pub(super) fn check_fn<'a, 'tcx>( ) -> (FnCtxt<'a, 'tcx>, Option>) { let mut fn_sig = fn_sig; - debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); - // Create the function context. This is either derived from scratch or, // in the case of closures, based on the outer context. let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id); @@ -241,32 +240,16 @@ pub(super) fn check_fn<'a, 'tcx>( // we saw and assigning it to the expected return type. This isn't // really expected to fail, since the coercions would have failed // earlier when trying to find a LUB. - // - // However, the behavior around `!` is sort of complex. In the - // event that the `actual_return_ty` comes back as `!`, that - // indicates that the fn either does not return or "returns" only - // values of type `!`. In this case, if there is an expected - // return type that is *not* `!`, that should be ok. But if the - // return type is being inferred, we want to "fallback" to `!`: - // - // let x = move || panic!(); - // - // To allow for that, I am creating a type variable with diverging - // fallback. This was deemed ever so slightly better than unifying - // the return value with `!` because it allows for the caller to - // make more assumptions about the return type (e.g., they could do - // - // let y: Option = Some(x()); - // - // which would then cause this return type to become `u32`, not - // `!`). let coercion = fcx.ret_coercion.take().unwrap().into_inner(); let mut actual_return_ty = coercion.complete(&fcx); - if actual_return_ty.is_never() { - actual_return_ty = fcx.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::DivergingFn, - span, - }); + debug!("actual_return_ty = {:?}", actual_return_ty); + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // We have special-cased the case where the function is declared + // `-> dyn Foo` and we don't actually relate it to the + // `fcx.ret_coercion`, so just substitute a type variable. + actual_return_ty = + fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); + debug!("actual_return_ty replaced with {:?}", actual_return_ty); } fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 65ba1c08b6243..410ac24b1f19c 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -33,6 +33,7 @@ struct ClosureSignatures<'tcx> { } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + #[instrument(skip(self, expr, _capture, decl, body_id), level = "debug")] pub fn check_expr_closure( &self, expr: &hir::Expr<'_>, @@ -42,7 +43,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { gen: Option, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected); + trace!("decl = {:#?}", decl); + trace!("expr = {:#?}", expr); // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected @@ -55,6 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_closure(expr, expected_kind, decl, body, gen, expected_sig) } + #[instrument(skip(self, expr, body, decl), level = "debug")] fn check_closure( &self, expr: &hir::Expr<'_>, @@ -64,14 +67,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { gen: Option, expected_sig: Option>, ) -> Ty<'tcx> { - debug!("check_closure(opt_kind={:?}, expected_sig={:?})", opt_kind, expected_sig); - + trace!("decl = {:#?}", decl); let expr_def_id = self.tcx.hir().local_def_id(expr.hir_id); + debug!(?expr_def_id); let ClosureSignatures { bound_sig, liberated_sig } = self.sig_of_closure(expr.hir_id, expr_def_id.to_def_id(), decl, body, expected_sig); - debug!("check_closure: ty_of_closure returns {:?}", liberated_sig); + debug!(?bound_sig, ?liberated_sig); let return_type_pre_known = !liberated_sig.output().is_ty_infer(); @@ -130,10 +133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }); - debug!( - "check_closure: expr_def_id={:?}, sig={:?}, opt_kind={:?}", - expr_def_id, sig, opt_kind - ); + debug!(?sig, ?opt_kind); let closure_kind_ty = match opt_kind { Some(kind) => kind.to_ty(self.tcx), @@ -159,19 +159,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs); - debug!("check_closure: expr.hir_id={:?} closure_type={:?}", expr.hir_id, closure_type); + debug!(?expr.hir_id, ?closure_type); closure_type } /// Given the expected type, figures out what it can about this closure we /// are about to type check: + #[instrument(skip(self), level = "debug")] fn deduce_expectations_from_expected_type( &self, expected_ty: Ty<'tcx>, ) -> (Option>, Option) { - debug!("deduce_expectations_from_expected_type(expected_ty={:?})", expected_ty); - match *expected_ty.kind() { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { @@ -314,6 +313,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// If there is no expected signature, then we will convert the /// types that the user gave into a signature. + #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")] fn sig_of_closure_no_expectation( &self, hir_id: hir::HirId, @@ -321,8 +321,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, ) -> ClosureSignatures<'tcx> { - debug!("sig_of_closure_no_expectation()"); - let bound_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body); self.closure_sigs(expr_def_id, body, bound_sig) @@ -375,6 +373,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - `expected_sig`: the expected signature (if any). Note that /// this is missing a binder: that is, there may be late-bound /// regions with depth 1, which are bound then by the closure. + #[instrument(skip(self, hir_id, expr_def_id, decl, body), level = "debug")] fn sig_of_closure_with_expectation( &self, hir_id: hir::HirId, @@ -383,8 +382,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { body: &hir::Body<'_>, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { - debug!("sig_of_closure_with_expectation(expected_sig={:?})", expected_sig); - // Watch out for some surprises and just ignore the // expectation if things don't see to match up with what we // expect. @@ -553,6 +550,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// types that the user gave into a signature. /// /// Also, record this closure signature for later. + #[instrument(skip(self, decl, body), level = "debug")] fn supplied_sig_of_closure( &self, hir_id: hir::HirId, @@ -562,10 +560,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> ty::PolyFnSig<'tcx> { let astconv: &dyn AstConv<'_> = self; - debug!( - "supplied_sig_of_closure(decl={:?}, body.generator_kind={:?})", - decl, body.generator_kind, - ); + trace!("decl = {:#?}", decl); + debug!(?body.generator_kind); let bound_vars = self.tcx.late_bound_vars(hir_id); @@ -578,7 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we expect the return type of the block to match that of the enclosing // function. Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => { - debug!("supplied_sig_of_closure: closure is async fn body"); + debug!("closure is async fn body"); self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| { // AFAIK, deducing the future output // always succeeds *except* in error cases @@ -606,7 +602,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_vars, ); - debug!("supplied_sig_of_closure: result={:?}", result); + debug!(?result); let c_result = self.inh.infcx.canonicalize_response(result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 92d0470bc2f58..07e542b70b90c 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -54,7 +54,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{self, BytePos, Span}; +use rustc_span::{self, BytePos, DesugaringKind, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; @@ -159,24 +159,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Coercing from `!` to any type is allowed: if a.is_never() { - // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound - // type variable, we want `?T` to fallback to `!` if not - // otherwise constrained. An example where this arises: - // - // let _: Option = Some({ return; }); - // - // here, we would coerce from `!` to `?T`. - return if b.is_ty_var() { - // Micro-optimization: no need for this if `b` is - // already resolved in some way. - let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::AdjustmentType, - span: self.cause.span, - }); - self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny)) - } else { - success(simple(Adjust::NeverToAny)(b), b, vec![]) - }; + return success(simple(Adjust::NeverToAny)(b), b, vec![]); } // Coercing *from* an unresolved inference variable means that @@ -273,10 +256,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { obligations.push(Obligation::new( self.cause.clone(), self.param_env, - ty::PredicateKind::Coerce(ty::CoercePredicate { + ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate { a: source_ty, b: target_ty, - }) + })) .to_predicate(self.tcx()), )); } @@ -499,12 +482,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // &[T; n] or &mut [T; n] -> &[T] // or &mut [T; n] -> &mut [T] // or &Concrete -> &Trait, etc. + #[instrument(skip(self), level = "debug")] fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> { - debug!("coerce_unsized(source={:?}, target={:?})", source, target); - source = self.shallow_resolve(source); target = self.shallow_resolve(target); - debug!("coerce_unsized: resolved source={:?} target={:?}", source, target); + debug!(?source, ?target); // These 'if' statements require some explanation. // The `CoerceUnsized` trait is special - it is only @@ -1502,21 +1484,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.emit_coerce_suggestions(&mut err, expr, found, expected, None); } - // Error possibly reported in `check_assign` so avoid emitting error again. - let assign_to_bool = expression - // #67273: Use initial expected type as opposed to `expected`. - // Otherwise we end up using prior coercions in e.g. a `match` expression: - // ``` - // match i { - // 0 => true, // Because of this... - // 1 => i = 1, // ...`expected == bool` now, but not when checking `i = 1`. - // _ => (), - // }; - // ``` - .filter(|e| fcx.is_assign_to_bool(e, self.expected_ty())) - .is_some(); - - err.emit_unless(assign_to_bool || unsized_return); + err.emit_unless(unsized_return); self.final_ty = Some(fcx.tcx.ty_error()); } @@ -1554,8 +1522,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // If the block is from an external macro or try (`?`) desugaring, then // do not suggest adding a semicolon, because there's nowhere to put it. // See issues #81943 and #87051. - if cond_expr.span.desugaring_kind().is_none() - && !in_external_macro(fcx.tcx.sess, cond_expr.span) + if matches!( + cond_expr.span.desugaring_kind(), + None | Some(DesugaringKind::WhileLoop) + ) && !in_external_macro(fcx.tcx.sess, cond_expr.span) && !matches!( cond_expr.kind, hir::ExprKind::Match(.., hir::MatchSource::TryDesugar) diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 722b110ed6108..1a2931b9377ce 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -59,6 +59,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_suptype_with_origin(&self.misc(sp), expected, actual) } + #[instrument(skip(self), level = "debug")] pub fn demand_suptype_with_origin( &self, cause: &ObligationCause<'tcx>, @@ -144,12 +145,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr_ty = self.resolve_vars_with_obligations(checked_ty); let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); - if self.is_assign_to_bool(expr, expected) { - // Error reported in `check_assign` so avoid emitting error again. - err.delay_as_bug(); - return (expected, None); - } - self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr); (expected, Some(err)) @@ -171,14 +166,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Returns whether the expected type is `bool` and the expression is `x = y`. - pub fn is_assign_to_bool(&self, expr: &hir::Expr<'_>, expected: Ty<'tcx>) -> bool { - if let hir::ExprKind::Assign(..) = expr.kind { - return expected == self.tcx.types.bool; - } - 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( diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 11b6c93a11528..676e751376a6c 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { !self.typeck_results.borrow().adjustments().contains_key(expr.hir_id), "expression with never type wound up being adjusted" ); - let adj_ty = self.next_diverging_ty_var(TypeVariableOrigin { + let adj_ty = self.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::AdjustmentType, span: expr.span, }); @@ -92,8 +92,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr = expr.peel_drop_temps(); self.suggest_deref_ref_or_into(&mut err, expr, expected_ty, ty, None); extend_err(&mut err); - // Error possibly reported in `check_assign` so avoid emitting error again. - err.emit_unless(self.is_assign_to_bool(expr, expected_ty)); + err.emit(); } ty } @@ -156,7 +155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Note that inspecting a type's structure *directly* may expose the fact /// that there are actually multiple representations for `Error`, so avoid /// that when err needs to be handled differently. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self, expr), level = "debug")] pub(super) fn check_expr_with_expectation( &self, expr: &'tcx hir::Expr<'tcx>, @@ -254,12 +253,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + #[instrument(skip(self, expr), level = "debug")] fn check_expr_kind( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - debug!("check_expr_kind(expected={:?}, expr={:?})", expected, expr); + trace!("expr={:#?}", expr); let tcx = self.tcx; match expr.kind { @@ -2136,7 +2136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { idx_t } else { let base_t = self.structurally_resolved_type(base.span, base_t); - match self.lookup_indexing(expr, base, base_t, idx_t) { + match self.lookup_indexing(expr, base, base_t, idx, idx_t) { Some((index_ty, element_ty)) => { // two-phase not needed because index_ty is never mutable self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index 8f6cdc7bb12a7..296e45337ed10 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -1,29 +1,52 @@ use crate::check::FnCtxt; -use rustc_infer::infer::type_variable::Diverging; +use rustc_data_structures::{ + fx::FxHashMap, + graph::WithSuccessors, + graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + stable_set::FxHashSet, +}; use rustc_middle::ty::{self, Ty}; impl<'tcx> FnCtxt<'_, 'tcx> { /// Performs type inference fallback, returning true if any fallback /// occurs. pub(super) fn type_inference_fallback(&self) -> bool { + debug!( + "type-inference-fallback start obligations: {:#?}", + self.fulfillment_cx.borrow_mut().pending_obligations() + ); + // All type checking constraints were added, try to fallback unsolved variables. self.select_obligations_where_possible(false, |_| {}); - let mut fallback_has_occurred = false; + debug!( + "type-inference-fallback post selection obligations: {:#?}", + self.fulfillment_cx.borrow_mut().pending_obligations() + ); + + // Check if we have any unsolved varibales. If not, no need for fallback. + let unsolved_variables = self.unsolved_variables(); + if unsolved_variables.is_empty() { + return false; + } + + let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables); + + let mut fallback_has_occurred = false; // We do fallback in two passes, to try to generate // better error messages. // The first time, we do *not* replace opaque types. - for ty in &self.unsolved_variables() { + for ty in unsolved_variables { debug!("unsolved_variable = {:?}", ty); - fallback_has_occurred |= self.fallback_if_possible(ty); + fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback); } - // We now see if we can make progress. This might - // cause us to unify inference variables for opaque types, - // since we may have unified some other type variables - // during the first phase of fallback. - // This means that we only replace inference variables with their underlying - // opaque types as a last resort. + // We now see if we can make progress. This might cause us to + // unify inference variables for opaque types, since we may + // have unified some other type variables during the first + // phase of fallback. This means that we only replace + // inference variables with their underlying opaque types as a + // last resort. // // In code like this: // @@ -62,36 +85,44 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // // - Unconstrained floats are replaced with with `f64`. // - // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` - // is enabled. Otherwise, they are replaced with `()`. + // - Non-numerics may get replaced with `()` or `!`, depending on + // how they were categorized by `calculate_diverging_fallback` + // (and the setting of `#![feature(never_type_fallback)]`). + // + // Fallback becomes very dubious if we have encountered + // type-checking errors. In that case, fallback to Error. // - // Fallback becomes very dubious if we have encountered type-checking errors. - // In that case, fallback to Error. // The return value indicates whether fallback has occurred. - fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool { + fn fallback_if_possible( + &self, + ty: Ty<'tcx>, + diverging_fallback: &FxHashMap, Ty<'tcx>>, + ) -> bool { // Careful: we do NOT shallow-resolve `ty`. We know that `ty` - // is an unsolved variable, and we determine its fallback based - // solely on how it was created, not what other type variables - // it may have been unified with since then. + // is an unsolved variable, and we determine its fallback + // based solely on how it was created, not what other type + // variables it may have been unified with since then. // - // The reason this matters is that other attempts at fallback may - // (in principle) conflict with this fallback, and we wish to generate - // a type error in that case. (However, this actually isn't true right now, - // because we're only using the builtin fallback rules. This would be - // true if we were using user-supplied fallbacks. But it's still useful - // to write the code to detect bugs.) + // The reason this matters is that other attempts at fallback + // may (in principle) conflict with this fallback, and we wish + // to generate a type error in that case. (However, this + // actually isn't true right now, because we're only using the + // builtin fallback rules. This would be true if we were using + // user-supplied fallbacks. But it's still useful to write the + // code to detect bugs.) // - // (Note though that if we have a general type variable `?T` that is then unified - // with an integer type variable `?I` that ultimately never gets - // resolved to a special integral type, `?T` is not considered unsolved, - // but `?I` is. The same is true for float variables.) + // (Note though that if we have a general type variable `?T` + // that is then unified with an integer type variable `?I` + // that ultimately never gets resolved to a special integral + // type, `?T` is not considered unsolved, but `?I` is. The + // same is true for float variables.) let fallback = match ty.kind() { _ if self.is_tainted_by_errors() => self.tcx.ty_error(), ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, - _ => match self.type_var_diverges(ty) { - Diverging::Diverges => self.tcx.mk_diverging_default(), - Diverging::NotDiverging => return false, + _ => match diverging_fallback.get(&ty) { + Some(&fallback_ty) => fallback_ty, + None => return false, }, }; debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback); @@ -105,11 +136,10 @@ impl<'tcx> FnCtxt<'_, 'tcx> { true } - /// Second round of fallback: Unconstrained type variables - /// created from the instantiation of an opaque - /// type fall back to the opaque type itself. This is a - /// somewhat incomplete attempt to manage "identity passthrough" - /// for `impl Trait` types. + /// Second round of fallback: Unconstrained type variables created + /// from the instantiation of an opaque type fall back to the + /// opaque type itself. This is a somewhat incomplete attempt to + /// manage "identity passthrough" for `impl Trait` types. /// /// For example, in this code: /// @@ -158,4 +188,274 @@ impl<'tcx> FnCtxt<'_, 'tcx> { return false; } } + + /// The "diverging fallback" system is rather complicated. This is + /// a result of our need to balance 'do the right thing' with + /// backwards compatibility. + /// + /// "Diverging" type variables are variables created when we + /// coerce a `!` type into an unbound type variable `?X`. If they + /// never wind up being constrained, the "right and natural" thing + /// is that `?X` should "fallback" to `!`. This means that e.g. an + /// expression like `Some(return)` will ultimately wind up with a + /// type like `Option` (presuming it is not assigned or + /// constrained to have some other type). + /// + /// However, the fallback used to be `()` (before the `!` type was + /// added). Moreover, there are cases where the `!` type 'leaks + /// out' from dead code into type variables that affect live + /// code. The most common case is something like this: + /// + /// ```rust + /// match foo() { + /// 22 => Default::default(), // call this type `?D` + /// _ => return, // return has type `!` + /// } // call the type of this match `?M` + /// ``` + /// + /// Here, coercing the type `!` into `?M` will create a diverging + /// type variable `?X` where `?X <: ?M`. We also have that `?D <: + /// ?M`. If `?M` winds up unconstrained, then `?X` will + /// fallback. If it falls back to `!`, then all the type variables + /// will wind up equal to `!` -- this includes the type `?D` + /// (since `!` doesn't implement `Default`, we wind up a "trait + /// not implemented" error in code like this). But since the + /// original fallback was `()`, this code used to compile with `?D + /// = ()`. This is somewhat surprising, since `Default::default()` + /// on its own would give an error because the types are + /// insufficiently constrained. + /// + /// Our solution to this dilemma is to modify diverging variables + /// so that they can *either* fallback to `!` (the default) or to + /// `()` (the backwards compatibility case). We decide which + /// fallback to use based on whether there is a coercion pattern + /// like this: + /// + /// ``` + /// ?Diverging -> ?V + /// ?NonDiverging -> ?V + /// ?V != ?NonDiverging + /// ``` + /// + /// Here `?Diverging` represents some diverging type variable and + /// `?NonDiverging` represents some non-diverging type + /// variable. `?V` can be any type variable (diverging or not), so + /// long as it is not equal to `?NonDiverging`. + /// + /// Intuitively, what we are looking for is a case where a + /// "non-diverging" type variable (like `?M` in our example above) + /// is coerced *into* some variable `?V` that would otherwise + /// fallback to `!`. In that case, we make `?V` fallback to `!`, + /// along with anything that would flow into `?V`. + /// + /// The algorithm we use: + /// * Identify all variables that are coerced *into* by a + /// diverging variable. Do this by iterating over each + /// diverging, unsolved variable and finding all variables + /// reachable from there. Call that set `D`. + /// * Walk over all unsolved, non-diverging variables, and find + /// any variable that has an edge into `D`. + fn calculate_diverging_fallback( + &self, + unsolved_variables: &[Ty<'tcx>], + ) -> FxHashMap, Ty<'tcx>> { + debug!("calculate_diverging_fallback({:?})", unsolved_variables); + + let relationships = self.fulfillment_cx.borrow_mut().relationships().clone(); + + // Construct a coercion graph where an edge `A -> B` indicates + // a type variable is that is coerced + let coercion_graph = self.create_coercion_graph(); + + // Extract the unsolved type inference variable vids; note that some + // unsolved variables are integer/float variables and are excluded. + let unsolved_vids = unsolved_variables.iter().filter_map(|ty| ty.ty_vid()); + + // Compute the diverging root vids D -- that is, the root vid of + // those type variables that (a) are the target of a coercion from + // a `!` type and (b) have not yet been solved. + // + // These variables are the ones that are targets for fallback to + // either `!` or `()`. + let diverging_roots: FxHashSet = self + .diverging_type_vars + .borrow() + .iter() + .map(|&ty| self.infcx.shallow_resolve(ty)) + .filter_map(|ty| ty.ty_vid()) + .map(|vid| self.infcx.root_var(vid)) + .collect(); + debug!( + "calculate_diverging_fallback: diverging_type_vars={:?}", + self.diverging_type_vars.borrow() + ); + debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots); + + // Find all type variables that are reachable from a diverging + // type variable. These will typically default to `!`, unless + // we find later that they are *also* reachable from some + // other type variable outside this set. + let mut roots_reachable_from_diverging = DepthFirstSearch::new(&coercion_graph); + let mut diverging_vids = vec![]; + let mut non_diverging_vids = vec![]; + for unsolved_vid in unsolved_vids { + let root_vid = self.infcx.root_var(unsolved_vid); + debug!( + "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}", + unsolved_vid, + root_vid, + diverging_roots.contains(&root_vid), + ); + if diverging_roots.contains(&root_vid) { + diverging_vids.push(unsolved_vid); + roots_reachable_from_diverging.push_start_node(root_vid); + + debug!( + "calculate_diverging_fallback: root_vid={:?} reaches {:?}", + root_vid, + coercion_graph.depth_first_search(root_vid).collect::>() + ); + + // drain the iterator to visit all nodes reachable from this node + roots_reachable_from_diverging.complete_search(); + } else { + non_diverging_vids.push(unsolved_vid); + } + } + + debug!( + "calculate_diverging_fallback: roots_reachable_from_diverging={:?}", + roots_reachable_from_diverging, + ); + + // Find all type variables N0 that are not reachable from a + // diverging variable, and then compute the set reachable from + // N0, which we call N. These are the *non-diverging* type + // variables. (Note that this set consists of "root variables".) + let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph); + for &non_diverging_vid in &non_diverging_vids { + let root_vid = self.infcx.root_var(non_diverging_vid); + if roots_reachable_from_diverging.visited(root_vid) { + continue; + } + roots_reachable_from_non_diverging.push_start_node(root_vid); + roots_reachable_from_non_diverging.complete_search(); + } + debug!( + "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}", + roots_reachable_from_non_diverging, + ); + + debug!("inherited: {:#?}", self.inh.fulfillment_cx.borrow_mut().pending_obligations()); + debug!("obligations: {:#?}", self.fulfillment_cx.borrow_mut().pending_obligations()); + debug!("relationships: {:#?}", relationships); + + // For each diverging variable, figure out whether it can + // reach a member of N. If so, it falls back to `()`. Else + // `!`. + let mut diverging_fallback = FxHashMap::default(); + diverging_fallback.reserve(diverging_vids.len()); + for &diverging_vid in &diverging_vids { + let diverging_ty = self.tcx.mk_ty_var(diverging_vid); + let root_vid = self.infcx.root_var(diverging_vid); + let can_reach_non_diverging = coercion_graph + .depth_first_search(root_vid) + .any(|n| roots_reachable_from_non_diverging.visited(n)); + + let mut relationship = ty::FoundRelationships { self_in_trait: false, output: false }; + + for (vid, rel) in relationships.iter() { + if self.infcx.root_var(*vid) == root_vid { + relationship.self_in_trait |= rel.self_in_trait; + relationship.output |= rel.output; + } + } + + if relationship.self_in_trait && relationship.output { + // This case falls back to () to ensure that the code pattern in + // src/test/ui/never_type/fallback-closure-ret.rs continues to + // compile when never_type_fallback is enabled. + // + // This rule is not readily explainable from first principles, + // but is rather intended as a patchwork fix to ensure code + // which compiles before the stabilization of never type + // fallback continues to work. + // + // Typically this pattern is encountered in a function taking a + // closure as a parameter, where the return type of that closure + // (checked by `relationship.output`) is expected to implement + // some trait (checked by `relationship.self_in_trait`). This + // can come up in non-closure cases too, so we do not limit this + // rule to specifically `FnOnce`. + // + // When the closure's body is something like `panic!()`, the + // return type would normally be inferred to `!`. However, it + // needs to fall back to `()` in order to still compile, as the + // trait is specifically implemented for `()` but not `!`. + // + // For details on the requirements for these relationships to be + // set, see the relationship finding module in + // compiler/rustc_trait_selection/src/traits/relationships.rs. + debug!("fallback to () - found trait and projection: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else if can_reach_non_diverging { + debug!("fallback to () - reached non-diverging: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.types.unit); + } else { + debug!("fallback to ! - all diverging: {:?}", diverging_vid); + diverging_fallback.insert(diverging_ty, self.tcx.mk_diverging_default()); + } + } + + diverging_fallback + } + + /// Returns a graph whose nodes are (unresolved) inference variables and where + /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`. + fn create_coercion_graph(&self) -> VecGraph { + let pending_obligations = self.fulfillment_cx.borrow_mut().pending_obligations(); + debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations); + let coercion_edges: Vec<(ty::TyVid, ty::TyVid)> = pending_obligations + .into_iter() + .filter_map(|obligation| { + // The predicates we are looking for look like `Coerce(?A -> ?B)`. + // They will have no bound variables. + obligation.predicate.kind().no_bound_vars() + }) + .filter_map(|atom| { + // We consider both subtyping and coercion to imply 'flow' from + // some position in the code `a` to a different position `b`. + // This is then used to determine which variables interact with + // live code, and as such must fall back to `()` to preserve + // soundness. + // + // In practice currently the two ways that this happens is + // coercion and subtyping. + let (a, b) = if let ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) = atom { + (a, b) + } else if let ty::PredicateKind::Subtype(ty::SubtypePredicate { + a_is_expected: _, + a, + b, + }) = atom + { + (a, b) + } else { + return None; + }; + + let a_vid = self.root_vid(a)?; + let b_vid = self.root_vid(b)?; + Some((a_vid, b_vid)) + }) + .collect(); + debug!("create_coercion_graph: coercion_edges={:?}", coercion_edges); + let num_ty_vars = self.infcx.num_ty_vars(); + VecGraph::new(num_ty_vars, coercion_edges) + } + + /// If `ty` is an unresolved type variable, returns its root vid. + fn root_vid(&self, ty: Ty<'tcx>) -> Option { + Some(self.infcx.root_var(self.infcx.shallow_resolve(ty).ty_vid()?)) + } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index ed01dae59f672..7b9629e534bf9 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -87,23 +87,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {}) } + #[instrument(skip(self, mutate_fulfillment_errors), level = "debug")] pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment( &self, mut ty: Ty<'tcx>, mutate_fulfillment_errors: impl Fn(&mut Vec>), ) -> Ty<'tcx> { - debug!("resolve_vars_with_obligations(ty={:?})", ty); - // No Infer()? Nothing needs doing. if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); + debug!("no inference var, nothing needs doing"); return ty; } // If `ty` is a type variable, see whether we already know what it is. ty = self.resolve_vars_if_possible(ty); if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); + debug!(?ty); return ty; } @@ -114,7 +113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.select_obligations_where_possible(false, mutate_fulfillment_errors); ty = self.resolve_vars_if_possible(ty); - debug!("resolve_vars_with_obligations: ty={:?}", ty); + debug!(?ty); ty } @@ -230,6 +229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This should be invoked **before any unifications have /// occurred**, so that annotations like `Vec<_>` are preserved /// properly. + #[instrument(skip(self), level = "debug")] pub fn write_user_type_annotation_from_substs( &self, hir_id: hir::HirId, @@ -237,37 +237,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { substs: SubstsRef<'tcx>, user_self_ty: Option>, ) { - debug!( - "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ - user_self_ty={:?} in fcx {}", - hir_id, - def_id, - substs, - user_self_ty, - self.tag(), - ); + debug!("fcx {}", self.tag()); if self.can_contain_user_lifetime_bounds((substs, user_self_ty)) { let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( def_id, UserSubsts { substs, user_self_ty }, )); - debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); + debug!(?canonicalized); self.write_user_type_annotation(hir_id, canonicalized); } } + #[instrument(skip(self), level = "debug")] pub fn write_user_type_annotation( &self, hir_id: hir::HirId, canonical_user_type_annotation: CanonicalUserType<'tcx>, ) { - debug!( - "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", - hir_id, - canonical_user_type_annotation, - self.tag(), - ); + debug!("fcx {}", self.tag()); if !canonical_user_type_annotation.is_identity() { self.typeck_results @@ -275,17 +263,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .user_provided_types_mut() .insert(hir_id, canonical_user_type_annotation); } else { - debug!("write_user_type_annotation: skipping identity substs"); + debug!("skipping identity substs"); } } + #[instrument(skip(self, expr), level = "debug")] pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec>) { - debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); + debug!("expr = {:#?}", expr); if adj.is_empty() { return; } + for a in &adj { + if let Adjust::NeverToAny = a.kind { + if a.target.is_ty_var() { + self.diverging_type_vars.borrow_mut().insert(a.target); + debug!("apply_adjustments: adding `{:?}` as diverging type var", a.target); + } + } + } + let autoborrow_mut = adj.iter().any(|adj| { matches!( adj, @@ -576,7 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicate(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx), )); } @@ -643,8 +641,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] pub(in super::super) fn select_all_obligations_or_error(&self) { - debug!("select_all_obligations_or_error"); if let Err(errors) = self .fulfillment_cx .borrow_mut() @@ -685,16 +683,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ret_ty.builtin_deref(true).unwrap() } + #[instrument(skip(self), level = "debug")] fn self_type_matches_expected_vid( &self, trait_ref: ty::PolyTraitRef<'tcx>, expected_vid: ty::TyVid, ) -> bool { let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); - debug!( - "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", - trait_ref, self_ty, expected_vid - ); + debug!(?self_ty); + match *self_ty.kind() { ty::Infer(ty::TyVar(found_vid)) => { // FIXME: consider using `sub_root_var` here so we @@ -707,6 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] pub(in super::super) fn obligations_for_self_ty<'b>( &'b self, self_ty: ty::TyVid, @@ -716,12 +714,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME: consider using `sub_root_var` here so we // can see through subtyping. let ty_var_root = self.root_var(self_ty); - debug!( - "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", - self_ty, - ty_var_root, - self.fulfillment_cx.borrow().pending_obligations() - ); + trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations()); self.fulfillment_cx .borrow() @@ -771,6 +764,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Unifies the output type with the expected type early, for more coercions /// and forward type information on the input expressions. + #[instrument(skip(self, call_span), level = "debug")] pub(in super::super) fn expected_inputs_for_expected_output( &self, call_span: Span, @@ -817,10 +811,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect()) }) .unwrap_or_default(); - debug!( - "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", - formal_args, formal_ret, expect_args, expected_ret - ); + debug!(?formal_args, ?formal_ret, ?expect_args, ?expected_ret); expect_args } @@ -1186,6 +1177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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")] pub fn instantiate_value_path( &self, segments: &[hir::PathSegment<'_>], @@ -1194,11 +1186,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, hir_id: hir::HirId, ) -> (Ty<'tcx>, Res) { - debug!( - "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", - segments, self_ty, res, hir_id, - ); - let tcx = self.tcx; let path_segs = match res { @@ -1221,7 +1208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { let container = tcx.associated_item(def_id).container; - debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); + debug!(?def_id, ?container); match container { ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(tcx, span, None, span, trait_did) diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs index 6006c8f7513d7..f7552c1f4eb0c 100644 --- a/compiler/rustc_typeck/src/check/inherited.rs +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -1,6 +1,7 @@ use super::callee::DeferredCallResolution; use super::MaybeInProgressTables; +use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::{DefIdMap, LocalDefId}; use rustc_hir::HirIdMap; @@ -56,6 +57,11 @@ pub struct Inherited<'a, 'tcx> { pub(super) constness: hir::Constness, pub(super) body_id: Option, + + /// Whenever we introduce an adjustment from `!` into a type variable, + /// we record that type variable here. This is later used to inform + /// fallback. See the `fallback` module for details. + pub(super) diverging_type_vars: RefCell>>, } impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { @@ -121,6 +127,7 @@ impl Inherited<'a, 'tcx> { deferred_call_resolutions: RefCell::new(Default::default()), deferred_cast_checks: RefCell::new(Vec::new()), deferred_generator_interiors: RefCell::new(Vec::new()), + diverging_type_vars: RefCell::new(Default::default()), constness, body_id, } diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index 88be49e96e7be..dc54f63f49c8d 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -28,7 +28,7 @@ struct ConfirmContext<'a, 'tcx> { impl<'a, 'tcx> Deref for ConfirmContext<'a, 'tcx> { type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { - &self.fcx + self.fcx } } @@ -290,7 +290,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { .autoderef(self.span, self_ty) .include_raw_pointers() .find_map(|(ty, _)| match ty.kind() { - ty::Dynamic(ref data, ..) => Some(closure( + ty::Dynamic(data, ..) => Some(closure( self, ty, data.principal().unwrap_or_else(|| { @@ -323,7 +323,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.tcx, self.span, pick.item.def_id, - &generics, + generics, seg, IsMethodCall::Yes, ); @@ -343,7 +343,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { def_id: DefId, ) -> (Option<&'a hir::GenericArgs<'a>>, bool) { if def_id == self.pick.item.def_id { - if let Some(ref data) = self.seg.args { + if let Some(data) = self.seg.args { return (Some(data), false); } } diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 8e09aa97dcf34..f0f2470e80a8c 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -21,7 +21,7 @@ use rustc_infer::infer::{self, InferOk}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_trait_selection::traits; @@ -160,7 +160,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(0); // Account for `foo.bar`; - let sugg_span = span.unwrap_or_else(|| call_expr.span).shrink_to_hi(); + let sugg_span = span.unwrap_or(call_expr.span).shrink_to_hi(); let (suggestion, applicability) = ( format!("({})", (0..params).map(|_| "_").collect::>().join(", ")), if params > 0 { Applicability::HasPlaceholders } else { Applicability::MaybeIncorrect }, @@ -290,29 +290,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } - /// `lookup_method_in_trait` is used for overloaded operators. - /// It does a very narrow slice of what the normal probe/confirm path does. - /// In particular, it doesn't really do any probing: it simply constructs - /// an obligation for a particular trait with the given self type and checks - /// whether that trait is implemented. - // - // FIXME(#18741): it seems likely that we can consolidate some of this - // code with the other method-lookup code. In particular, the second half - // of this method is basically the same as confirmation. - #[instrument(level = "debug", skip(self, span, opt_input_types))] - pub fn lookup_method_in_trait( + pub(super) fn obligation_for_method( &self, span: Span, - m_name: Ident, trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, - ) -> Option>> { - debug!( - "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})", - self_ty, m_name, trait_def_id, opt_input_types - ); - + ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List>) + { // Construct a trait-reference `self_ty : Trait` let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { @@ -320,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { GenericParamDefKind::Type { .. } => { if param.index == 0 { return self_ty.into(); - } else if let Some(ref input_types) = opt_input_types { + } else if let Some(input_types) = opt_input_types { return input_types[param.index as usize - 1].into(); } } @@ -331,18 +316,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_ref = ty::TraitRef::new(trait_def_id, substs); // Construct an obligation - let poly_trait_ref = trait_ref.to_poly_trait_ref(); - let obligation = traits::Obligation::misc( - span, - self.body_id, - self.param_env, - poly_trait_ref.without_const().to_predicate(self.tcx), + let poly_trait_ref = ty::Binder::dummy(trait_ref); + ( + traits::Obligation::misc( + span, + self.body_id, + self.param_env, + poly_trait_ref.without_const().to_predicate(self.tcx), + ), + substs, + ) + } + + /// `lookup_method_in_trait` is used for overloaded operators. + /// It does a very narrow slice of what the normal probe/confirm path does. + /// In particular, it doesn't really do any probing: it simply constructs + /// an obligation for a particular trait with the given self type and checks + /// whether that trait is implemented. + // + // FIXME(#18741): it seems likely that we can consolidate some of this + // code with the other method-lookup code. In particular, the second half + // of this method is basically the same as confirmation. + #[instrument(level = "debug", skip(self, span, opt_input_types))] + pub(super) fn lookup_method_in_trait( + &self, + span: Span, + m_name: Ident, + trait_def_id: DefId, + self_ty: Ty<'tcx>, + opt_input_types: Option<&[Ty<'tcx>]>, + ) -> Option>> { + debug!( + "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})", + self_ty, m_name, trait_def_id, opt_input_types ); + let (obligation, substs) = + self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types); + // Now we want to know if this can be matched if !self.predicate_may_hold(&obligation) { debug!("--> Cannot match obligation"); - return None; // Cannot be matched, no such method resolution is possible. + // Cannot be matched, no such method resolution is possible. + return None; } // Trait must have a method named `m_name` and it should not have @@ -413,10 +429,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligations.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx), )); - let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig }; + let callee = MethodCallee { def_id, substs, sig: fn_sig }; debug!("callee = {:?}", callee); diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index cbfdce96bc57b..44d6f076f5da4 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -21,9 +21,7 @@ use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{ - self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; +use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::lev_distance::{find_best_match_for_name, lev_distance}; @@ -90,7 +88,7 @@ struct ProbeContext<'a, 'tcx> { impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { - &self.fcx + self.fcx } } @@ -616,7 +614,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let lang_items = self.tcx.lang_items(); match *self_ty.value.value.kind() { - ty::Dynamic(ref data, ..) if let Some(p) = data.principal() => { + ty::Dynamic(data, ..) if let Some(p) = data.principal() => { // Subtle: we can't use `instantiate_query_response` here: using it will // commit to all of the type equalities assumed by inference going through // autoderef (see the `method-probe-no-guessing` test). @@ -636,7 +634,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // type variables in any form, so just do that! let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) = self.fcx - .instantiate_canonical_with_fresh_inference_vars(self.span, &self_ty); + .instantiate_canonical_with_fresh_inference_vars(self.span, self_ty); self.assemble_inherent_candidates_from_object(generalized_self_ty); self.assemble_inherent_impl_candidates_for_type(p.def_id()); @@ -966,8 +964,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs); if self.tcx.is_trait_alias(trait_def_id) { - // For trait aliases, assume all super-traits are relevant. - let bounds = iter::once(trait_ref.to_poly_trait_ref()); + // For trait aliases, assume all supertraits are relevant. + let bounds = iter::once(ty::Binder::dummy(trait_ref)); self.elaborate_bounds(bounds, |this, new_trait_ref, item| { let new_trait_ref = this.erase_late_bound_regions(new_trait_ref); @@ -1372,7 +1370,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { trait_ref: ty::TraitRef<'tcx>, ) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> { let cause = traits::ObligationCause::misc(self.span, self.body_id); - let predicate = trait_ref.to_poly_trait_ref().to_poly_trait_predicate(); + let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate(); let obligation = traits::Obligation::new(cause, self.param_env, predicate); traits::SelectionContext::new(self).select(&obligation) } @@ -1430,7 +1428,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // match as well (or at least may match, sometimes we // don't have enough information to fully evaluate). match probe.kind { - InherentImplCandidate(ref substs, ref ref_obligations) => { + InherentImplCandidate(substs, ref ref_obligations) => { // Check whether the impl imposes obligations we have to worry about. let impl_def_id = probe.item.container.id(); let impl_bounds = self.tcx.predicates_of(impl_def_id); @@ -1470,7 +1468,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } } - let predicate = trait_ref.without_const().to_predicate(self.tcx); + let predicate = + ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx); let obligation = traits::Obligation::new(cause, self.param_env, predicate); if !self.predicate_may_hold(&obligation) { result = ProbeResult::NoMatch; diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 9744f4f6483c7..183ebc559ae42 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -12,14 +12,12 @@ use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::fast_reject::simplify_type; use rustc_middle::ty::print::with_crate_prefix; -use rustc_middle::ty::{ - self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::lev_distance; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{source_map, FileName, Span}; +use rustc_span::{source_map, FileName, MultiSpan, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::Obligation; +use rustc_trait_selection::traits::{FulfillmentError, Obligation}; use std::cmp::Ordering; use std::iter; @@ -53,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into()], ); let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); - let poly_trait_ref = trait_ref.to_poly_trait_ref(); + let poly_trait_ref = ty::Binder::dummy(trait_ref); let obligation = Obligation::misc( span, self.body_id, @@ -178,6 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg_span, idx, self.tcx.sess.source_map(), + item.fn_has_self_parameter, ); } } @@ -220,6 +219,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg_span, idx, self.tcx.sess.source_map(), + item.fn_has_self_parameter, ); } } @@ -328,48 +328,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - ExprKind::Path(ref qpath) => { + ExprKind::Path(QPath::Resolved(_, path)) => { // local binding - if let QPath::Resolved(_, path) = qpath { - if let hir::def::Res::Local(hir_id) = path.res { - let span = tcx.hir().span(hir_id); - let snippet = tcx.sess.source_map().span_to_snippet(span); - let filename = tcx.sess.source_map().span_to_filename(span); - - let parent_node = self - .tcx - .hir() - .get(self.tcx.hir().get_parent_node(hir_id)); - let msg = format!( - "you must specify a type for this binding, like `{}`", - concrete_type, - ); - - match (filename, parent_node, snippet) { - ( - FileName::Real(_), - Node::Local(hir::Local { - source: hir::LocalSource::Normal, - ty, - .. - }), - Ok(ref snippet), - ) => { - err.span_suggestion( - // account for `let x: _ = 42;` - // ^^^^ - span.to(ty - .as_ref() - .map(|ty| ty.span) - .unwrap_or(span)), - &msg, - format!("{}: {}", snippet, concrete_type), - Applicability::MaybeIncorrect, - ); - } - _ => { - err.span_label(span, msg); - } + if let hir::def::Res::Local(hir_id) = path.res { + let span = tcx.hir().span(hir_id); + let snippet = tcx.sess.source_map().span_to_snippet(span); + let filename = tcx.sess.source_map().span_to_filename(span); + + let parent_node = + self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)); + let msg = format!( + "you must specify a type for this binding, like `{}`", + concrete_type, + ); + + match (filename, parent_node, snippet) { + ( + FileName::Real(_), + Node::Local(hir::Local { + source: hir::LocalSource::Normal, + ty, + .. + }), + Ok(ref snippet), + ) => { + err.span_suggestion( + // account for `let x: _ = 42;` + // ^^^^ + span.to(ty + .as_ref() + .map(|ty| ty.span) + .unwrap_or(span)), + &msg, + format!("{}: {}", snippet, concrete_type), + Applicability::MaybeIncorrect, + ); + } + _ => { + err.span_label(span, msg); } } } @@ -383,11 +379,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Don't show generic arguments when the method can't be found in any implementation (#81576). let mut ty_str_reported = ty_str.clone(); - if let ty::Adt(_, ref generics) = actual.kind() { + if let ty::Adt(_, generics) = actual.kind() { if generics.len() > 0 { let mut autoderef = self.autoderef(span, actual); let candidate_found = autoderef.any(|(ty, _)| { - if let ty::Adt(ref adt_deref, _) = ty.kind() { + if let ty::Adt(adt_deref, _) = ty.kind() { self.tcx .inherent_impls(adt_deref.did) .iter() @@ -482,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut label_span_not_found = || { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); - if let ty::Adt(ref adt, _) = rcvr_ty.kind() { + if let ty::Adt(adt, _) = rcvr_ty.kind() { let mut inherent_impls_candidate = self .tcx .inherent_impls(adt.did) @@ -511,7 +507,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }) .collect::>(); - if inherent_impls_candidate.len() > 0 { + if !inherent_impls_candidate.is_empty() { inherent_impls_candidate.sort(); inherent_impls_candidate.dedup(); @@ -565,7 +561,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_accessible = field.vis.is_accessible_from(scope, self.tcx); if is_accessible { - if self.is_fn_ty(&field_ty, span) { + if self.is_fn_ty(field_ty, span) { let expr_span = expr.span.to(item_name.span); err.multipart_suggestion( &format!( @@ -605,7 +601,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { label_span_not_found(); } - if self.is_fn_ty(&rcvr_ty, span) { + if self.is_fn_ty(rcvr_ty, span) { fn report_function( err: &mut DiagnosticBuilder<'_>, name: T, @@ -618,7 +614,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let SelfSource::MethodCall(expr) = source { if let Ok(expr_string) = tcx.sess.source_map().span_to_snippet(expr.span) { report_function(&mut err, expr_string); - } else if let ExprKind::Path(QPath::Resolved(_, ref path)) = expr.kind { + } else if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind { if let Some(segment) = path.segments.last() { report_function(&mut err, segment.ident); } @@ -808,7 +804,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - bound_list.sort_by(|(_, a), (_, b)| a.cmp(&b)); // Sort alphabetically. + bound_list.sort_by(|(_, a), (_, b)| a.cmp(b)); // Sort alphabetically. bound_list.dedup_by(|(_, a), (_, b)| a == b); // #35677 bound_list.sort_by_key(|(pos, _)| *pos); // Keep the original predicate order. bound_spans.sort(); @@ -973,61 +969,119 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } + crate fn note_unmet_impls_on_type( + &self, + err: &mut rustc_errors::DiagnosticBuilder<'_>, + errors: Vec>, + ) { + let all_local_types_needing_impls = + errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(pred) => match pred.self_ty().kind() { + ty::Adt(def, _) => def.did.is_local(), + _ => false, + }, + _ => false, + }); + let mut preds: Vec<_> = errors + .iter() + .filter_map(|e| match e.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(pred) => Some(pred), + _ => None, + }) + .collect(); + preds.sort_by_key(|pred| (pred.def_id(), pred.self_ty())); + let def_ids = preds + .iter() + .filter_map(|pred| match pred.self_ty().kind() { + ty::Adt(def, _) => Some(def.did), + _ => None, + }) + .collect::>(); + let sm = self.tcx.sess.source_map(); + let mut spans: MultiSpan = def_ids + .iter() + .filter_map(|def_id| { + let span = self.tcx.def_span(*def_id); + if span.is_dummy() { None } else { Some(sm.guess_head_span(span)) } + }) + .collect::>() + .into(); + + for pred in &preds { + match pred.self_ty().kind() { + ty::Adt(def, _) => { + spans.push_span_label( + sm.guess_head_span(self.tcx.def_span(def.did)), + format!("must implement `{}`", pred.trait_ref.print_only_trait_path()), + ); + } + _ => {} + } + } + + if all_local_types_needing_impls && spans.primary_span().is_some() { + let msg = if preds.len() == 1 { + format!( + "an implementation of `{}` might be missing for `{}`", + preds[0].trait_ref.print_only_trait_path(), + preds[0].self_ty() + ) + } else { + format!( + "the following type{} would have to `impl` {} required trait{} for this \ + operation to be valid", + pluralize!(def_ids.len()), + if def_ids.len() == 1 { "its" } else { "their" }, + pluralize!(preds.len()), + ) + }; + err.span_note(spans, &msg); + } + + let preds: Vec<_> = errors.iter().map(|e| (e.obligation.predicate, None)).collect(); + self.suggest_derive(err, &preds); + } + fn suggest_derive( &self, err: &mut DiagnosticBuilder<'_>, unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option>)>, ) { - let derivables = [ - sym::Eq, - sym::PartialEq, - sym::Ord, - sym::PartialOrd, - sym::Clone, - sym::Copy, - sym::Hash, - sym::Default, - sym::debug_trait, - ]; - let mut derives = unsatisfied_predicates - .iter() - .filter_map(|(pred, _)| { - let trait_pred = - if let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() { - trait_pred - } else { - return None; - }; - let trait_ref = trait_pred.trait_ref; - let adt_def = if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() { - adt_def - } else { - return None; - }; - if adt_def.did.is_local() { - let diagnostic_items = self.tcx.diagnostic_items(trait_ref.def_id.krate); - return derivables.iter().find_map(|trait_derivable| { - let item_def_id = - if let Some(item_def_id) = diagnostic_items.get(trait_derivable) { - item_def_id - } else { - return None; - }; - if item_def_id == &trait_pred.trait_ref.def_id - && !(adt_def.is_enum() && *trait_derivable == sym::Default) - { - return Some(( - format!("{}", trait_ref.self_ty()), - self.tcx.def_span(adt_def.did), - format!("{}", trait_ref.print_only_trait_path()), - )); - } - None - }); - } - None - }) - .collect::>(); + let mut derives = Vec::<(String, Span, String)>::new(); + let mut traits = Vec::::new(); + for (pred, _) in unsatisfied_predicates { + let trait_pred = match pred.kind().skip_binder() { + ty::PredicateKind::Trait(trait_pred) => trait_pred, + _ => continue, + }; + let adt = match trait_pred.self_ty().ty_adt_def() { + Some(adt) if adt.did.is_local() => adt, + _ => continue, + }; + let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) { + Some(sym::Default) => !adt.is_enum(), + Some( + sym::Eq + | sym::PartialEq + | sym::Ord + | sym::PartialOrd + | sym::Clone + | sym::Copy + | sym::Hash + | sym::Debug, + ) => true, + _ => false, + }; + if can_derive { + derives.push(( + format!("{}", trait_pred.self_ty()), + self.tcx.def_span(adt.did), + format!("{}", trait_pred.trait_ref.print_only_trait_name()), + )); + } else { + traits.push(self.tcx.def_span(trait_pred.def_id())); + } + } derives.sort(); let derives_grouped = derives.into_iter().fold( Vec::<(String, Span, String)>::new(), @@ -1042,6 +1096,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { acc }, ); + traits.sort(); + traits.dedup(); + + let len = traits.len(); + if len > 0 { + let span: MultiSpan = traits.into(); + err.span_note( + span, + &format!("the following trait{} must be implemented", pluralize!(len),), + ); + } + for (self_name, self_span, traits) in &derives_grouped { err.span_suggestion_verbose( self_span.shrink_to_lo(), @@ -1371,9 +1437,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }; // Obtain the span for `param` and use it for a structured suggestion. - if let (Some(ref param), Some(ref table)) = - (param_type, self.in_progress_typeck_results) - { + if let (Some(param), Some(table)) = (param_type, self.in_progress_typeck_results) { let table_owner = table.borrow().hir_owner; let generics = self.tcx.generics_of(table_owner.to_def_id()); let type_param = generics.type_param(param, self.tcx); @@ -1384,7 +1448,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We do this to avoid suggesting code that ends up as `T: FooBar`, // instead we suggest `T: Foo + Bar` in that case. match hir.get(id) { - Node::GenericParam(ref param) => { + Node::GenericParam(param) => { let mut impl_trait = false; let has_bounds = if let hir::GenericParamKind::Type { synthetic: Some(_), .. } = @@ -1558,7 +1622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match ty.kind() { ty::Adt(def, _) => def.did.is_local(), ty::Foreign(did) => did.is_local(), - ty::Dynamic(ref tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()), + ty::Dynamic(tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()), ty::Param(_) => true, // Everything else (primitive types, etc.) is effectively @@ -1646,7 +1710,7 @@ fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] { fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} } - tcx.hir().krate().visit_all_item_likes(&mut Visitor { traits: &mut traits }); + tcx.hir().visit_all_item_likes(&mut Visitor { traits: &mut traits }); // Cross-crate: @@ -1738,6 +1802,7 @@ fn print_disambiguation_help( span: Span, candidate: Option, source_map: &source_map::SourceMap, + fn_has_self_parameter: bool, ) { let mut applicability = Applicability::MachineApplicable; let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) { @@ -1756,9 +1821,14 @@ fn print_disambiguation_help( .collect::>() .join(", "), ); + let trait_name = if !fn_has_self_parameter { + format!("<{} as {}>", rcvr_ty, trait_name) + } else { + trait_name + }; (span, format!("{}::{}{}", trait_name, item_name, args)) } else { - (span.with_hi(item_name.span.lo()), format!("{}::", trait_name)) + (span.with_hi(item_name.span.lo()), format!("<{} as {}>::", rcvr_ty, trait_name)) }; err.span_suggestion_verbose( span, diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index a10490a9a15c7..7450b4a4ef1c3 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -271,22 +271,22 @@ fn primary_body_of( ) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> { match tcx.hir().get(id) { Node::Item(item) => match item.kind { - hir::ItemKind::Const(ref ty, body) | hir::ItemKind::Static(ref ty, _, body) => { + hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => { Some((body, Some(ty), None)) } - hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(&sig))), + hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))), _ => None, }, Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None)), + hir::TraitItemKind::Const(ty, Some(body)) => Some((body, Some(ty), None)), hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - Some((body, None, Some(&sig))) + Some((body, None, Some(sig))) } _ => None, }, Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None)), - hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(&sig))), + hir::ImplItemKind::Const(ty, body) => Some((body, Some(ty), None)), + hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(sig))), _ => None, }, Node::AnonConst(constant) => Some((constant.body, None, None)), @@ -555,16 +555,13 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. - match tcx.eval_static_initializer(id.to_def_id()) { - Ok(alloc) => { - if alloc.relocations().len() != 0 { - let msg = "statics with a custom `#[link_section]` must be a \ + if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) { + if alloc.relocations().len() != 0 { + let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.sess.span_err(span, msg); - } + tcx.sess.span_err(span, msg); } - Err(_) => {} } } @@ -631,7 +628,7 @@ fn missing_items_err( let padding: String = " ".repeat(indentation); for trait_item in missing_items { - let snippet = suggestion_signature(&trait_item, tcx); + let snippet = suggestion_signature(trait_item, tcx); let code = format!("{}{}\n{}", padding, snippet, padding); let msg = format!("implement the missing item: `{}`", snippet); let appl = Applicability::HasPlaceholders; @@ -921,9 +918,7 @@ impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { } fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) { - tcx.par_body_owners(|body_owner_def_id| { - tcx.ensure().typeck(body_owner_def_id); - }); + tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id)); } fn fatally_break_rust(sess: &Session) { diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index a574a63d63b28..79e004a47db53 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -18,6 +18,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt}; use std::ops::ControlFlow; @@ -257,12 +258,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method.sig.output() } // error types are considered "builtin" - Err(()) if lhs_ty.references_error() || rhs_ty.references_error() => { - self.tcx.ty_error() - } - Err(()) => { + Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), + Err(errors) => { let source_map = self.tcx.sess.source_map(); - let (mut err, missing_trait, use_output, involves_fn) = match is_assign { + let (mut err, missing_trait, use_output) = match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( self.tcx.sess, @@ -289,7 +288,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::BinOpKind::Shr => Some("std::ops::ShrAssign"), _ => None, }; - (err, missing_trait, false, false) + self.note_unmet_impls_on_type(&mut err, errors); + (err, missing_trait, false) } IsAssign::No => { let (message, missing_trait, use_output) = match op.node { @@ -376,9 +376,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{}", message.as_str()); - let mut involves_fn = false; if !lhs_expr.span.eq(&rhs_expr.span) { - involves_fn |= self.add_type_neq_err_label( + self.add_type_neq_err_label( &mut err, lhs_expr.span, lhs_ty, @@ -386,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { op, is_assign, ); - involves_fn |= self.add_type_neq_err_label( + self.add_type_neq_err_label( &mut err, rhs_expr.span, rhs_ty, @@ -395,10 +394,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_assign, ); } - (err, missing_trait, use_output, involves_fn) + self.note_unmet_impls_on_type(&mut err, errors); + (err, missing_trait, use_output) } }; - let mut suggested_deref = false; if let Ref(_, rty, _) = lhs_ty.kind() { if { self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span) @@ -423,7 +422,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "*".to_string(), rustc_errors::Applicability::MachineApplicable, ); - suggested_deref = true; } } } @@ -444,7 +442,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Check if the method would be found if the type param wasn't // involved. If so, it means that adding a trait bound to the param is // enough. Otherwise we do not give the suggestion. - let mut eraser = TypeParamEraser(&self, expr.span); + let mut eraser = TypeParamEraser(self, expr.span); let needs_bound = self .lookup_op_method( eraser.fold_ty(lhs_ty), @@ -474,8 +472,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { bug!("type param visitor stored a non type param: {:?}", ty.kind()); } - } else if !suggested_deref && !involves_fn { - suggest_impl_missing(&mut err, lhs_ty, &missing_trait); } } err.emit(); @@ -572,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { on the left and may require reallocation. This \ requires ownership of the string on the left"; - let string_type = self.tcx.get_diagnostic_item(sym::string_type); + let string_type = self.tcx.get_diagnostic_item(sym::String); let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() { Some(ty_def) => Some(ty_def.did) == string_type, None => false, @@ -665,7 +661,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.write_method_call(ex.hir_id, method); method.sig.output() } - Err(()) => { + Err(errors) => { let actual = self.resolve_vars_if_possible(operand_ty); if !actual.references_error() { let mut err = struct_span_err!( @@ -718,14 +714,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } Str | Never | Char | Tuple(_) | Array(_, _) => {} - Ref(_, ref lty, _) if *lty.kind() == Str => {} + Ref(_, lty, _) if *lty.kind() == Str => {} _ => { - let missing_trait = match op { - hir::UnOp::Neg => "std::ops::Neg", - hir::UnOp::Not => "std::ops::Not", - hir::UnOp::Deref => "std::ops::UnDerf", - }; - suggest_impl_missing(&mut err, operand_ty, &missing_trait); + self.note_unmet_impls_on_type(&mut err, errors); } } } @@ -741,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty: Ty<'tcx>, other_tys: &[Ty<'tcx>], op: Op, - ) -> Result, ()> { + ) -> Result, Vec>> { let lang = self.tcx.lang_items(); let span = match op { @@ -820,22 +811,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Op::Unary(..) => 0, }, ) { - return Err(()); + return Err(vec![]); } + let opname = Ident::with_dummy_span(opname); let method = trait_did.and_then(|trait_did| { - let opname = Ident::with_dummy_span(opname); self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)) }); - match method { - Some(ok) => { + match (method, trait_did) { + (Some(ok), _) => { let method = self.register_infer_ok_obligations(ok); self.select_obligations_where_possible(false, |_| {}); - Ok(method) } - None => Err(()), + (None, None) => Err(vec![]), + (None, Some(trait_did)) => { + let (obligation, _) = + self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys)); + let mut fulfill = >::new(self.tcx); + fulfill.register_predicate_obligation(self, obligation); + Err(match fulfill.select_where_possible(&self.infcx) { + Err(errors) => errors, + _ => vec![], + }) + } } } } @@ -962,18 +962,6 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool } } -/// If applicable, note that an implementation of `trait` for `ty` may fix the error. -fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_trait: &str) { - if let Adt(def, _) = ty.peel_refs().kind() { - if def.did.is_local() { - err.note(&format!( - "an implementation of `{}` might be missing for `{}`", - missing_trait, ty - )); - } - } -} - fn suggest_constraining_param( tcx: TyCtxt<'_>, body_id: hir::HirId, diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 829268e3cb527..635219146d0f5 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -181,8 +181,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti) } PatKind::Path(_) => self.check_pat_path(pat, path_res.unwrap(), expected, ti), - PatKind::Struct(ref qpath, fields, etc) => { - self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti) + PatKind::Struct(ref qpath, fields, has_rest_pat) => { + self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti) } PatKind::Or(pats) => { let parent_pat = Some(pat); @@ -341,7 +341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, mut def_bm: BindingMode, ) -> (Ty<'tcx>, BindingMode) { - let mut expected = self.resolve_vars_with_obligations(&expected); + let mut expected = self.resolve_vars_with_obligations(expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches @@ -449,16 +449,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr { - None => (None, None), + None => None, Some(expr) => { let ty = self.check_expr(expr); - // Check that the end-point is of numeric or char type. - let fail = !(ty.is_numeric() || ty.is_char() || ty.references_error()); - (Some(ty), Some((fail, ty, expr.span))) + // Check that the end-point is possibly of numeric or char type. + // The early check here is not for correctness, but rather better + // diagnostics (e.g. when `&str` is being matched, `expected` will + // be peeled to `str` while ty here is still `&str`, if we don't + // err ealy here, a rather confusing unification error will be + // emitted instead). + let fail = + !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error()); + Some((fail, ty, expr.span)) } }; - let (lhs_ty, lhs) = calc_side(lhs); - let (rhs_ty, rhs) = calc_side(rhs); + let mut lhs = calc_side(lhs); + let mut rhs = calc_side(rhs); if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { // There exists a side that didn't meet our criteria that the end-point @@ -467,25 +473,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return self.tcx.ty_error(); } - // Now that we know the types can be unified we find the unified type - // and use it to type the entire expression. - let common_type = self.resolve_vars_if_possible(lhs_ty.or(rhs_ty).unwrap_or(expected)); - + // Unify each side with `expected`. // Subtyping doesn't matter here, as the value is some kind of scalar. - let demand_eqtype = |x, y| { - if let Some((_, x_ty, x_span)) = x { + let demand_eqtype = |x: &mut _, y| { + if let Some((ref mut fail, x_ty, x_span)) = *x { if let Some(mut err) = self.demand_eqtype_pat_diag(x_span, expected, x_ty, ti) { if let Some((_, y_ty, y_span)) = y { self.endpoint_has_type(&mut err, y_span, y_ty); } err.emit(); + *fail = true; }; } }; - demand_eqtype(lhs, rhs); - demand_eqtype(rhs, lhs); + demand_eqtype(&mut lhs, rhs); + demand_eqtype(&mut rhs, lhs); - common_type + if let (Some((true, ..)), _) | (_, Some((true, ..))) = (lhs, rhs) { + return self.tcx.ty_error(); + } + + // Find the unified type and check if it's of numeric or char type again. + // This check is needed if both sides are inference variables. + // We require types to be resolved here so that we emit inference failure + // rather than "_ is not a char or numeric". + let ty = self.structurally_resolved_type(span, expected); + if !(ty.is_numeric() || ty.is_char() || ty.references_error()) { + if let Some((ref mut fail, _, _)) = lhs { + *fail = true; + } + if let Some((ref mut fail, _, _)) = rhs { + *fail = true; + } + self.emit_err_pat_range(span, lhs, rhs); + return self.tcx.ty_error(); + } + ty } fn endpoint_has_type(&self, err: &mut DiagnosticBuilder<'_>, span: Span, ty: Ty<'_>) { @@ -512,10 +535,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { E0029, "only `char` and numeric types are allowed in range patterns" ); - let msg = |ty| format!("this is of type `{}` but it should be `char` or numeric", ty); + let msg = |ty| { + let ty = self.resolve_vars_if_possible(ty); + format!("this is of type `{}` but it should be `char` or numeric", ty) + }; let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| { err.span_label(first_span, &msg(first_ty)); if let Some((_, ty, sp)) = second { + let ty = self.resolve_vars_if_possible(ty); self.endpoint_has_type(&mut err, sp, ty); } }; @@ -587,7 +614,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(p) = sub { - self.check_pat(&p, expected, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); + self.check_pat(p, expected, def_bm, TopInfo { parent_pat: Some(pat), ..ti }); } local_ty @@ -685,7 +712,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, qpath: &hir::QPath<'_>, fields: &'tcx [hir::PatField<'tcx>], - etc: bool, + has_rest_pat: bool, expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, @@ -697,8 +724,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { let err = self.tcx.ty_error(); for field in fields { - let ti = TopInfo { parent_pat: Some(&pat), ..ti }; - self.check_pat(&field.pat, err, def_bm, ti); + let ti = TopInfo { parent_pat: Some(pat), ..ti }; + self.check_pat(field.pat, err, def_bm, ti); } return err; }; @@ -707,7 +734,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.demand_eqtype_pat(pat.span, expected, pat_ty, ti); // Type-check subpatterns. - if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, etc, def_bm, ti) { + if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) { pat_ty } else { self.tcx.ty_error() @@ -876,7 +903,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let on_error = || { let parent_pat = Some(pat); for pat in subpats { - self.check_pat(&pat, tcx.ty_error(), def_bm, TopInfo { parent_pat, ..ti }); + self.check_pat(pat, tcx.ty_error(), def_bm, TopInfo { parent_pat, ..ti }); } }; let report_unexpected_res = |res: Res| { @@ -961,7 +988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs); - self.check_pat(&subpat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); + self.check_pat(subpat, field_ty, def_bm, TopInfo { parent_pat: Some(pat), ..ti }); self.tcx.check_stability( variant.fields[i].did, @@ -1151,7 +1178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut expected_len = elements.len(); if ddpos.is_some() { // Require known type only when `..` is present. - if let ty::Tuple(ref tys) = self.structurally_resolved_type(span, expected).kind() { + if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() { expected_len = tys.len(); } } @@ -1172,12 +1199,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| tcx.ty_error()); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, &tcx.ty_error(), def_bm, ti); + self.check_pat(elem, tcx.ty_error(), def_bm, ti); } tcx.mk_tup(element_tys_iter) } else { for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat(elem, &element_tys[i].expect_ty(), def_bm, ti); + self.check_pat(elem, element_tys[i].expect_ty(), def_bm, ti); } pat_ty } @@ -1189,7 +1216,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], - etc: bool, + has_rest_pat: bool, def_bm: BindingMode, ti: TopInfo<'tcx>, ) -> bool { @@ -1240,14 +1267,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - self.check_pat(&field.pat, field_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); + self.check_pat(field.pat, field_ty, def_bm, TopInfo { parent_pat: Some(pat), ..ti }); } let mut unmentioned_fields = variant .fields .iter() .map(|field| (field, field.ident.normalize_to_macros_2_0())) - .filter(|(_, ident)| !used_fields.contains_key(&ident)) + .filter(|(_, ident)| !used_fields.contains_key(ident)) .collect::>(); let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) { @@ -1263,7 +1290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Require `..` if struct has non_exhaustive attribute. let non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did.is_local(); - if non_exhaustive && !etc { + if non_exhaustive && !has_rest_pat { self.error_foreign_non_exhaustive_spat(pat, adt.variant_descr(), fields.is_empty()); } @@ -1275,7 +1302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .struct_span_err(pat.span, "union patterns should have exactly one field") .emit(); } - if etc { + if has_rest_pat { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !unmentioned_fields.is_empty() { @@ -1286,19 +1313,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) }) .collect(); - if non_exhaustive { - self.non_exhaustive_reachable_pattern(pat, &accessible_unmentioned_fields, adt_ty) - } else if !etc { + + if !has_rest_pat { if accessible_unmentioned_fields.is_empty() { - unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields)); + unmentioned_err = Some(self.error_no_accessible_fields(pat, fields)); } else { unmentioned_err = Some(self.error_unmentioned_fields( pat, &accessible_unmentioned_fields, accessible_unmentioned_fields.len() != unmentioned_fields.len(), - &fields, + fields, )); } + } else if non_exhaustive && !accessible_unmentioned_fields.is_empty() { + self.lint_non_exhaustive_omitted_patterns( + pat, + &accessible_unmentioned_fields, + adt_ty, + ) } } match (inexistent_fields_err, unmentioned_err) { @@ -1626,7 +1658,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// is not exhaustive enough. /// /// Nb: the partner lint for enums lives in `compiler/rustc_mir_build/src/thir/pattern/usefulness.rs`. - fn non_exhaustive_reachable_pattern( + fn lint_non_exhaustive_omitted_patterns( &self, pat: &Pat<'_>, unmentioned_fields: &[(&ty::FieldDef, Ident)], @@ -1763,7 +1795,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, &inner) { + let (box_ty, inner_ty) = if self.check_dereferenceable(span, expected, inner) { // Here, `demand::subtype` is good enough, but I don't // think any errors can be introduced by using `demand::eqtype`. let inner_ty = self.next_ty_var(TypeVariableOrigin { @@ -1777,7 +1809,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let err = tcx.ty_error(); (err, err) }; - self.check_pat(&inner, inner_ty, def_bm, ti); + self.check_pat(inner, inner_ty, def_bm, ti); box_ty } @@ -1792,7 +1824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let tcx = self.tcx; let expected = self.shallow_resolve(expected); - let (rptr_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, &inner) { + let (rptr_ty, inner_ty) = if self.check_dereferenceable(pat.span, expected, inner) { // `demand::subtype` would be good enough, but using `eqtype` turns // out to be equally general. See (note_1) for details. @@ -1814,7 +1846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Look for a case like `fn foo(&foo: u32)` and suggest // `fn foo(foo: &u32)` if let Some(mut err) = err { - self.borrow_pat_suggestion(&mut err, &pat, &inner, &expected); + self.borrow_pat_suggestion(&mut err, pat, inner, expected); err.emit(); } (rptr_ty, inner_ty) @@ -1824,7 +1856,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let err = tcx.ty_error(); (err, err) }; - self.check_pat(&inner, inner_ty, def_bm, TopInfo { parent_pat: Some(&pat), ..ti }); + self.check_pat(inner, inner_ty, def_bm, TopInfo { parent_pat: Some(pat), ..ti }); rptr_ty } @@ -1880,15 +1912,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type check all the patterns before `slice`. for elt in before { - self.check_pat(&elt, element_ty, def_bm, ti); + self.check_pat(elt, element_ty, def_bm, ti); } // Type check the `slice`, if present, against its expected type. if let Some(slice) = slice { - self.check_pat(&slice, opt_slice_ty.unwrap(), def_bm, ti); + self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti); } // Type check the elements after `slice`, if present. for elt in after { - self.check_pat(&elt, element_ty, def_bm, ti); + self.check_pat(elt, element_ty, def_bm, ti); } inferred } diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index 055072d3a1d9d..849bf1e455cbf 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -1,5 +1,7 @@ use crate::check::method::MethodCallee; use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp}; +use rustc_ast as ast; +use rustc_errors::Applicability; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; @@ -47,6 +49,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'_>, base_expr: &'tcx hir::Expr<'tcx>, base_ty: Ty<'tcx>, + index_expr: &'tcx hir::Expr<'tcx>, idx_ty: Ty<'tcx>, ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { // FIXME(#18741) -- this is almost but not quite the same as the @@ -56,12 +59,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut autoderef = self.autoderef(base_expr.span, base_ty); let mut result = None; while result.is_none() && autoderef.next().is_some() { - result = self.try_index_step(expr, base_expr, &autoderef, idx_ty); + result = self.try_index_step(expr, base_expr, &autoderef, idx_ty, index_expr); } self.register_predicates(autoderef.into_obligations()); result } + fn negative_index( + &self, + ty: Ty<'tcx>, + span: Span, + base_expr: &hir::Expr<'_>, + ) -> Option<(Ty<'tcx>, Ty<'tcx>)> { + let ty = self.resolve_vars_if_possible(ty); + let mut err = self.tcx.sess.struct_span_err( + span, + &format!("negative integers cannot be used to index on a `{}`", ty), + ); + err.span_label(span, &format!("cannot use a negative integer for indexing on `{}`", ty)); + if let (hir::ExprKind::Path(..), Ok(snippet)) = + (&base_expr.kind, self.tcx.sess.source_map().span_to_snippet(base_expr.span)) + { + // `foo[-1]` to `foo[foo.len() - 1]` + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "to access an element starting from the end of the `{}`, compute the index", + ty, + ), + format!("{}.len() ", snippet), + Applicability::MachineApplicable, + ); + } + err.emit(); + Some((self.tcx.ty_error(), self.tcx.ty_error())) + } + /// To type-check `base_expr[index_expr]`, we progressively autoderef /// (and otherwise adjust) `base_expr`, looking for a type which either /// supports builtin indexing or overloaded indexing. @@ -73,6 +106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_expr: &hir::Expr<'_>, autoderef: &Autoderef<'a, 'tcx>, index_ty: Ty<'tcx>, + index_expr: &hir::Expr<'_>, ) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> { let adjusted_ty = self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false)); @@ -82,6 +116,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr, base_expr, adjusted_ty, index_ty ); + if let hir::ExprKind::Unary( + hir::UnOp::Neg, + hir::Expr { + kind: hir::ExprKind::Lit(hir::Lit { node: ast::LitKind::Int(..), .. }), + .. + }, + ) = index_expr.kind + { + match adjusted_ty.kind() { + ty::Adt(ty::AdtDef { did, .. }, _) + if self.tcx.is_diagnostic_item(sym::Vec, *did) => + { + return self.negative_index(adjusted_ty, index_expr.span, base_expr); + } + ty::Slice(_) | ty::Array(_, _) => { + return self.negative_index(adjusted_ty, index_expr.span, base_expr); + } + _ => {} + } + } + for unsize in [false, true] { let mut self_ty = adjusted_ty; if unsize { @@ -233,7 +288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | hir::ExprKind::Index(ref expr, _) | hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind { - exprs.push(&expr); + exprs.push(expr); } debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs); @@ -295,10 +350,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } match expr.kind { - hir::ExprKind::Index(ref base_expr, ..) => { + hir::ExprKind::Index(base_expr, ..) => { self.convert_place_op_to_mutable(PlaceOp::Index, expr, base_expr); } - hir::ExprKind::Unary(hir::UnOp::Deref, ref base_expr) => { + hir::ExprKind::Unary(hir::UnOp::Deref, base_expr) => { self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr); } _ => {} diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 134604a0e32b4..693246a3433e0 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -190,7 +190,7 @@ pub struct RegionCtxt<'a, 'tcx> { impl<'a, 'tcx> Deref for RegionCtxt<'a, 'tcx> { type Target = FnCtxt<'a, 'tcx>; fn deref(&self) -> &Self::Target { - &self.fcx + self.fcx } } @@ -292,7 +292,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.outlives_environment.add_implied_bounds(self.fcx, fn_sig_tys, body_id.hir_id, span); self.outlives_environment.save_implied_bounds(body_id.hir_id); - self.link_fn_params(&body.params); + self.link_fn_params(body.params); self.visit_body(body); self.visit_region_obligations(body_id.hir_id); @@ -379,13 +379,13 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { // see above - self.constrain_bindings_in_pat(&arm.pat); + self.constrain_bindings_in_pat(arm.pat); intravisit::walk_arm(self, arm); } fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { // see above - self.constrain_bindings_in_pat(&l.pat); + self.constrain_bindings_in_pat(l.pat); self.link_local(l); intravisit::walk_local(self, l); } @@ -407,13 +407,13 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> { match expr.kind { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => { - self.link_addr_of(expr, m, &base); + self.link_addr_of(expr, m, base); intravisit::walk_expr(self, expr); } - hir::ExprKind::Match(ref discr, ref arms, _) => { - self.link_match(&discr, &arms[..]); + hir::ExprKind::Match(ref discr, arms, _) => { + self.link_match(discr, &arms[..]); intravisit::walk_expr(self, expr); } @@ -448,7 +448,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; let typeck_results = self.typeck_results.borrow(); - let adjustments = typeck_results.expr_adjustments(&expr); + let adjustments = typeck_results.expr_adjustments(expr); if adjustments.is_empty() { return Ok(place); } @@ -475,7 +475,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { self.link_autoref(expr, &place, autoref); } - place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, &adjustment))?; + place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, adjustment))?; } Ok(place) @@ -540,10 +540,10 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { None => { return; } - Some(ref expr) => &**expr, + Some(expr) => &*expr, }; let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr))); - self.link_pattern(discr_cmt, &local.pat); + self.link_pattern(discr_cmt, local.pat); } /// Computes the guarantors for any ref bindings in a match and @@ -554,7 +554,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))); debug!("discr_cmt={:?}", discr_cmt); for arm in arms { - self.link_pattern(discr_cmt.clone(), &arm.pat); + self.link_pattern(discr_cmt.clone(), arm.pat); } } @@ -567,7 +567,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { let param_cmt = self.with_mc(|mc| mc.cat_rvalue(param.hir_id, param.pat.span, param_ty)); debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param); - self.link_pattern(param_cmt, ¶m.pat); + self.link_pattern(param_cmt, param.pat); } } @@ -582,7 +582,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { if let Some(ty::BindByReference(mutbl)) = mc.typeck_results.extract_binding_mode(self.tcx.sess, *hir_id, *span) { - self.link_region_from_node_type(*span, *hir_id, mutbl, &sub_cmt); + self.link_region_from_node_type(*span, *hir_id, mutbl, sub_cmt); } } }) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 53b99a14f379d..b7c042a08cf1c 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -122,6 +122,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Analysis starting point. + #[instrument(skip(self, body), level = "debug")] fn analyze_closure( &self, closure_hir_id: hir::HirId, @@ -130,8 +131,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { body: &'tcx hir::Body<'tcx>, capture_clause: hir::CaptureBy, ) { - debug!("analyze_closure(id={:?}, body.id={:?})", closure_hir_id, body.id()); - // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); let (closure_def_id, substs) = match *ty.kind() { @@ -602,7 +601,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list); + debug!( + "For closure={:?}, min_captures before sorting={:?}", + closure_def_id, root_var_min_capture_list + ); + + // Now that we have the minimized list of captures, sort the captures by field id. + // This causes the closure to capture the upvars in the same order as the fields are + // declared which is also the drop order. Thus, in situations where we capture all the + // fields of some type, the obserable drop order will remain the same as it previously + // was even though we're dropping each capture individually. + // See https://github.com/rust-lang/project-rfc-2229/issues/42 and + // `src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`. + for (_, captures) in &mut root_var_min_capture_list { + captures.sort_by(|capture1, capture2| { + for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) { + // We do not need to look at the `Projection.ty` fields here because at each + // step of the iteration, the projections will either be the same and therefore + // the types must be as well or the current projection will be different and + // we will return the result of comparing the field indexes. + match (p1.kind, p2.kind) { + // Paths are the same, continue to next loop. + (ProjectionKind::Deref, ProjectionKind::Deref) => {} + (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) + if i1 == i2 => {} + + // Fields are different, compare them. + (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => { + return i1.cmp(&i2); + } + + // We should have either a pair of `Deref`s or a pair of `Field`s. + // Anything else is a bug. + ( + l @ (ProjectionKind::Deref | ProjectionKind::Field(..)), + r @ (ProjectionKind::Deref | ProjectionKind::Field(..)), + ) => bug!( + "ProjectionKinds Deref and Field were mismatched: ({:?}, {:?})", + l, + r + ), + ( + l + @ + (ProjectionKind::Index + | ProjectionKind::Subslice + | ProjectionKind::Deref + | ProjectionKind::Field(..)), + r + @ + (ProjectionKind::Index + | ProjectionKind::Subslice + | ProjectionKind::Deref + | ProjectionKind::Field(..)), + ) => bug!( + "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})", + l, + r + ), + } + } + + unreachable!( + "we captured two identical projections: capture1 = {:?}, capture2 = {:?}", + capture1, capture2 + ); + }); + } + + debug!( + "For closure={:?}, min_captures after sorting={:#?}", + closure_def_id, root_var_min_capture_list + ); typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list); } @@ -720,7 +790,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is a multi-line closure with just a `{` on the first line, // so we put the `let` on its own line. // We take the indentation from the next non-empty line. - let line2 = lines.filter(|line| !line.is_empty()).next().unwrap_or_default(); + let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default(); let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0; diagnostics_builder.span_suggestion( closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(), @@ -774,14 +844,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> String { let mut reasons = String::new(); - if auto_trait_reasons.len() > 0 { + if !auto_trait_reasons.is_empty() { reasons = format!( "{} trait implementation for closure", auto_trait_reasons.clone().into_iter().collect::>().join(", ") ); } - if auto_trait_reasons.len() > 0 && drop_reason { + if !auto_trait_reasons.is_empty() && drop_reason { reasons = format!("{} and ", reasons); } @@ -807,7 +877,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let auto_traits_def_id = vec![ self.tcx.lang_items().clone_trait(), self.tcx.lang_items().sync_trait(), - self.tcx.get_diagnostic_item(sym::send_trait), + self.tcx.get_diagnostic_item(sym::Send), self.tcx.lang_items().unpin_trait(), self.tcx.get_diagnostic_item(sym::unwind_safe_trait), self.tcx.get_diagnostic_item(sym::ref_unwind_safe_trait), @@ -815,13 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let auto_traits = vec!["`Clone`", "`Sync`", "`Send`", "`Unpin`", "`UnwindSafe`", "`RefUnwindSafe`"]; - let root_var_min_capture_list = if let Some(root_var_min_capture_list) = - min_captures.and_then(|m| m.get(&var_hir_id)) - { - root_var_min_capture_list - } else { - return None; - }; + let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?; let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id)); @@ -896,14 +960,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if capture_problems.len() > 0 { + if !capture_problems.is_empty() { problematic_captures.insert( (capture.info.path_expr_id, capture.to_string(self.tcx)), capture_problems, ); } } - if problematic_captures.len() > 0 { + if !problematic_captures.is_empty() { return Some(problematic_captures); } None @@ -972,7 +1036,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_moved = !projections_list.is_empty(); let is_not_completely_captured = - root_var_min_capture_list.iter().any(|capture| capture.place.projections.len() > 0); + root_var_min_capture_list.iter().any(|capture| !capture.place.projections.is_empty()); if is_moved && is_not_completely_captured @@ -986,7 +1050,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Some(diagnostics_info); } - return None; + None } /// Figures out the list of root variables (and their types) that aren't completely @@ -1082,7 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - if capture_diagnostic.len() > 0 { + if !capture_diagnostic.is_empty() { need_migrations.push((var_hir_id, responsible_captured_hir_ids)); } } @@ -1612,15 +1676,12 @@ struct InferBorrowKind<'a, 'tcx> { } impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind_for_consume( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - debug!( - "adjust_upvar_borrow_kind_for_consume(place_with_id={:?}, diag_expr_id={:?})", - place_with_id, diag_expr_id - ); let tcx = self.fcx.tcx; let upvar_id = if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { upvar_id @@ -1628,7 +1689,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { return; }; - debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id); + debug!(?upvar_id); let usage_span = tcx.hir().span(diag_expr_id); @@ -1647,16 +1708,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { /// Indicates that `place_with_id` is being directly mutated (e.g., assigned /// to). If the place is based on a by-ref upvar, this implies that /// the upvar must be borrowed using an `&mut` borrow. + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind_for_mut( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - debug!( - "adjust_upvar_borrow_kind_for_mut(place_with_id={:?}, diag_expr_id={:?})", - place_with_id, diag_expr_id - ); - if let PlaceBase::Upvar(_) = place_with_id.place.base { // Raw pointers don't inherit mutability if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { @@ -1666,16 +1723,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind_for_unique( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, ) { - debug!( - "adjust_upvar_borrow_kind_for_unique(place_with_id={:?}, diag_expr_id={:?})", - place_with_id, diag_expr_id - ); - if let PlaceBase::Upvar(_) = place_with_id.place.base { if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) { // Raw pointers don't inherit mutability. @@ -1712,6 +1765,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { /// moving from left to right as needed (but never right to left). /// Here the argument `mutbl` is the borrow_kind that is required by /// some particular use. + #[instrument(skip(self), level = "debug")] fn adjust_upvar_borrow_kind( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -1720,10 +1774,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { ) { let curr_capture_info = self.capture_information[&place_with_id.place]; - debug!( - "adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})", - place_with_id, diag_expr_id, curr_capture_info, kind - ); + debug!(?curr_capture_info); if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind { // It's already captured by value, we don't need to do anything here @@ -1743,6 +1794,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { }; } + #[instrument(skip(self, diag_expr_id), level = "debug")] fn init_capture_info_for_place( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -1769,7 +1821,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { self.capture_information.insert(place_with_id.place.clone(), capture_info); } else { - debug!("Not upvar: {:?}", place_with_id); + debug!("Not upvar"); } } } @@ -1796,27 +1848,22 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { - debug!("consume(place_with_id={:?}, diag_expr_id={:?})", place_with_id, diag_expr_id); - if !self.capture_information.contains_key(&place_with_id.place) { - self.init_capture_info_for_place(&place_with_id, diag_expr_id); + self.init_capture_info_for_place(place_with_id, diag_expr_id); } - self.adjust_upvar_borrow_kind_for_consume(&place_with_id, diag_expr_id); + self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id); } + #[instrument(skip(self), level = "debug")] fn borrow( &mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId, bk: ty::BorrowKind, ) { - debug!( - "borrow(place_with_id={:?}, diag_expr_id={:?}, bk={:?})", - place_with_id, diag_expr_id, bk - ); - // The region here will get discarded/ignored let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: bk, region: &ty::ReErased }); @@ -1853,9 +1900,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { } } + #[instrument(skip(self), level = "debug")] fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) { - debug!("mutate(assignee_place={:?}, diag_expr_id={:?})", assignee_place, diag_expr_id); - self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow); } } @@ -1945,7 +1991,7 @@ fn restrict_capture_precision<'tcx>( } } - return (place, curr_mode); + (place, curr_mode) } /// Truncate deref of any reference. @@ -2014,7 +2060,7 @@ fn construct_capture_kind_reason_string( place: &Place<'tcx>, capture_info: &ty::CaptureInfo<'tcx>, ) -> String { - let place_str = construct_place_string(tcx, &place); + let place_str = construct_place_string(tcx, place); let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue(_) => "ByValue".into(), @@ -2025,7 +2071,7 @@ fn construct_capture_kind_reason_string( } fn construct_path_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String { - let place_str = construct_place_string(tcx, &place); + let place_str = construct_place_string(tcx, place); format!("{} used here", place_str) } @@ -2035,7 +2081,7 @@ fn construct_capture_info_string( place: &Place<'tcx>, capture_info: &ty::CaptureInfo<'tcx>, ) -> String { - let place_str = construct_place_string(tcx, &place); + let place_str = construct_place_string(tcx, place); let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue(_) => "ByValue".into(), diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index cb07fcf5fef58..20cf9a75e1267 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -2,7 +2,7 @@ use crate::check::{FnCtxt, Inherited}; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -12,7 +12,7 @@ use rustc_hir::itemlikevisit::ParItemLikeVisitor; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_middle::hir::map as hir_map; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst}; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -20,7 +20,6 @@ use rustc_middle::ty::{ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; -use rustc_trait_selection::opaque_types::may_define_opaque_type; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc}; @@ -77,14 +76,14 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> { /// We do this check as a pre-pass before checking fn bodies because if these constraints are /// not included it frequently leads to confusing errors in fn bodies. So it's better to check /// the types first. +#[instrument(skip(tcx), level = "debug")] pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let item = tcx.hir().expect_item(hir_id); debug!( - "check_item_well_formed(it.def_id={:?}, it.name={})", - item.def_id, - tcx.def_path_str(def_id.to_def_id()) + ?item.def_id, + item.name = ? tcx.def_path_str(def_id.to_def_id()) ); match item.kind { @@ -145,20 +144,20 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { hir::ItemKind::Fn(ref sig, ..) => { check_item_fn(tcx, item.hir_id(), item.ident, item.span, sig.decl); } - hir::ItemKind::Static(ref ty, ..) => { + hir::ItemKind::Static(ty, ..) => { check_item_type(tcx, item.hir_id(), ty.span, false); } - hir::ItemKind::Const(ref ty, ..) => { + hir::ItemKind::Const(ty, ..) => { check_item_type(tcx, item.hir_id(), ty.span, false); } hir::ItemKind::ForeignMod { items, .. } => { for it in items.iter() { let it = tcx.hir().foreign_item(it.id); match it.kind { - hir::ForeignItemKind::Fn(ref decl, ..) => { + hir::ForeignItemKind::Fn(decl, ..) => { check_item_fn(tcx, it.hir_id(), it.ident, it.span, decl) } - hir::ForeignItemKind::Static(ref ty, ..) => { + hir::ForeignItemKind::Static(ty, ..) => { check_item_type(tcx, it.hir_id(), ty.span, true) } hir::ForeignItemKind::Type => (), @@ -199,8 +198,61 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span), _ => (None, trait_item.span), }; - check_object_unsafe_self_trait_by_name(tcx, &trait_item); + check_object_unsafe_self_trait_by_name(tcx, trait_item); check_associated_item(tcx, trait_item.hir_id(), span, method_sig); + + let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id); + let encl_trait = tcx.hir().expect_item(encl_trait_hir_id); + let encl_trait_def_id = encl_trait.def_id.to_def_id(); + let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() { + Some("fn") + } else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() { + Some("fn_mut") + } else { + None + }; + + if let (Some(fn_lang_item_name), "call") = + (fn_lang_item_name, trait_item.ident.name.to_ident_string().as_str()) + { + // We are looking at the `call` function of the `fn` or `fn_mut` lang item. + // Do some rudimentary sanity checking to avoid an ICE later (issue #83471). + if let Some(hir::FnSig { decl, span, .. }) = method_sig { + if let [self_ty, _] = decl.inputs { + if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) { + tcx.sess + .struct_span_err( + self_ty.span, + &format!( + "first argument of `call` in `{}` lang item must be a reference", + fn_lang_item_name + ), + ) + .emit(); + } + } else { + tcx.sess + .struct_span_err( + *span, + &format!( + "`call` function in `{}` lang item takes exactly two arguments", + fn_lang_item_name + ), + ) + .emit(); + } + } else { + tcx.sess + .struct_span_err( + trait_item.span, + &format!( + "`call` trait item in `{}` lang item must be a function", + fn_lang_item_name + ), + ) + .emit(); + } + } } fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { @@ -421,7 +473,7 @@ fn check_associated_item( item.def_id, &mut implied_bounds, ); - check_method_receiver(fcx, hir_sig, &item, self_ty); + check_method_receiver(fcx, hir_sig, item, self_ty); } ty::AssocKind::Type => { if let ty::AssocItemContainer::TraitContainer(_) = item.container { @@ -541,10 +593,10 @@ fn check_type_defn<'tcx, F>( fcx.register_predicate(traits::Obligation::new( cause, fcx.param_env, - ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), discr_substs, - )) + ))) .to_predicate(tcx), )); } @@ -557,8 +609,9 @@ fn check_type_defn<'tcx, F>( }); } +#[instrument(skip(tcx, item))] fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { - debug!("check_trait: {:?}", item.def_id); + debug!(?item.def_id); let trait_def = tcx.trait_def(item.def_id); if trait_def.is_marker @@ -712,13 +765,13 @@ fn check_impl<'tcx>( } /// Checks where-clauses and inline bounds that are declared on `def_id`. +#[instrument(skip(fcx), level = "debug")] fn check_where_clauses<'tcx, 'fcx>( fcx: &FnCtxt<'fcx, 'tcx>, span: Span, def_id: DefId, return_ty: Option<(Ty<'tcx>, Span)>, ) { - debug!("check_where_clauses(def_id={:?}, return_ty={:?})", def_id, return_ty); let tcx = fcx.tcx; let predicates = tcx.predicates_of(def_id); @@ -741,7 +794,7 @@ fn check_where_clauses<'tcx, 'fcx>( for param in &generics.params { match param.kind { GenericParamDefKind::Type { .. } => { - if is_our_default(¶m) { + if is_our_default(param) { let ty = tcx.type_of(param.def_id); // Ignore dependent defaults -- that is, where the default of one type // parameter includes another (e.g., ``). In those cases, we can't @@ -756,7 +809,7 @@ fn check_where_clauses<'tcx, 'fcx>( } } GenericParamDefKind::Const { .. } => { - if is_our_default(¶m) { + if is_our_default(param) { // FIXME(const_generics_defaults): This // is incorrect when dealing with unused substs, for example // for `struct Foo` @@ -888,17 +941,15 @@ fn check_where_clauses<'tcx, 'fcx>( let predicates = predicates.instantiate_identity(tcx); - if let Some((mut return_ty, span)) = return_ty { + if let Some((return_ty, _)) = return_ty { if return_ty.has_infer_types_or_consts() { fcx.select_obligations_where_possible(false, |_| {}); - return_ty = fcx.resolve_vars_if_possible(return_ty); } - check_opaque_types(fcx, def_id.expect_local(), span, return_ty); } let predicates = fcx.normalize_associated_types_in(span, predicates); - debug!("check_where_clauses: predicates={:?}", predicates.predicates); + debug!(?predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| { @@ -984,143 +1035,6 @@ fn check_fn_or_method<'fcx, 'tcx>( check_where_clauses(fcx, span, def_id, Some((sig.output(), hir_decl.output.span()))); } -/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions -/// laid for "higher-order pattern unification". -/// This ensures that inference is tractable. -/// In particular, definitions of opaque types can only use other generics as arguments, -/// and they cannot repeat an argument. Example: -/// -/// ```rust -/// type Foo = impl Bar; -/// -/// // Okay -- `Foo` is applied to two distinct, generic types. -/// fn a() -> Foo { .. } -/// -/// // Not okay -- `Foo` is applied to `T` twice. -/// fn b() -> Foo { .. } -/// -/// // Not okay -- `Foo` is applied to a non-generic type. -/// fn b() -> Foo { .. } -/// ``` -/// -fn check_opaque_types<'fcx, 'tcx>( - fcx: &FnCtxt<'fcx, 'tcx>, - fn_def_id: LocalDefId, - span: Span, - ty: Ty<'tcx>, -) { - trace!("check_opaque_types(fn_def_id={:?}, ty={:?})", fn_def_id, ty); - let tcx = fcx.tcx; - - ty.fold_with(&mut ty::fold::BottomUpFolder { - tcx, - ty_op: |ty| { - if let ty::Opaque(def_id, substs) = *ty.kind() { - trace!("check_opaque_types: opaque_ty, {:?}, {:?}", def_id, substs); - let generics = tcx.generics_of(def_id); - - let opaque_hir_id = if let Some(local_id) = def_id.as_local() { - tcx.hir().local_def_id_to_hir_id(local_id) - } else { - // Opaque types from other crates won't have defining uses in this crate. - return ty; - }; - if let hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) = - tcx.hir().expect_item(opaque_hir_id).kind - { - // No need to check return position impl trait (RPIT) - // because for type and const parameters they are correct - // by construction: we convert - // - // fn foo() -> impl Trait - // - // into - // - // type Foo - // fn foo() -> Foo. - // - // For lifetime parameters we convert - // - // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> - // - // into - // - // type foo::<'p0..'pn>::Foo<'q0..'qm> - // fn foo() -> foo::<'static..'static>::Foo<'l0..'lm>. - // - // which would error here on all of the `'static` args. - return ty; - } - if !may_define_opaque_type(tcx, fn_def_id, opaque_hir_id) { - return ty; - } - trace!("check_opaque_types: may define, generics={:#?}", generics); - let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default(); - for (i, arg) in substs.iter().enumerate() { - let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), - - GenericArgKind::Lifetime(region) if let ty::ReStatic = region => { - tcx.sess - .struct_span_err( - span, - "non-defining opaque type use in defining scope", - ) - .span_label( - tcx.def_span(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(); - continue; - } - - GenericArgKind::Lifetime(_) => true, - - GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), - }; - - if arg_is_param { - seen_params.entry(arg).or_default().push(i); - } else { - // Prevent `fn foo() -> Foo` from being defining. - let opaque_param = generics.param_at(i, tcx); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note( - tcx.def_span(opaque_param.def_id), - &format!( - "used non-generic {} `{}` for generic parameter", - opaque_param.kind.descr(), - arg, - ), - ) - .emit(); - } - } // for (arg, param) - - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(generics.param_at(i, tcx).def_id)) - .collect(); - tcx.sess - .struct_span_err(span, "non-defining opaque type use in defining scope") - .span_note(spans, &format!("{} used multiple times", descr)) - .emit(); - } - } - } // if let Opaque - ty - }, - lt_op: |lt| lt, - ct_op: |ct| ct, - }); -} - const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut self`, `self: Box`, \ `self: Rc`, `self: Arc`, or `self: Pin

: parent, : child, (?): don't-care + /// + /// DETACHED (-1) --------------------> EXITED (?) + /// finish/exd_tsk + /// ^ + /// | + /// |

detach + /// | + /// + /// INIT (0) -----------------------> FINISHED (-1) + /// finish + /// | | + /// |

join/slp_tsk |

join/del_tsk + /// | |

detach/del_tsk + /// v v + /// + /// JOINING JOINED (?) + /// (parent_tid) + /// ^ + /// \ / + /// \ finish/wup_tsk /

slp_tsk-complete/ter_tsk + /// \ / & del_tsk + /// \ / + /// '--> JOIN_FINALIZE ---' + /// (-1) + /// + lifecycle: AtomicUsize, +} + +// Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by +// the task represented by `ThreadInner`. +unsafe impl Sync for ThreadInner {} + +const LIFECYCLE_INIT: usize = 0; +const LIFECYCLE_FINISHED: usize = usize::MAX; +const LIFECYCLE_DETACHED: usize = usize::MAX; +const LIFECYCLE_JOIN_FINALIZE: usize = usize::MAX; +const LIFECYCLE_DETACHED_OR_JOINED: usize = usize::MAX; +const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX; +// there's no single value for `JOINING` + +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * crate::mem::size_of::(); + +impl Thread { + /// # Safety + /// + /// See `thread::Builder::spawn_unchecked` for safety requirements. + pub unsafe fn new(stack: usize, p: Box) -> io::Result { + // Inherit the current task's priority + let current_task = task::try_current_task_id().map_err(|e| e.as_io_error())?; + let priority = task::try_task_priority(current_task).map_err(|e| e.as_io_error())?; + + let inner = Box::new(ThreadInner { + start: UnsafeCell::new(ManuallyDrop::new(p)), + lifecycle: AtomicUsize::new(LIFECYCLE_INIT), + }); + + unsafe extern "C" fn trampoline(exinf: isize) { + // Safety: `ThreadInner` is alive at this point + let inner = unsafe { &*(exinf as *const ThreadInner) }; + + // Safety: Since `trampoline` is called only once for each + // `ThreadInner` and only `trampoline` touches `start`, + // `start` contains contents and is safe to mutably borrow. + let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) }; + p(); + + // Fix the current thread's state just in case, so that the + // destructors won't abort + // Safety: Not really unsafe + let _ = unsafe { abi::unl_cpu() }; + let _ = unsafe { abi::ena_dsp() }; + + // Run TLS destructors now because they are not + // called automatically for terminated tasks. + unsafe { run_dtors() }; + + let old_lifecycle = inner + .lifecycle + .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release); + + match old_lifecycle { + LIFECYCLE_DETACHED => { + // [DETACHED → EXITED] + // No one will ever join, so we'll ask the collector task to + // delete the task. + + // In this case, `inner`'s ownership has been moved to us, + // And we are responsible for dropping it. The acquire + // ordering is not necessary because the parent thread made + // no memory acccess needing synchronization since the call + // to `acre_tsk`. + // Safety: See above. + let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) }; + + // Safety: There are no pinned references to the stack + unsafe { terminate_and_delete_current_task() }; + } + LIFECYCLE_INIT => { + // [INIT → FINISHED] + // The parent hasn't decided whether to join or detach this + // thread yet. Whichever option the parent chooses, + // it'll have to delete this task. + // Since the parent might drop `*inner` as soon as it sees + // `FINISHED`, the release ordering must be used in the + // above `swap` call. + } + parent_tid => { + // Since the parent might drop `*inner` and terminate us as + // soon as it sees `JOIN_FINALIZE`, the release ordering + // must be used in the above `swap` call. + + // [JOINING → JOIN_FINALIZE] + // Wake up the parent task. + expect_success( + unsafe { + let mut er = abi::wup_tsk(parent_tid as _); + if er == abi::E_QOVR { + // `E_QOVR` indicates there's already + // a parking token + er = abi::E_OK; + } + er + }, + &"wup_tsk", + ); + } + } + } + + let inner_ptr = (&*inner) as *const ThreadInner; + + let new_task = ItronError::err_if_negative(unsafe { + abi::acre_tsk(&abi::T_CTSK { + // Activate this task immediately + tskatr: abi::TA_ACT, + exinf: inner_ptr as abi::EXINF, + // The entry point + task: Some(trampoline), + itskpri: priority, + stksz: stack, + // Let the kernel allocate the stack, + stk: crate::ptr::null_mut(), + }) + }) + .map_err(|e| e.as_io_error())?; + + Ok(Self { inner: ManuallyDrop::new(inner), task: new_task }) + } + + pub fn yield_now() { + expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq"); + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(dur: Duration) { + for timeout in dur2reltims(dur) { + expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk"); + } + } + + pub fn join(mut self) { + let inner = &*self.inner; + // Get the current task ID. Panicking here would cause a resource leak, + // so just abort on failure. + let current_task = task::current_task_id_aborting(); + debug_assert!(usize::try_from(current_task).is_ok()); + debug_assert_ne!(current_task as usize, LIFECYCLE_INIT); + debug_assert_ne!(current_task as usize, LIFECYCLE_DETACHED); + + let current_task = current_task as usize; + + match inner.lifecycle.swap(current_task, Ordering::Acquire) { + LIFECYCLE_INIT => { + // [INIT → JOINING] + // The child task will transition the state to `JOIN_FINALIZE` + // and wake us up. + loop { + expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk"); + // To synchronize with the child task's memory accesses to + // `inner` up to the point of the assignment of + // `JOIN_FINALIZE`, `Ordering::Acquire` must be used for the + // `load`. + if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE { + break; + } + } + + // [JOIN_FINALIZE → JOINED] + } + LIFECYCLE_FINISHED => { + // [FINISHED → JOINED] + // To synchronize with the child task's memory accesses to + // `inner` up to the point of the assignment of `FINISHED`, + // `Ordering::Acquire` must be used for the above `swap` call`. + } + _ => unsafe { hint::unreachable_unchecked() }, + } + + // Terminate and delete the task + // Safety: `self.task` still represents a task we own (because this + // method or `detach_inner` is called only once for each + // `Thread`). The task indicated that it's safe to delete by + // entering the `FINISHED` or `JOIN_FINALIZE` state. + unsafe { terminate_and_delete_task(self.task) }; + + // In either case, we are responsible for dropping `inner`. + // Safety: The contents of `self.inner` will not be accessed hereafter + let _inner = unsafe { ManuallyDrop::take(&mut self.inner) }; + + // Skip the destructor (because it would attempt to detach the thread) + crate::mem::forget(self); + } +} + +impl Drop for Thread { + fn drop(&mut self) { + // Detach the thread. + match self.inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) { + LIFECYCLE_INIT => { + // [INIT → DETACHED] + // When the time comes, the child will figure out that no + // one will ever join it. + // The ownership of `self.inner` is moved to the child thread. + // However, the release ordering is not necessary because we + // made no memory acccess needing synchronization since the call + // to `acre_tsk`. + } + LIFECYCLE_FINISHED => { + // [FINISHED → JOINED] + // The task has already decided that we should delete the task. + // To synchronize with the child task's memory accesses to + // `inner` up to the point of the assignment of `FINISHED`, + // the acquire ordering is required for the above `swap` call. + + // Terminate and delete the task + // Safety: `self.task` still represents a task we own (because + // this method or `join_inner` is called only once for + // each `Thread`). The task indicated that it's safe to + // delete by entering the `FINISHED` state. + unsafe { terminate_and_delete_task(self.task) }; + + // Wwe are responsible for dropping `inner`. + // Safety: The contents of `self.inner` will not be accessed + // hereafter + unsafe { ManuallyDrop::drop(&mut self.inner) }; + } + _ => unsafe { hint::unreachable_unchecked() }, + } + } +} + +pub mod guard { + pub type Guard = !; + pub unsafe fn current() -> Option { + None + } + pub unsafe fn init() -> Option { + None + } +} + +/// Terminate and delete the specified task. +/// +/// This function will abort if `deleted_task` refers to the calling task. +/// +/// It is assumed that the specified task is solely managed by the caller - +/// i.e., other threads must not "resuscitate" the specified task or delete it +/// prematurely while this function is still in progress. It is allowed for the +/// specified task to exit by its own. +/// +/// # Safety +/// +/// The task must be safe to terminate. This is in general not true +/// because there might be pinned references to the task's stack. +unsafe fn terminate_and_delete_task(deleted_task: abi::ID) { + // Terminate the task + // Safety: Upheld by the caller + match unsafe { abi::ter_tsk(deleted_task) } { + // Indicates the task is already dormant, ignore it + abi::E_OBJ => {} + er => { + expect_success_aborting(er, &"ter_tsk"); + } + } + + // Delete the task + // Safety: Upheld by the caller + expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk"); +} + +/// Terminate and delete the calling task. +/// +/// Atomicity is not required - i.e., it can be assumed that other threads won't +/// `ter_tsk` the calling task while this function is still in progress. (This +/// property makes it easy to implement this operation on μITRON-derived kernels +/// that don't support `exd_tsk`.) +/// +/// # Safety +/// +/// The task must be safe to terminate. This is in general not true +/// because there might be pinned references to the task's stack. +unsafe fn terminate_and_delete_current_task() -> ! { + expect_success_aborting(unsafe { abi::exd_tsk() }, &"exd_tsk"); + // Safety: `exd_tsk` never returns on success + unsafe { crate::hint::unreachable_unchecked() }; +} + +pub fn available_concurrency() -> io::Result { + super::unsupported() +} diff --git a/library/std/src/sys/itron/time.rs b/library/std/src/sys/itron/time.rs new file mode 100644 index 0000000000000..6a992ad1d3c75 --- /dev/null +++ b/library/std/src/sys/itron/time.rs @@ -0,0 +1,123 @@ +use super::{abi, error::expect_success}; +use crate::{convert::TryInto, mem::MaybeUninit, time::Duration}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct Instant(abi::SYSTIM); + +impl Instant { + pub fn now() -> Instant { + // Safety: The provided pointer is valid + unsafe { + let mut out = MaybeUninit::uninit(); + expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim"); + Instant(out.assume_init()) + } + } + + pub const fn zero() -> Instant { + Instant(0) + } + + pub fn actually_monotonic() -> bool { + // There are ways to change the system time + false + } + + pub fn checked_sub_instant(&self, other: &Instant) -> Option { + self.0.checked_sub(other.0).map(|ticks| { + // `SYSTIM` is measured in microseconds + Duration::from_micros(ticks) + }) + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + // `SYSTIM` is measured in microseconds + let ticks = other.as_micros(); + + Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + // `SYSTIM` is measured in microseconds + let ticks = other.as_micros(); + + Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?)) + } +} + +/// Split `Duration` into zero or more `RELTIM`s. +#[inline] +pub fn dur2reltims(dur: Duration) -> impl Iterator { + // `RELTIM` is microseconds + let mut ticks = dur.as_micros(); + + crate::iter::from_fn(move || { + if ticks == 0 { + None + } else if ticks <= abi::TMAX_RELTIM as u128 { + Some(crate::mem::replace(&mut ticks, 0) as abi::RELTIM) + } else { + ticks -= abi::TMAX_RELTIM as u128; + Some(abi::TMAX_RELTIM) + } + }) +} + +/// Split `Duration` into one or more `TMO`s. +#[inline] +fn dur2tmos(dur: Duration) -> impl Iterator { + // `TMO` is microseconds + let mut ticks = dur.as_micros(); + let mut end = false; + + crate::iter::from_fn(move || { + if end { + None + } else if ticks <= abi::TMAX_RELTIM as u128 { + end = true; + Some(crate::mem::replace(&mut ticks, 0) as abi::TMO) + } else { + ticks -= abi::TMAX_RELTIM as u128; + Some(abi::TMAX_RELTIM) + } + }) +} + +/// Split `Duration` into one or more API calls with timeout. +#[inline] +pub fn with_tmos(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER { + let mut er = abi::E_TMOUT; + for tmo in dur2tmos(dur) { + er = f(tmo); + if er != abi::E_TMOUT { + break; + } + } + er +} + +/// Split `Duration` into one or more API calls with timeout. This function can +/// handle spurious wakeups. +#[inline] +pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER { + // `TMO` and `SYSTIM` are microseconds. + // Clamp at `SYSTIM::MAX` for performance reasons. This shouldn't cause + // a problem in practice. (`u64::MAX` μs ≈ 584942 years) + let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM; + + let start = Instant::now().0; + let mut elapsed = 0; + let mut er = abi::E_TMOUT; + while elapsed <= ticks { + er = f(elapsed.min(abi::TMAX_RELTIM as abi::SYSTIM) as abi::TMO); + if er != abi::E_TMOUT { + break; + } + elapsed = Instant::now().0.wrapping_sub(start); + } + + er +} + +#[cfg(test)] +mod tests; diff --git a/library/std/src/sys/itron/time/tests.rs b/library/std/src/sys/itron/time/tests.rs new file mode 100644 index 0000000000000..d14035d9da49f --- /dev/null +++ b/library/std/src/sys/itron/time/tests.rs @@ -0,0 +1,33 @@ +use super::*; + +fn reltim2dur(t: u64) -> Duration { + Duration::from_micros(t) +} + +#[test] +fn test_dur2reltims() { + assert_eq!(dur2reltims(reltim2dur(0)).collect::>(), vec![]); + assert_eq!(dur2reltims(reltim2dur(42)).collect::>(), vec![42]); + assert_eq!( + dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), + vec![abi::TMAX_RELTIM] + ); + assert_eq!( + dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), + vec![abi::TMAX_RELTIM, 10000] + ); +} + +#[test] +fn test_dur2tmos() { + assert_eq!(dur2tmos(reltim2dur(0)).collect::>(), vec![0]); + assert_eq!(dur2tmos(reltim2dur(42)).collect::>(), vec![42]); + assert_eq!( + dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::>(), + vec![abi::TMAX_RELTIM] + ); + assert_eq!( + dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::>(), + vec![abi::TMAX_RELTIM, 10000] + ); +} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index f813587b1b340..8b8be6ebc2f55 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -31,6 +31,9 @@ cfg_if::cfg_if! { } else if #[cfg(windows)] { mod windows; pub use self::windows::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use self::solid::*; } else if #[cfg(target_os = "hermit")] { mod hermit; pub use self::hermit::*; diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs index cbb8ba964018a..d745a61961404 100644 --- a/library/std/src/sys/sgx/thread.rs +++ b/library/std/src/sys/sgx/thread.rs @@ -137,7 +137,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/solid/abi/fs.rs b/library/std/src/sys/solid/abi/fs.rs new file mode 100644 index 0000000000000..32800bd9a9d0a --- /dev/null +++ b/library/std/src/sys/solid/abi/fs.rs @@ -0,0 +1,53 @@ +//! `solid_fs.h` +use crate::os::raw::{c_char, c_int, c_uchar}; +pub use libc::{ + blksize_t, dev_t, ino_t, off_t, stat, time_t, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, + O_TRUNC, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, S_IEXEC, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, + S_IFMT, S_IFREG, S_IREAD, S_IWRITE, +}; + +pub const O_ACCMODE: c_int = 0x3; + +pub const SOLID_MAX_PATH: usize = 256; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct dirent { + pub d_ino: ino_t, + pub d_type: c_uchar, + pub d_name: [c_char; 256usize], +} + +pub const DT_UNKNOWN: c_uchar = 0; +pub const DT_FIFO: c_uchar = 1; +pub const DT_CHR: c_uchar = 2; +pub const DT_DIR: c_uchar = 4; +pub const DT_BLK: c_uchar = 6; +pub const DT_REG: c_uchar = 8; +pub const DT_LNK: c_uchar = 10; +pub const DT_SOCK: c_uchar = 12; +pub const DT_WHT: c_uchar = 14; + +pub type S_DIR = c_int; + +extern "C" { + pub fn SOLID_FS_Open(fd: *mut c_int, path: *const c_char, mode: c_int) -> c_int; + pub fn SOLID_FS_Close(fd: c_int) -> c_int; + pub fn SOLID_FS_Read(fd: c_int, buf: *mut u8, size: usize, result: *mut usize) -> c_int; + pub fn SOLID_FS_Write(fd: c_int, buf: *const u8, size: usize, result: *mut usize) -> c_int; + pub fn SOLID_FS_Lseek(fd: c_int, offset: off_t, whence: c_int) -> c_int; + pub fn SOLID_FS_Sync(fd: c_int) -> c_int; + pub fn SOLID_FS_Ftell(fd: c_int, result: *mut off_t) -> c_int; + pub fn SOLID_FS_Feof(fd: c_int, result: *mut c_int) -> c_int; + pub fn SOLID_FS_Fsize(fd: c_int, result: *mut usize) -> c_int; + pub fn SOLID_FS_Truncate(path: *const c_char, size: off_t) -> c_int; + pub fn SOLID_FS_OpenDir(path: *const c_char, pDir: *mut S_DIR) -> c_int; + pub fn SOLID_FS_CloseDir(dir: S_DIR) -> c_int; + pub fn SOLID_FS_ReadDir(dir: S_DIR, dirp: *mut dirent) -> c_int; + pub fn SOLID_FS_Stat(path: *const c_char, buf: *mut stat) -> c_int; + pub fn SOLID_FS_Unlink(path: *const c_char) -> c_int; + pub fn SOLID_FS_Rename(oldpath: *const c_char, newpath: *const c_char) -> c_int; + pub fn SOLID_FS_Chmod(path: *const c_char, mode: c_int) -> c_int; + pub fn SOLID_FS_Utime(path: *const c_char, time: time_t) -> c_int; + pub fn SOLID_FS_Mkdir(path: *const c_char) -> c_int; +} diff --git a/library/std/src/sys/solid/abi/mod.rs b/library/std/src/sys/solid/abi/mod.rs new file mode 100644 index 0000000000000..3526440fb85f0 --- /dev/null +++ b/library/std/src/sys/solid/abi/mod.rs @@ -0,0 +1,92 @@ +use crate::os::raw::c_int; + +mod fs; +pub mod sockets; +pub use self::fs::*; + +pub const SOLID_BP_PROGRAM_EXITED: usize = 15; +pub const SOLID_BP_CSABORT: usize = 16; + +#[inline(always)] +pub fn breakpoint_program_exited(tid: usize) { + unsafe { + match () { + #[cfg(target_arch = "arm")] + () => asm!("bkpt #{}", const SOLID_BP_PROGRAM_EXITED, in("r0") tid), + #[cfg(target_arch = "aarch64")] + () => asm!("hlt #{}", const SOLID_BP_PROGRAM_EXITED, in("x0") tid), + } + } +} + +#[inline(always)] +pub fn breakpoint_abort() { + unsafe { + match () { + #[cfg(target_arch = "arm")] + () => asm!("bkpt #{}", const SOLID_BP_CSABORT), + #[cfg(target_arch = "aarch64")] + () => asm!("hlt #{}", const SOLID_BP_CSABORT), + } + } +} + +// `solid_types.h` +pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID}; + +pub const SOLID_ERR_NOTFOUND: ER = -1000; +pub const SOLID_ERR_NOTSUPPORTED: ER = -1001; +pub const SOLID_ERR_EBADF: ER = -1002; +pub const SOLID_ERR_INVALIDCONTENT: ER = -1003; +pub const SOLID_ERR_NOTUSED: ER = -1004; +pub const SOLID_ERR_ALREADYUSED: ER = -1005; +pub const SOLID_ERR_OUTOFBOUND: ER = -1006; +pub const SOLID_ERR_BADSEQUENCE: ER = -1007; +pub const SOLID_ERR_UNKNOWNDEVICE: ER = -1008; +pub const SOLID_ERR_BUSY: ER = -1009; +pub const SOLID_ERR_TIMEOUT: ER = -1010; +pub const SOLID_ERR_INVALIDACCESS: ER = -1011; +pub const SOLID_ERR_NOTREADY: ER = -1012; + +// `solid_rtc.h` +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct SOLID_RTC_TIME { + pub tm_sec: c_int, + pub tm_min: c_int, + pub tm_hour: c_int, + pub tm_mday: c_int, + pub tm_mon: c_int, + pub tm_year: c_int, + pub tm_wday: c_int, +} + +extern "C" { + pub fn SOLID_RTC_ReadTime(time: *mut SOLID_RTC_TIME) -> c_int; +} + +// `solid_log.h` +extern "C" { + pub fn SOLID_LOG_write(s: *const u8, l: usize); +} + +// `solid_mem.h` +extern "C" { + pub fn SOLID_TLS_AddDestructor(id: i32, dtor: unsafe extern "C" fn(*mut u8)); +} + +// `solid_rng.h` +extern "C" { + pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> c_int; +} + +// `rwlock.h` +extern "C" { + pub fn rwl_loc_rdl(id: ID) -> ER; + pub fn rwl_loc_wrl(id: ID) -> ER; + pub fn rwl_ploc_rdl(id: ID) -> ER; + pub fn rwl_ploc_wrl(id: ID) -> ER; + pub fn rwl_unl_rwl(id: ID) -> ER; + pub fn rwl_acre_rwl() -> ER_ID; + pub fn rwl_del_rwl(id: ID) -> ER; +} diff --git a/library/std/src/sys/solid/abi/sockets.rs b/library/std/src/sys/solid/abi/sockets.rs new file mode 100644 index 0000000000000..7c21d0dd25e03 --- /dev/null +++ b/library/std/src/sys/solid/abi/sockets.rs @@ -0,0 +1,274 @@ +use crate::os::raw::{c_char, c_uint, c_void}; +pub use libc::{c_int, c_long, size_t, ssize_t, suseconds_t, time_t, timeval}; + +pub const SOLID_NET_ERR_BASE: c_int = -2000; +pub const EINPROGRESS: c_int = SOLID_NET_ERR_BASE - libc::EINPROGRESS; + +pub const AF_INET6: i32 = 10; +pub const AF_INET: i32 = 2; +pub const IPPROTO_IP: i32 = 0; +pub const IPPROTO_IPV6: i32 = 41; +pub const IPPROTO_TCP: i32 = 6; +pub const IPV6_ADD_MEMBERSHIP: i32 = 12; +pub const IPV6_DROP_MEMBERSHIP: i32 = 13; +pub const IPV6_MULTICAST_LOOP: i32 = 19; +pub const IPV6_V6ONLY: i32 = 27; +pub const IP_TTL: i32 = 2; +pub const IP_MULTICAST_TTL: i32 = 5; +pub const IP_MULTICAST_LOOP: i32 = 7; +pub const IP_ADD_MEMBERSHIP: i32 = 3; +pub const IP_DROP_MEMBERSHIP: i32 = 4; +pub const SHUT_RD: i32 = 0; +pub const SHUT_RDWR: i32 = 2; +pub const SHUT_WR: i32 = 1; +pub const SOCK_DGRAM: i32 = 2; +pub const SOCK_STREAM: i32 = 1; +pub const SOL_SOCKET: i32 = 4095; +pub const SO_BROADCAST: i32 = 32; +pub const SO_ERROR: i32 = 4103; +pub const SO_RCVTIMEO: i32 = 4102; +pub const SO_REUSEADDR: i32 = 4; +pub const SO_SNDTIMEO: i32 = 4101; +pub const SO_LINGER: i32 = 128; +pub const TCP_NODELAY: i32 = 1; +pub const MSG_PEEK: c_int = 1; +pub const FIONBIO: c_long = 0x8008667eu32 as c_long; +pub const EAI_NONAME: i32 = -2200; +pub const EAI_SERVICE: i32 = -2201; +pub const EAI_FAIL: i32 = -2202; +pub const EAI_MEMORY: i32 = -2203; +pub const EAI_FAMILY: i32 = -2204; + +pub type sa_family_t = u8; +pub type socklen_t = u32; +pub type in_addr_t = u32; +pub type in_port_t = u16; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct in_addr { + pub s_addr: in_addr_t, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct in6_addr { + pub s6_addr: [u8; 16], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct msghdr { + pub msg_name: *mut c_void, + pub msg_namelen: socklen_t, + pub msg_iov: *mut iovec, + pub msg_iovlen: c_int, + pub msg_control: *mut c_void, + pub msg_controllen: socklen_t, + pub msg_flags: c_int, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sockaddr { + pub sa_len: u8, + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14usize], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sockaddr_in { + pub sin_len: u8, + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [c_char; 8usize], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct sockaddr_in6 { + pub sin6_len: u8, + pub sin6_family: sa_family_t, + pub sin6_port: in_port_t, + pub sin6_flowinfo: u32, + pub sin6_addr: in6_addr, + pub sin6_scope_id: u32, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sockaddr_storage { + pub s2_len: u8, + pub ss_family: sa_family_t, + pub s2_data1: [c_char; 2usize], + pub s2_data2: [u32; 3usize], +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct addrinfo { + pub ai_flags: c_int, + pub ai_family: c_int, + pub ai_socktype: c_int, + pub ai_protocol: c_int, + pub ai_addrlen: socklen_t, + pub ai_addr: *mut sockaddr, + pub ai_canonname: *mut c_char, + pub ai_next: *mut addrinfo, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: usize, +} + +/// This value can be chosen by an application +pub const SOLID_NET_FD_SETSIZE: usize = 1; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct fd_set { + pub num_fds: usize, + pub fds: [c_int; SOLID_NET_FD_SETSIZE], +} + +extern "C" { + #[link_name = "SOLID_NET_StrError"] + pub fn strerror(errnum: c_int) -> *const c_char; + + pub fn SOLID_NET_GetLastError() -> c_int; + + #[link_name = "SOLID_NET_Accept"] + pub fn accept(s: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t) -> c_int; + + #[link_name = "SOLID_NET_Bind"] + pub fn bind(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int; + + #[link_name = "SOLID_NET_Connect"] + pub fn connect(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int; + + #[link_name = "SOLID_NET_Close"] + pub fn close(s: c_int) -> c_int; + + #[link_name = "SOLID_NET_GetPeerName"] + pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; + + #[link_name = "SOLID_NET_GetSockName"] + pub fn getsockname(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; + + #[link_name = "SOLID_NET_GetSockOpt"] + pub fn getsockopt( + s: c_int, + level: c_int, + optname: c_int, + optval: *mut c_void, + optlen: *mut socklen_t, + ) -> c_int; + + #[link_name = "SOLID_NET_SetSockOpt"] + pub fn setsockopt( + s: c_int, + level: c_int, + optname: c_int, + optval: *const c_void, + optlen: socklen_t, + ) -> c_int; + + #[link_name = "SOLID_NET_Ioctl"] + pub fn ioctl(s: c_int, cmd: c_long, argp: *mut c_void) -> c_int; + + #[link_name = "SOLID_NET_Listen"] + pub fn listen(s: c_int, backlog: c_int) -> c_int; + + #[link_name = "SOLID_NET_Recv"] + pub fn recv(s: c_int, mem: *mut c_void, len: size_t, flags: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_Read"] + pub fn read(s: c_int, mem: *mut c_void, len: size_t) -> ssize_t; + + #[link_name = "SOLID_NET_Readv"] + pub fn readv(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_RecvFrom"] + pub fn recvfrom( + s: c_int, + mem: *mut c_void, + len: size_t, + flags: c_int, + from: *mut sockaddr, + fromlen: *mut socklen_t, + ) -> ssize_t; + + #[link_name = "SOLID_NET_Send"] + pub fn send(s: c_int, mem: *const c_void, len: size_t, flags: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_SendMsg"] + pub fn sendmsg(s: c_int, message: *const msghdr, flags: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_SendTo"] + pub fn sendto( + s: c_int, + mem: *const c_void, + len: size_t, + flags: c_int, + to: *const sockaddr, + tolen: socklen_t, + ) -> ssize_t; + + #[link_name = "SOLID_NET_Shutdown"] + pub fn shutdown(s: c_int, how: c_int) -> c_int; + + #[link_name = "SOLID_NET_Socket"] + pub fn socket(domain: c_int, type_: c_int, protocol: c_int) -> c_int; + + #[link_name = "SOLID_NET_Write"] + pub fn write(s: c_int, mem: *const c_void, len: size_t) -> ssize_t; + + #[link_name = "SOLID_NET_Writev"] + pub fn writev(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t; + + #[link_name = "SOLID_NET_FreeAddrInfo"] + pub fn freeaddrinfo(ai: *mut addrinfo); + + #[link_name = "SOLID_NET_GetAddrInfo"] + pub fn getaddrinfo( + nodename: *const c_char, + servname: *const c_char, + hints: *const addrinfo, + res: *mut *mut addrinfo, + ) -> c_int; + + #[link_name = "SOLID_NET_Select"] + pub fn select( + maxfdp1: c_int, + readset: *mut fd_set, + writeset: *mut fd_set, + exceptset: *mut fd_set, + timeout: *mut timeval, + ) -> c_int; +} diff --git a/library/std/src/sys/solid/alloc.rs b/library/std/src/sys/solid/alloc.rs new file mode 100644 index 0000000000000..d013bd8761003 --- /dev/null +++ b/library/std/src/sys/solid/alloc.rs @@ -0,0 +1,32 @@ +use crate::{ + alloc::{GlobalAlloc, Layout, System}, + sys::common::alloc::{realloc_fallback, MIN_ALIGN}, +}; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + unsafe { libc::malloc(layout.size()) as *mut u8 } + } else { + unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 } + } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + unsafe { libc::free(ptr as *mut libc::c_void) } + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + unsafe { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + } else { + realloc_fallback(self, ptr, layout, new_size) + } + } + } +} diff --git a/library/std/src/sys/solid/env.rs b/library/std/src/sys/solid/env.rs new file mode 100644 index 0000000000000..6855c113b2893 --- /dev/null +++ b/library/std/src/sys/solid/env.rs @@ -0,0 +1,9 @@ +pub mod os { + pub const FAMILY: &str = "itron"; + pub const OS: &str = "solid"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} diff --git a/library/std/src/sys/solid/error.rs b/library/std/src/sys/solid/error.rs new file mode 100644 index 0000000000000..547b4f3a9840e --- /dev/null +++ b/library/std/src/sys/solid/error.rs @@ -0,0 +1,55 @@ +use super::{abi, itron, net}; +use crate::io::ErrorKind; + +pub use self::itron::error::{expect_success, ItronError as SolidError}; + +/// Describe the specified SOLID error code. Returns `None` if it's an +/// undefined error code. +/// +/// The SOLID error codes are a superset of μITRON error codes. +pub fn error_name(er: abi::ER) -> Option<&'static str> { + match er { + // Success + er if er >= 0 => None, + er if er < abi::sockets::SOLID_NET_ERR_BASE => net::error_name(er), + + abi::SOLID_ERR_NOTFOUND => Some("not found"), + abi::SOLID_ERR_NOTSUPPORTED => Some("not supported"), + abi::SOLID_ERR_EBADF => Some("bad flags"), + abi::SOLID_ERR_INVALIDCONTENT => Some("invalid content"), + abi::SOLID_ERR_NOTUSED => Some("not used"), + abi::SOLID_ERR_ALREADYUSED => Some("already used"), + abi::SOLID_ERR_OUTOFBOUND => Some("out of bounds"), + abi::SOLID_ERR_BADSEQUENCE => Some("bad sequence"), + abi::SOLID_ERR_UNKNOWNDEVICE => Some("unknown device"), + abi::SOLID_ERR_BUSY => Some("busy"), + abi::SOLID_ERR_TIMEOUT => Some("operation timed out"), + abi::SOLID_ERR_INVALIDACCESS => Some("invalid access"), + abi::SOLID_ERR_NOTREADY => Some("not ready"), + + _ => itron::error::error_name(er), + } +} + +pub fn decode_error_kind(er: abi::ER) -> ErrorKind { + match er { + // Success + er if er >= 0 => ErrorKind::Uncategorized, + er if er < abi::sockets::SOLID_NET_ERR_BASE => net::decode_error_kind(er), + + abi::SOLID_ERR_NOTFOUND => ErrorKind::NotFound, + abi::SOLID_ERR_NOTSUPPORTED => ErrorKind::Unsupported, + abi::SOLID_ERR_EBADF => ErrorKind::InvalidInput, + abi::SOLID_ERR_INVALIDCONTENT => ErrorKind::InvalidData, + // abi::SOLID_ERR_NOTUSED + // abi::SOLID_ERR_ALREADYUSED + abi::SOLID_ERR_OUTOFBOUND => ErrorKind::InvalidInput, + // abi::SOLID_ERR_BADSEQUENCE + abi::SOLID_ERR_UNKNOWNDEVICE => ErrorKind::NotFound, + // abi::SOLID_ERR_BUSY + abi::SOLID_ERR_TIMEOUT => ErrorKind::TimedOut, + // abi::SOLID_ERR_INVALIDACCESS + // abi::SOLID_ERR_NOTREADY + _ => itron::error::decode_error_kind(er), + } +} diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs new file mode 100644 index 0000000000000..abc60b56fbbe5 --- /dev/null +++ b/library/std/src/sys/solid/fs.rs @@ -0,0 +1,529 @@ +use super::{abi, error}; +use crate::{ + ffi::{CStr, CString, OsStr, OsString}, + fmt, + io::{self, IoSlice, IoSliceMut, SeekFrom}, + mem::MaybeUninit, + os::raw::{c_int, c_short}, + os::solid::ffi::OsStrExt, + path::{Path, PathBuf}, + sync::Arc, + sys::time::SystemTime, + sys::unsupported, +}; + +pub use crate::sys_common::fs::try_exists; + +/// A file descriptor. +#[derive(Clone, Copy)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +struct FileDesc { + fd: c_int, +} + +impl FileDesc { + #[inline] + fn new(fd: c_int) -> FileDesc { + assert_ne!(fd, -1i32); + // Safety: we just asserted that the value is in the valid range and + // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { FileDesc { fd } } + } + + #[inline] + fn raw(&self) -> c_int { + self.fd + } +} + +pub struct File { + fd: FileDesc, +} + +#[derive(Clone)] +pub struct FileAttr { + stat: abi::stat, +} + +// all DirEntry's will have a reference to this struct +struct InnerReadDir { + dirp: abi::S_DIR, + root: PathBuf, +} + +pub struct ReadDir { + inner: Arc, +} + +pub struct DirEntry { + entry: abi::dirent, + inner: Arc, +} + +#[derive(Clone, Debug)] +pub struct OpenOptions { + // generic + read: bool, + write: bool, + append: bool, + truncate: bool, + create: bool, + create_new: bool, + // system-specific + custom_flags: i32, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FilePermissions(c_short); + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub struct FileType(c_short); + +#[derive(Debug)] +pub struct DirBuilder {} + +impl FileAttr { + pub fn size(&self) -> u64 { + self.stat.st_size as u64 + } + + pub fn perm(&self) -> FilePermissions { + FilePermissions(self.stat.st_mode) + } + + pub fn file_type(&self) -> FileType { + FileType(self.stat.st_mode) + } + + pub fn modified(&self) -> io::Result { + Ok(SystemTime::from_time_t(self.stat.st_mtime)) + } + + pub fn accessed(&self) -> io::Result { + Ok(SystemTime::from_time_t(self.stat.st_atime)) + } + + pub fn created(&self) -> io::Result { + Ok(SystemTime::from_time_t(self.stat.st_ctime)) + } +} + +impl FilePermissions { + pub fn readonly(&self) -> bool { + (self.0 & abi::S_IWRITE) == 0 + } + + pub fn set_readonly(&mut self, readonly: bool) { + if readonly { + self.0 &= !abi::S_IWRITE; + } else { + self.0 |= abi::S_IWRITE; + } + } +} + +impl FileType { + pub fn is_dir(&self) -> bool { + self.is(abi::S_IFDIR) + } + pub fn is_file(&self) -> bool { + self.is(abi::S_IFREG) + } + pub fn is_symlink(&self) -> bool { + false + } + + pub fn is(&self, mode: c_short) -> bool { + self.0 & abi::S_IFMT == mode + } +} + +pub fn readdir(p: &Path) -> io::Result { + unsafe { + let mut dir = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_OpenDir( + cstr(p)?.as_ptr(), + dir.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + let inner = Arc::new(InnerReadDir { dirp: dir.assume_init(), root: p.to_owned() }); + Ok(ReadDir { inner }) + } +} + +impl fmt::Debug for ReadDir { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. + // Thus the result will be e g 'ReadDir("/home")' + fmt::Debug::fmt(&*self.inner.root, f) + } +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option> { + unsafe { + let mut out_dirent = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_ReadDir( + self.inner.dirp, + out_dirent.as_mut_ptr(), + )) + .ok()?; + Some(Ok(DirEntry { entry: out_dirent.assume_init(), inner: Arc::clone(&self.inner) })) + } + } +} + +impl Drop for InnerReadDir { + fn drop(&mut self) { + unsafe { abi::SOLID_FS_CloseDir(self.dirp) }; + } +} + +impl DirEntry { + pub fn path(&self) -> PathBuf { + self.inner.root.join(OsStr::from_bytes( + unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes(), + )) + } + + pub fn file_name(&self) -> OsString { + OsStr::from_bytes(unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes()) + .to_os_string() + } + + pub fn metadata(&self) -> io::Result { + lstat(&self.path()) + } + + pub fn file_type(&self) -> io::Result { + match self.entry.d_type { + abi::DT_CHR => Ok(FileType(abi::S_IFCHR)), + abi::DT_FIFO => Ok(FileType(abi::S_IFIFO)), + abi::DT_REG => Ok(FileType(abi::S_IFREG)), + abi::DT_DIR => Ok(FileType(abi::S_IFDIR)), + abi::DT_BLK => Ok(FileType(abi::S_IFBLK)), + _ => lstat(&self.path()).map(|m| m.file_type()), + } + } +} + +impl OpenOptions { + pub fn new() -> OpenOptions { + OpenOptions { + // generic + read: false, + write: false, + append: false, + truncate: false, + create: false, + create_new: false, + // system-specific + custom_flags: 0, + } + } + + pub fn read(&mut self, read: bool) { + self.read = read; + } + pub fn write(&mut self, write: bool) { + self.write = write; + } + pub fn append(&mut self, append: bool) { + self.append = append; + } + pub fn truncate(&mut self, truncate: bool) { + self.truncate = truncate; + } + pub fn create(&mut self, create: bool) { + self.create = create; + } + pub fn create_new(&mut self, create_new: bool) { + self.create_new = create_new; + } + + pub fn custom_flags(&mut self, flags: i32) { + self.custom_flags = flags; + } + pub fn mode(&mut self, _mode: u32) {} + + fn get_access_mode(&self) -> io::Result { + match (self.read, self.write, self.append) { + (true, false, false) => Ok(abi::O_RDONLY), + (false, true, false) => Ok(abi::O_WRONLY), + (true, true, false) => Ok(abi::O_RDWR), + (false, _, true) => Ok(abi::O_WRONLY | abi::O_APPEND), + (true, _, true) => Ok(abi::O_RDWR | abi::O_APPEND), + (false, false, false) => Err(io::Error::from_raw_os_error(libc::EINVAL)), + } + } + + fn get_creation_mode(&self) -> io::Result { + match (self.write, self.append) { + (true, false) => {} + (false, false) => { + if self.truncate || self.create || self.create_new { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + } + } + (_, true) => { + if self.truncate && !self.create_new { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + } + } + } + + Ok(match (self.create, self.truncate, self.create_new) { + (false, false, false) => 0, + (true, false, false) => abi::O_CREAT, + (false, true, false) => abi::O_TRUNC, + (true, true, false) => abi::O_CREAT | abi::O_TRUNC, + (_, _, true) => abi::O_CREAT | abi::O_EXCL, + }) + } +} + +fn cstr(path: &Path) -> io::Result { + Ok(CString::new(path.as_os_str().as_bytes())?) +} + +impl File { + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { + let flags = opts.get_access_mode()? + | opts.get_creation_mode()? + | (opts.custom_flags as c_int & !abi::O_ACCMODE); + unsafe { + let mut fd = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Open( + fd.as_mut_ptr(), + cstr(path)?.as_ptr(), + flags, + )) + .map_err(|e| e.as_io_error())?; + Ok(File { fd: FileDesc::new(fd.assume_init()) }) + } + } + + pub fn file_attr(&self) -> io::Result { + unsupported() + } + + pub fn fsync(&self) -> io::Result<()> { + self.flush() + } + + pub fn datasync(&self) -> io::Result<()> { + self.flush() + } + + pub fn truncate(&self, _size: u64) -> io::Result<()> { + unsupported() + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + unsafe { + let mut out_num_bytes = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Read( + self.fd.raw(), + buf.as_mut_ptr(), + buf.len(), + out_num_bytes.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(out_num_bytes.assume_init()) + } + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + + pub fn is_read_vectored(&self) -> bool { + false + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + unsafe { + let mut out_num_bytes = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Write( + self.fd.raw(), + buf.as_ptr(), + buf.len(), + out_num_bytes.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(out_num_bytes.assume_init()) + } + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) + } + + pub fn is_write_vectored(&self) -> bool { + false + } + + pub fn flush(&self) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Sync(self.fd.raw()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } + + pub fn seek(&self, pos: SeekFrom) -> io::Result { + let (whence, pos) = match pos { + // Casting to `i64` is fine, too large values will end up as + // negative which will cause an error in `SOLID_FS_Lseek`. + SeekFrom::Start(off) => (abi::SEEK_SET, off as i64), + SeekFrom::End(off) => (abi::SEEK_END, off), + SeekFrom::Current(off) => (abi::SEEK_CUR, off), + }; + error::SolidError::err_if_negative(unsafe { + abi::SOLID_FS_Lseek(self.fd.raw(), pos, whence) + }) + .map_err(|e| e.as_io_error())?; + + // Get the new offset + unsafe { + let mut out_offset = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Ftell( + self.fd.raw(), + out_offset.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(out_offset.assume_init() as u64) + } + } + + pub fn duplicate(&self) -> io::Result { + unsupported() + } + + pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { + unsupported() + } +} + +impl Drop for File { + fn drop(&mut self) { + unsafe { abi::SOLID_FS_Close(self.fd.raw()) }; + } +} + +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder {} + } + + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Mkdir(cstr(p)?.as_ptr()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } +} + +impl fmt::Debug for File { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("File").field("fd", &self.fd.raw()).finish() + } +} + +pub fn unlink(p: &Path) -> io::Result<()> { + if stat(p)?.file_type().is_dir() { + Err(io::Error::new_const(io::ErrorKind::IsADirectory, &"is a directory")) + } else { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } +} + +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { + abi::SOLID_FS_Rename(cstr(old)?.as_ptr(), cstr(new)?.as_ptr()) + }) + .map_err(|e| e.as_io_error())?; + Ok(()) +} + +pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { + error::SolidError::err_if_negative(unsafe { + abi::SOLID_FS_Chmod(cstr(p)?.as_ptr(), perm.0.into()) + }) + .map_err(|e| e.as_io_error())?; + Ok(()) +} + +pub fn rmdir(p: &Path) -> io::Result<()> { + if stat(p)?.file_type().is_dir() { + error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) }) + .map_err(|e| e.as_io_error())?; + Ok(()) + } else { + Err(io::Error::new_const(io::ErrorKind::NotADirectory, &"not a directory")) + } +} + +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + for child in readdir(path)? { + let child = child?; + let child_type = child.file_type()?; + if child_type.is_dir() { + remove_dir_all(&child.path())?; + } else { + unlink(&child.path())?; + } + } + rmdir(path) +} + +pub fn readlink(p: &Path) -> io::Result { + // This target doesn't support symlinks + stat(p)?; + Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"not a symbolic link")) +} + +pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> { + // This target doesn't support symlinks + unsupported() +} + +pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + // This target doesn't support symlinks + unsupported() +} + +pub fn stat(p: &Path) -> io::Result { + // This target doesn't support symlinks + lstat(p) +} + +pub fn lstat(p: &Path) -> io::Result { + unsafe { + let mut out_stat = MaybeUninit::uninit(); + error::SolidError::err_if_negative(abi::SOLID_FS_Stat( + cstr(p)?.as_ptr(), + out_stat.as_mut_ptr(), + )) + .map_err(|e| e.as_io_error())?; + Ok(FileAttr { stat: out_stat.assume_init() }) + } +} + +pub fn canonicalize(_p: &Path) -> io::Result { + unsupported() +} + +pub fn copy(from: &Path, to: &Path) -> io::Result { + use crate::fs::File; + + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + + io::copy(&mut reader, &mut writer) +} diff --git a/library/std/src/sys/solid/io.rs b/library/std/src/sys/solid/io.rs new file mode 100644 index 0000000000000..9eb17a10daa28 --- /dev/null +++ b/library/std/src/sys/solid/io.rs @@ -0,0 +1,77 @@ +use crate::marker::PhantomData; +use crate::slice; + +use super::abi::sockets::iovec; +use libc::c_void; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct IoSlice<'a> { + vec: iovec, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + IoSlice { + vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSlice beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} + +#[repr(transparent)] +pub struct IoSliceMut<'a> { + vec: iovec, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { + vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, + _p: PhantomData, + } + } + + #[inline] + pub fn advance(&mut self, n: usize) { + if self.vec.iov_len < n { + panic!("advancing IoSliceMut beyond its length"); + } + + unsafe { + self.vec.iov_len -= n; + self.vec.iov_base = self.vec.iov_base.add(n); + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } + } +} diff --git a/library/std/src/sys/solid/memchr.rs b/library/std/src/sys/solid/memchr.rs new file mode 100644 index 0000000000000..452b7a3de1b33 --- /dev/null +++ b/library/std/src/sys/solid/memchr.rs @@ -0,0 +1,21 @@ +pub fn memchr(needle: u8, haystack: &[u8]) -> Option { + let p = unsafe { + libc::memchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len(), + ) + }; + if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) } +} + +pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { + let p = unsafe { + libc::memrchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len(), + ) + }; + if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) } +} diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs new file mode 100644 index 0000000000000..211b8d7de31f5 --- /dev/null +++ b/library/std/src/sys/solid/mod.rs @@ -0,0 +1,96 @@ +#![allow(dead_code)] +#![allow(missing_docs, nonstandard_style)] +#![deny(unsafe_op_in_unsafe_fn)] + +mod abi; + +#[path = "../itron"] +mod itron { + pub(super) mod abi; + pub mod condvar; + pub(super) mod error; + pub mod mutex; + pub(super) mod spin; + pub(super) mod task; + pub mod thread; + pub(super) mod time; + use super::unsupported; +} + +pub mod alloc; +#[path = "../unsupported/args.rs"] +pub mod args; +#[path = "../unix/cmath.rs"] +pub mod cmath; +pub mod env; +// `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as +// `crate::sys::error` +pub(crate) mod error; +pub mod fs; +pub mod io; +pub mod net; +pub mod os; +#[path = "../unix/os_str.rs"] +pub mod os_str; +pub mod path; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +#[path = "../unsupported/process.rs"] +pub mod process; +pub mod rwlock; +pub mod stdio; +pub use self::itron::{condvar, mutex, thread}; +pub mod memchr; +pub mod thread_local_dtor; +pub mod thread_local_key; +pub mod time; + +// SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. +pub unsafe fn init(_argc: isize, _argv: *const *const u8) {} + +// SAFETY: must be called only once during runtime cleanup. +pub unsafe fn cleanup() {} + +pub fn unsupported() -> crate::io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> crate::io::Error { + crate::io::Error::new_const( + crate::io::ErrorKind::Unsupported, + &"operation not supported on this platform", + ) +} + +pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind { + error::decode_error_kind(code) +} + +#[inline(always)] +pub fn abort_internal() -> ! { + loop { + abi::breakpoint_abort(); + } +} + +// This function is needed by the panic runtime. The symbol is named in +// pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +// NB. used by both libunwind and libpanic_abort +pub extern "C" fn __rust_abort() { + abort_internal(); +} + +pub fn hashmap_random_keys() -> (u64, u64) { + unsafe { + let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit(); + let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16); + assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {}", result); + let [x1, x2] = out.assume_init(); + (x1, x2) + } +} + +pub use libc::strlen; diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs new file mode 100644 index 0000000000000..63ba6341c796c --- /dev/null +++ b/library/std/src/sys/solid/net.rs @@ -0,0 +1,469 @@ +use super::abi; +use crate::{ + cmp, + ffi::CStr, + io::{self, ErrorKind, IoSlice, IoSliceMut}, + mem, + net::{Shutdown, SocketAddr}, + ptr, str, + sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}, + sys_common::{AsInner, FromInner, IntoInner}, + time::Duration, +}; + +use self::netc::{sockaddr, socklen_t, MSG_PEEK}; +use libc::{c_int, c_void, size_t}; + +pub mod netc { + pub use super::super::abi::sockets::*; +} + +pub type wrlen_t = size_t; + +const READ_LIMIT: usize = libc::ssize_t::MAX as usize; + +const fn max_iov() -> usize { + // Judging by the source code, it's unlimited, but specify a lower + // value just in case. + 1024 +} + +/// A file descriptor. +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] +struct FileDesc { + fd: c_int, +} + +impl FileDesc { + #[inline] + fn new(fd: c_int) -> FileDesc { + assert_ne!(fd, -1i32); + // Safety: we just asserted that the value is in the valid range and + // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { FileDesc { fd } } + } + + #[inline] + fn raw(&self) -> c_int { + self.fd + } + + /// Extracts the actual file descriptor without closing it. + #[inline] + fn into_raw(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + fn read(&self, buf: &mut [u8]) -> io::Result { + let ret = cvt(unsafe { + netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) + })?; + Ok(ret as usize) + } + + fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let ret = cvt(unsafe { + netc::readv( + self.fd, + bufs.as_ptr() as *const netc::iovec, + cmp::min(bufs.len(), max_iov()) as c_int, + ) + })?; + Ok(ret as usize) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + true + } + + fn write(&self, buf: &[u8]) -> io::Result { + let ret = cvt(unsafe { + netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) + })?; + Ok(ret as usize) + } + + fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let ret = cvt(unsafe { + netc::writev( + self.fd, + bufs.as_ptr() as *const netc::iovec, + cmp::min(bufs.len(), max_iov()) as c_int, + ) + })?; + Ok(ret as usize) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + fn duplicate(&self) -> io::Result { + super::unsupported() + } +} + +impl AsInner for FileDesc { + fn as_inner(&self) -> &c_int { + &self.fd + } +} + +impl Drop for FileDesc { + fn drop(&mut self) { + unsafe { netc::close(self.fd) }; + } +} + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +pub fn cvt(t: T) -> io::Result { + if t.is_minus_one() { Err(last_error()) } else { Ok(t) } +} + +/// A variant of `cvt` for `getaddrinfo` which return 0 for a success. +pub fn cvt_gai(err: c_int) -> io::Result<()> { + if err == 0 { + Ok(()) + } else { + let msg: &dyn crate::fmt::Display = match err { + netc::EAI_NONAME => &"name or service not known", + netc::EAI_SERVICE => &"service not supported", + netc::EAI_FAIL => &"non-recoverable failure in name resolution", + netc::EAI_MEMORY => &"memory allocation failure", + netc::EAI_FAMILY => &"family not supported", + _ => &err, + }; + Err(io::Error::new( + io::ErrorKind::Uncategorized, + &format!("failed to lookup address information: {}", msg)[..], + )) + } +} + +/// Just to provide the same interface as sys/unix/net.rs +pub fn cvt_r(mut f: F) -> io::Result +where + T: IsMinusOne, + F: FnMut() -> T, +{ + cvt(f()) +} + +/// Returns the last error from the network subsystem. +fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { netc::SOLID_NET_GetLastError() }) +} + +pub(super) fn error_name(er: abi::ER) -> Option<&'static str> { + unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok() +} + +pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind { + let errno = netc::SOLID_NET_ERR_BASE - er; + match errno as libc::c_int { + libc::ECONNREFUSED => ErrorKind::ConnectionRefused, + libc::ECONNRESET => ErrorKind::ConnectionReset, + libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, + libc::EPIPE => ErrorKind::BrokenPipe, + libc::ENOTCONN => ErrorKind::NotConnected, + libc::ECONNABORTED => ErrorKind::ConnectionAborted, + libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, + libc::EADDRINUSE => ErrorKind::AddrInUse, + libc::ENOENT => ErrorKind::NotFound, + libc::EINTR => ErrorKind::Interrupted, + libc::EINVAL => ErrorKind::InvalidInput, + libc::ETIMEDOUT => ErrorKind::TimedOut, + libc::EEXIST => ErrorKind::AlreadyExists, + libc::ENOSYS => ErrorKind::Unsupported, + libc::ENOMEM => ErrorKind::OutOfMemory, + libc::EAGAIN => ErrorKind::WouldBlock, + + _ => ErrorKind::Uncategorized, + } +} + +pub fn init() {} + +pub struct Socket(FileDesc); + +impl Socket { + pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { + let fam = match *addr { + SocketAddr::V4(..) => netc::AF_INET, + SocketAddr::V6(..) => netc::AF_INET6, + }; + Socket::new_raw(fam, ty) + } + + pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { + unsafe { + let fd = cvt(netc::socket(fam, ty, 0))?; + let fd = FileDesc::new(fd); + let socket = Socket(fd); + + Ok(socket) + } + } + + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { + self.set_nonblocking(true)?; + let r = unsafe { + let (addrp, len) = addr.into_inner(); + cvt(netc::connect(self.0.raw(), addrp, len)) + }; + self.set_nonblocking(false)?; + + match r { + Ok(_) => return Ok(()), + // there's no ErrorKind for EINPROGRESS + Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {} + Err(e) => return Err(e), + } + + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"cannot set a 0 duration timeout", + )); + } + + let mut timeout = + netc::timeval { tv_sec: timeout.as_secs() as _, tv_usec: timeout.subsec_micros() as _ }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + + let fds = netc::fd_set { num_fds: 1, fds: [self.0.raw()] }; + + let mut writefds = fds; + let mut errorfds = fds; + + let n = unsafe { + cvt(netc::select( + self.0.raw() + 1, + ptr::null_mut(), + &mut writefds, + &mut errorfds, + &mut timeout, + ))? + }; + + match n { + 0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")), + _ => { + let can_write = writefds.num_fds != 0; + if !can_write { + if let Some(e) = self.take_error()? { + return Err(e); + } + } + Ok(()) + } + } + } + + pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result { + let fd = cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) })?; + let fd = FileDesc::new(fd); + Ok(Socket(fd)) + } + + pub fn duplicate(&self) -> io::Result { + self.0.duplicate().map(Socket) + } + + fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { + let ret = cvt(unsafe { + netc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + })?; + Ok(ret as usize) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.recv_with_flags(buf, 0) + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.recv_with_flags(buf, MSG_PEEK) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + + fn recv_from_with_flags( + &self, + buf: &mut [u8], + flags: c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; + + let n = cvt(unsafe { + netc::recvfrom( + self.0.raw(), + buf.as_mut_ptr() as *mut c_void, + buf.len(), + flags, + &mut storage as *mut _ as *mut _, + &mut addrlen, + ) + })?; + Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, 0) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, MSG_PEEK) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + pub fn set_timeout(&self, dur: Option, kind: c_int) -> io::Result<()> { + let timeout = match dur { + Some(dur) => { + if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { + return Err(io::Error::new_const( + io::ErrorKind::InvalidInput, + &"cannot set a 0 duration timeout", + )); + } + + let secs = if dur.as_secs() > netc::c_long::MAX as u64 { + netc::c_long::MAX + } else { + dur.as_secs() as netc::c_long + }; + let mut timeout = netc::timeval { tv_sec: secs, tv_usec: dur.subsec_micros() as _ }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => netc::timeval { tv_sec: 0, tv_usec: 0 }, + }; + setsockopt(self, netc::SOL_SOCKET, kind, timeout) + } + + pub fn timeout(&self, kind: c_int) -> io::Result> { + let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + if raw.tv_sec == 0 && raw.tv_usec == 0 { + Ok(None) + } else { + let sec = raw.tv_sec as u64; + let nsec = (raw.tv_usec as u32) * 1000; + Ok(Some(Duration::new(sec, nsec))) + } + } + + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + let how = match how { + Shutdown::Write => netc::SHUT_WR, + Shutdown::Read => netc::SHUT_RD, + Shutdown::Both => netc::SHUT_RDWR, + }; + cvt(unsafe { netc::shutdown(self.0.raw(), how) })?; + Ok(()) + } + + pub fn set_linger(&self, linger: Option) -> io::Result<()> { + let linger = netc::linger { + l_onoff: linger.is_some() as netc::c_int, + l_linger: linger.unwrap_or_default().as_secs() as netc::c_int, + }; + + setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) + } + + pub fn linger(&self) -> io::Result> { + let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?; + + Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) + } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) + } + + pub fn nodelay(&self) -> io::Result { + let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + Ok(raw != 0) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_int; + cvt(unsafe { + netc::ioctl(*self.as_inner(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _) + }) + .map(drop) + } + + pub fn take_error(&self) -> io::Result> { + let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?; + if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } + } + + // This method is used by sys_common code to abstract over targets. + pub fn as_raw(&self) -> c_int { + *self.as_inner() + } +} + +impl AsInner for Socket { + fn as_inner(&self) -> &c_int { + self.0.as_inner() + } +} + +impl FromInner for Socket { + fn from_inner(fd: c_int) -> Socket { + Socket(FileDesc::new(fd)) + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> c_int { + self.0.into_raw() + } +} diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs new file mode 100644 index 0000000000000..82542d81e6709 --- /dev/null +++ b/library/std/src/sys/solid/os.rs @@ -0,0 +1,200 @@ +use super::unsupported; +use crate::error::Error as StdError; +use crate::ffi::{CStr, CString, OsStr, OsString}; +use crate::fmt; +use crate::io; +use crate::os::{ + raw::{c_char, c_int}, + solid::ffi::{OsStrExt, OsStringExt}, +}; +use crate::path::{self, PathBuf}; +use crate::sys_common::rwlock::StaticRWLock; +use crate::vec; + +use super::{abi, error, itron, memchr}; + +// `solid` directly maps `errno`s to μITRON error codes. +impl itron::error::ItronError { + #[inline] + pub(crate) fn as_io_error(self) -> crate::io::Error { + crate::io::Error::from_raw_os_error(self.as_raw()) + } +} + +pub fn errno() -> i32 { + 0 +} + +pub fn error_string(errno: i32) -> String { + if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{}", errno) } +} + +pub fn getcwd() -> io::Result { + unsupported() +} + +pub fn chdir(_: &path::Path) -> io::Result<()> { + unsupported() +} + +pub struct SplitPaths<'a>(&'a !); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option { + *self.0 + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(_paths: I) -> Result +where + I: Iterator, + T: AsRef, +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "not supported on this platform yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + #[allow(deprecated)] + fn description(&self) -> &str { + "not supported on this platform yet" + } +} + +pub fn current_exe() -> io::Result { + unsupported() +} + +static ENV_LOCK: StaticRWLock = StaticRWLock::new(); + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env() -> Env { + extern "C" { + static mut environ: *const *const c_char; + } + + unsafe { + let _guard = ENV_LOCK.read(); + let mut result = Vec::new(); + if !environ.is_null() { + while !(*environ).is_null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.add(1); + } + } + return Env { iter: result.into_iter() }; + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub fn getenv(k: &OsStr) -> Option { + // environment variables with a nul byte can't be set, so their value is + // always None as well + let k = CString::new(k.as_bytes()).ok()?; + unsafe { + let _guard = ENV_LOCK.read(); + let s = libc::getenv(k.as_ptr()) as *const libc::c_char; + if s.is_null() { + None + } else { + Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) + } + } +} + +pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let k = CString::new(k.as_bytes())?; + let v = CString::new(v.as_bytes())?; + + unsafe { + let _guard = ENV_LOCK.write(); + cvt_env(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) + } +} + +pub fn unsetenv(n: &OsStr) -> io::Result<()> { + let nbuf = CString::new(n.as_bytes())?; + + unsafe { + let _guard = ENV_LOCK.write(); + cvt_env(libc::unsetenv(nbuf.as_ptr())).map(drop) + } +} + +/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this +/// function just returns a generic error. +fn cvt_env(t: c_int) -> io::Result { + if t == -1 { + Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"failure")) + } else { + Ok(t) + } +} + +pub fn temp_dir() -> PathBuf { + panic!("no standard temporary directory on this platform") +} + +pub fn home_dir() -> Option { + None +} + +pub fn exit(_code: i32) -> ! { + let tid = itron::task::try_current_task_id().unwrap_or(0); + loop { + abi::breakpoint_program_exited(tid as usize); + } +} + +pub fn getpid() -> u32 { + panic!("no pids on this platform") +} diff --git a/library/std/src/sys/solid/path.rs b/library/std/src/sys/solid/path.rs new file mode 100644 index 0000000000000..4a14332d4999c --- /dev/null +++ b/library/std/src/sys/solid/path.rs @@ -0,0 +1,19 @@ +use crate::ffi::OsStr; +use crate::path::Prefix; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'\\' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'\\' +} + +pub fn parse_prefix(_: &OsStr) -> Option> { + None +} + +pub const MAIN_SEP_STR: &str = "\\"; +pub const MAIN_SEP: char = '\\'; diff --git a/library/std/src/sys/solid/rwlock.rs b/library/std/src/sys/solid/rwlock.rs new file mode 100644 index 0000000000000..4e39ac2a93071 --- /dev/null +++ b/library/std/src/sys/solid/rwlock.rs @@ -0,0 +1,92 @@ +//! A readers-writer lock implementation backed by the SOLID kernel extension. +use super::{ + abi, + itron::{ + error::{expect_success, expect_success_aborting, fail, ItronError}, + spin::SpinIdOnceCell, + }, +}; + +pub struct RWLock { + /// The ID of the underlying mutex object + rwl: SpinIdOnceCell<()>, +} + +pub type MovableRWLock = RWLock; + +// Safety: `num_readers` is protected by `mtx_num_readers` +unsafe impl Send for RWLock {} +unsafe impl Sync for RWLock {} + +fn new_rwl() -> Result { + ItronError::err_if_negative(unsafe { abi::rwl_acre_rwl() }) +} + +impl RWLock { + pub const fn new() -> RWLock { + RWLock { rwl: SpinIdOnceCell::new() } + } + + /// Get the inner mutex's ID, which is lazily created. + fn raw(&self) -> abi::ID { + match self.rwl.get_or_try_init(|| new_rwl().map(|id| (id, ()))) { + Ok((id, ())) => id, + Err(e) => fail(e, &"rwl_acre_rwl"), + } + } + + #[inline] + pub unsafe fn read(&self) { + let rwl = self.raw(); + expect_success(unsafe { abi::rwl_loc_rdl(rwl) }, &"rwl_loc_rdl"); + } + + #[inline] + pub unsafe fn try_read(&self) -> bool { + let rwl = self.raw(); + match unsafe { abi::rwl_ploc_rdl(rwl) } { + abi::E_TMOUT => false, + er => { + expect_success(er, &"rwl_ploc_rdl"); + true + } + } + } + + #[inline] + pub unsafe fn write(&self) { + let rwl = self.raw(); + expect_success(unsafe { abi::rwl_loc_wrl(rwl) }, &"rwl_loc_wrl"); + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + let rwl = self.raw(); + match unsafe { abi::rwl_ploc_wrl(rwl) } { + abi::E_TMOUT => false, + er => { + expect_success(er, &"rwl_ploc_wrl"); + true + } + } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + let rwl = self.raw(); + expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); + } + + #[inline] + pub unsafe fn write_unlock(&self) { + let rwl = self.raw(); + expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl"); + } + + #[inline] + pub unsafe fn destroy(&self) { + if let Some(rwl) = self.rwl.get().map(|x| x.0) { + expect_success_aborting(unsafe { abi::rwl_del_rwl(rwl) }, &"rwl_del_rwl"); + } + } +} diff --git a/library/std/src/sys/solid/stdio.rs b/library/std/src/sys/solid/stdio.rs new file mode 100644 index 0000000000000..50f0176967b2d --- /dev/null +++ b/library/std/src/sys/solid/stdio.rs @@ -0,0 +1,80 @@ +use super::abi; +use crate::io; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; +struct PanicOutput; + +impl Stdin { + pub const fn new() -> Stdin { + Stdin + } +} + +impl io::Read for Stdin { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + Ok(0) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub const fn new() -> Stderr { + Stderr + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl PanicOutput { + pub const fn new() -> PanicOutput { + PanicOutput + } +} + +impl io::Write for PanicOutput { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) }; + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +pub fn panic_output() -> Option { + Some(PanicOutput::new()) +} diff --git a/library/std/src/sys/solid/thread_local_dtor.rs b/library/std/src/sys/solid/thread_local_dtor.rs new file mode 100644 index 0000000000000..9735645705776 --- /dev/null +++ b/library/std/src/sys/solid/thread_local_dtor.rs @@ -0,0 +1,50 @@ +#![cfg(target_thread_local)] +#![unstable(feature = "thread_local_internals", issue = "none")] + +// Simplify dtor registration by using a list of destructors. + +use super::{abi, itron::task}; +use crate::cell::Cell; +use crate::ptr; + +#[thread_local] +static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut()); + +type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; + +pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { + if DTORS.get().is_null() { + let tid = task::current_task_id_aborting(); + let v: Box = box Vec::new(); + DTORS.set(Box::into_raw(v)); + + // Register `tls_dtor` to make sure the TLS destructors are called + // for tasks created by other means than `std::thread` + unsafe { abi::SOLID_TLS_AddDestructor(tid as i32, tls_dtor) }; + } + + let list: &mut List = unsafe { &mut *DTORS.get() }; + list.push((t, dtor)); +} + +pub unsafe fn run_dtors() { + let ptr = DTORS.get(); + if !ptr.is_null() { + // Swap the destructor list, call all registered destructors, + // and repeat this until the list becomes permanently empty. + while let Some(list) = Some(crate::mem::replace(unsafe { &mut *ptr }, Vec::new())) + .filter(|list| !list.is_empty()) + { + for (ptr, dtor) in list.into_iter() { + unsafe { dtor(ptr) }; + } + } + + // Drop the destructor list + unsafe { Box::from_raw(DTORS.replace(ptr::null_mut())) }; + } +} + +unsafe extern "C" fn tls_dtor(_unused: *mut u8) { + unsafe { run_dtors() }; +} diff --git a/library/std/src/sys/solid/thread_local_key.rs b/library/std/src/sys/solid/thread_local_key.rs new file mode 100644 index 0000000000000..b17521f701daf --- /dev/null +++ b/library/std/src/sys/solid/thread_local_key.rs @@ -0,0 +1,26 @@ +pub type Key = usize; + +#[inline] +pub unsafe fn create(_dtor: Option) -> Key { + panic!("should not be used on the solid target"); +} + +#[inline] +pub unsafe fn set(_key: Key, _value: *mut u8) { + panic!("should not be used on the solid target"); +} + +#[inline] +pub unsafe fn get(_key: Key) -> *mut u8 { + panic!("should not be used on the solid target"); +} + +#[inline] +pub unsafe fn destroy(_key: Key) { + panic!("should not be used on the solid target"); +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + panic!("should not be used on the solid target"); +} diff --git a/library/std/src/sys/solid/time.rs b/library/std/src/sys/solid/time.rs new file mode 100644 index 0000000000000..c67a736a9032c --- /dev/null +++ b/library/std/src/sys/solid/time.rs @@ -0,0 +1,56 @@ +use super::{abi, error::expect_success}; +use crate::{convert::TryInto, mem::MaybeUninit, time::Duration}; + +pub use super::itron::time::Instant; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub struct SystemTime(abi::time_t); + +pub const UNIX_EPOCH: SystemTime = SystemTime(0); + +impl SystemTime { + pub fn now() -> SystemTime { + let rtc = unsafe { + let mut out = MaybeUninit::zeroed(); + expect_success(abi::SOLID_RTC_ReadTime(out.as_mut_ptr()), &"SOLID_RTC_ReadTime"); + out.assume_init() + }; + let t = unsafe { + libc::mktime(&mut libc::tm { + tm_sec: rtc.tm_sec, + tm_min: rtc.tm_min, + tm_hour: rtc.tm_hour, + tm_mday: rtc.tm_mday, + tm_mon: rtc.tm_mon, + tm_year: rtc.tm_year, + tm_wday: rtc.tm_wday, + tm_yday: 0, + tm_isdst: 0, + tm_gmtoff: 0, + tm_zone: crate::ptr::null_mut(), + }) + }; + assert_ne!(t, -1, "mktime failed"); + SystemTime(t) + } + + pub(super) fn from_time_t(t: abi::time_t) -> Self { + Self(t) + } + + pub fn sub_time(&self, other: &SystemTime) -> Result { + if self.0 >= other.0 { + Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64))) + } else { + Err(Duration::from_secs((other.0 as u64).wrapping_sub(self.0 as u64))) + } + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_add(other.as_secs().try_into().ok()?)?)) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + Some(SystemTime(self.0.checked_sub(other.as_secs().try_into().ok()?)?)) + } +} diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index f5424e3d28214..1c37f4ee4981e 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -120,7 +120,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { unsafe fn reset_sigpipe() { #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); + rtassert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } } diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 1d5ffb073211b..87893d269120b 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -380,20 +380,24 @@ pub fn current_exe() -> io::Result { #[cfg(any(target_os = "solaris", target_os = "illumos"))] pub fn current_exe() -> io::Result { - extern "C" { - fn getexecname() -> *const c_char; - } - unsafe { - let path = getexecname(); - if path.is_null() { - Err(io::Error::last_os_error()) - } else { - let filename = CStr::from_ptr(path).to_bytes(); - let path = PathBuf::from(::from_bytes(filename)); + if let Ok(path) = crate::fs::read_link("/proc/self/path/a.out") { + Ok(path) + } else { + extern "C" { + fn getexecname() -> *const c_char; + } + unsafe { + let path = getexecname(); + if path.is_null() { + Err(io::Error::last_os_error()) + } else { + let filename = CStr::from_ptr(path).to_bytes(); + let path = PathBuf::from(::from_bytes(filename)); - // Prepend a current working directory to the path if - // it doesn't contain an absolute pathname. - if filename[0] == b'/' { Ok(path) } else { getcwd().map(|cwd| cwd.join(path)) } + // Prepend a current working directory to the path if + // it doesn't contain an absolute pathname. + if filename[0] == b'/' { Ok(path) } else { getcwd().map(|cwd| cwd.join(path)) } + } } } } diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 7b261a302c33f..7ac2f9d8af75a 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -457,9 +457,15 @@ impl fmt::Debug for Command { } } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy)] pub struct ExitCode(u8); +impl fmt::Debug for ExitCode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("unix_exit_status").field(&self.0).finish() + } +} + impl ExitCode { pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 12edf04a4e2e9..99013efb495d0 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -333,9 +333,19 @@ impl Command { let mut set = MaybeUninit::::uninit(); cvt(sigemptyset(set.as_mut_ptr()))?; cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), ptr::null_mut()))?; - let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); - if ret == libc::SIG_ERR { - return Err(io::Error::last_os_error()); + + #[cfg(target_os = "android")] // see issue #88585 + { + let mut action: libc::sigaction = mem::zeroed(); + action.sa_sigaction = libc::SIG_DFL; + cvt(libc::sigaction(libc::SIGPIPE, &action, ptr::null_mut()))?; + } + #[cfg(not(target_os = "android"))] + { + let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); + if ret == libc::SIG_ERR { + return Err(io::Error::last_os_error()); + } } } @@ -552,8 +562,7 @@ impl Process { use crate::os::unix::io::FromRawFd; use crate::sys_common::FromInner; // Safety: If `pidfd` is nonnegative, we assume it's valid and otherwise unowned. - let pidfd = (pidfd >= 0) - .then(|| PidFd::from_inner(unsafe { sys::fd::FileDesc::from_raw_fd(pidfd) })); + let pidfd = (pidfd >= 0).then(|| PidFd::from_inner(sys::fd::FileDesc::from_raw_fd(pidfd))); Process { pid, status: None, pidfd } } @@ -607,9 +616,15 @@ impl Process { } /// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy)] pub struct ExitStatus(c_int); +impl fmt::Debug for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("unix_wait_status").field(&self.0).finish() + } +} + impl ExitStatus { pub fn new(status: c_int) -> ExitStatus { ExitStatus(status) @@ -683,7 +698,7 @@ impl fmt::Display for ExitStatus { } } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy)] pub struct ExitStatusError(NonZero_c_int); impl Into for ExitStatusError { @@ -692,6 +707,12 @@ impl Into for ExitStatusError { } } +impl fmt::Debug for ExitStatusError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("unix_wait_status").field(&self.0).finish() + } +} + impl ExitStatusError { pub fn code(self) -> Option { ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap()) diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 133ad3ea420b8..891f3413e9138 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -263,7 +263,7 @@ impl Drop for Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { cfg_if::cfg_if! { if #[cfg(any( target_os = "android", @@ -338,8 +338,21 @@ pub fn available_concurrency() -> io::Result { } Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }) + } else if #[cfg(target_os = "haiku")] { + // system_info cpu_count field gets the static data set at boot time with `smp_set_num_cpus` + // `get_system_info` calls then `smp_get_num_cpus` + unsafe { + let mut sinfo: libc::system_info = crate::mem::zeroed(); + let res = libc::get_system_info(&mut sinfo); + + if res != libc::B_OK { + return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")); + } + + Ok(NonZeroUsize::new_unchecked(sinfo.cpu_count as usize)) + } } else { - // FIXME: implement on vxWorks, Redox, Haiku, l4re + // FIXME: implement on vxWorks, Redox, l4re Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Getting the number of hardware threads is not supported on the target platform")) } } diff --git a/library/std/src/sys/unsupported/thread.rs b/library/std/src/sys/unsupported/thread.rs index dc75d4ee6725c..a8db251de2017 100644 --- a/library/std/src/sys/unsupported/thread.rs +++ b/library/std/src/sys/unsupported/thread.rs @@ -31,7 +31,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index 9ec02bbec2644..2e4e474c4492c 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -64,7 +64,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/wasm/atomics/thread.rs b/library/std/src/sys/wasm/atomics/thread.rs index a66ab0837570d..16418a06226e4 100644 --- a/library/std/src/sys/wasm/atomics/thread.rs +++ b/library/std/src/sys/wasm/atomics/thread.rs @@ -40,7 +40,7 @@ impl Thread { pub fn join(self) {} } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 0c1a50e231cd4..cc137771bb8d4 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -357,7 +357,7 @@ impl File { let mut info: c::FILE_BASIC_INFO = mem::zeroed(); let size = mem::size_of_val(&info); cvt(c::GetFileInformationByHandleEx( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileBasicInfo, &mut info as *mut _ as *mut libc::c_void, size as c::DWORD, @@ -385,7 +385,7 @@ impl File { let mut info: c::FILE_STANDARD_INFO = mem::zeroed(); let size = mem::size_of_val(&info); cvt(c::GetFileInformationByHandleEx( - self.handle.raw(), + self.handle.as_raw_handle(), c::FileStandardInfo, &mut info as *mut _ as *mut libc::c_void, size as c::DWORD, diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 33152cc97abc0..9c631e7e51c1d 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -2,13 +2,13 @@ use crate::cmp; use crate::io::{self, IoSlice, IoSliceMut, Read}; +use crate::lazy::SyncOnceCell; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::windows::io::{ AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, }; use crate::ptr; -use crate::sync::Once; use crate::sys; use crate::sys::c; use crate::sys_common::net; @@ -29,26 +29,31 @@ pub mod netc { pub struct Socket(OwnedSocket); -static INIT: Once = Once::new(); +static WSA_CLEANUP: SyncOnceCell i32> = SyncOnceCell::new(); /// Checks whether the Windows socket interface has been started already, and /// if not, starts it. pub fn init() { - INIT.call_once(|| unsafe { + let _ = WSA_CLEANUP.get_or_init(|| unsafe { let mut data: c::WSADATA = mem::zeroed(); let ret = c::WSAStartup( 0x202, // version 2.2 &mut data, ); assert_eq!(ret, 0); + + // Only register `WSACleanup` if `WSAStartup` is actually ever called. + // Workaround to prevent linking to `WS2_32.dll` when no network functionality is used. + // See issue #85441. + c::WSACleanup }); } pub fn cleanup() { - if INIT.is_completed() { - // only close the socket interface if it has actually been started + // only perform cleanup if network functionality was actually initialized + if let Some(cleanup) = WSA_CLEANUP.get() { unsafe { - c::WSACleanup(); + cleanup(); } } } diff --git a/library/std/src/sys/windows/stdio_uwp.rs b/library/std/src/sys/windows/stdio_uwp.rs index 872511af862a7..32550f796ec64 100644 --- a/library/std/src/sys/windows/stdio_uwp.rs +++ b/library/std/src/sys/windows/stdio_uwp.rs @@ -2,6 +2,7 @@ use crate::io; use crate::mem::ManuallyDrop; +use crate::os::windows::io::FromRawHandle; use crate::sys::c; use crate::sys::handle::Handle; @@ -25,7 +26,8 @@ pub fn get_handle(handle_id: c::DWORD) -> io::Result { fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result { let handle = get_handle(handle_id)?; - let handle = Handle::new(handle); + // SAFETY: The handle returned from `get_handle` must be valid and non-null. + let handle = unsafe { Handle::from_raw_handle(handle) }; ManuallyDrop::new(handle).write(data) } @@ -38,7 +40,8 @@ impl Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { let handle = get_handle(c::STD_INPUT_HANDLE)?; - let handle = Handle::new(handle); + // SAFETY: The handle returned from `get_handle` must be valid and non-null. + let handle = unsafe { Handle::from_raw_handle(handle) }; ManuallyDrop::new(handle).read(buf) } } diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs index a5293133b3ab0..75f70c2076ee1 100644 --- a/library/std/src/sys/windows/thread.rs +++ b/library/std/src/sys/windows/thread.rs @@ -100,7 +100,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { let res = unsafe { let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed(); c::GetSystemInfo(&mut sysinfo); diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 894440564b738..5a5913ebd79a3 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -28,8 +28,6 @@ pub mod memchr; pub mod mutex; pub mod process; pub mod remutex; -#[macro_use] -pub mod rt; pub mod rwlock; pub mod thread; pub mod thread_info; diff --git a/library/std/src/sys_common/rt.rs b/library/std/src/sys_common/rt.rs deleted file mode 100644 index 02013ecc4ced6..0000000000000 --- a/library/std/src/sys_common/rt.rs +++ /dev/null @@ -1,81 +0,0 @@ -#![deny(unsafe_op_in_unsafe_fn)] -#![allow(unused_macros)] - -use crate::sync::Once; -use crate::sys; -use crate::sys_common::thread_info; -use crate::thread::Thread; - -// One-time runtime initialization. -// Runs before `main`. -// SAFETY: must be called only once during runtime initialization. -// NOTE: this is not guaranteed to run, for example when Rust code is called externally. -#[cfg_attr(test, allow(dead_code))] -pub unsafe fn init(argc: isize, argv: *const *const u8) { - unsafe { - sys::init(argc, argv); - - let main_guard = sys::thread::guard::init(); - // Next, set up the current Thread with the guard information we just - // created. Note that this isn't necessary in general for new threads, - // but we just do this to name the main thread and to give it correct - // info about the stack bounds. - let thread = Thread::new(Some("main".to_owned())); - thread_info::set(main_guard, thread); - } -} - -// One-time runtime cleanup. -// Runs after `main` or at program exit. -// NOTE: this is not guaranteed to run, for example when the program aborts. -#[cfg_attr(test, allow(dead_code))] -pub fn cleanup() { - static CLEANUP: Once = Once::new(); - CLEANUP.call_once(|| unsafe { - // Flush stdout and disable buffering. - crate::io::cleanup(); - // SAFETY: Only called once during runtime cleanup. - sys::cleanup(); - }); -} - -// Prints to the "panic output", depending on the platform this may be: -// - the standard error output -// - some dedicated platform specific output -// - nothing (so this macro is a no-op) -macro_rules! rtprintpanic { - ($($t:tt)*) => { - if let Some(mut out) = crate::sys::stdio::panic_output() { - let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); - } - } -} - -macro_rules! rtabort { - ($($t:tt)*) => { - { - rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*)); - crate::sys::abort_internal(); - } - } -} - -macro_rules! rtassert { - ($e:expr) => { - if !$e { - rtabort!(concat!("assertion failed: ", stringify!($e))); - } - }; -} - -macro_rules! rtunwrap { - ($ok:ident, $e:expr) => { - match $e { - $ok(v) => v, - ref err => { - let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug - rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) - } - } - }; -} diff --git a/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs index f09d16c33e6d6..38c9e50009af5 100644 --- a/library/std/src/sys_common/thread_info.rs +++ b/library/std/src/sys_common/thread_info.rs @@ -1,4 +1,5 @@ #![allow(dead_code)] // stack_guard isn't used right now on all platforms +#![allow(unused_unsafe)] // thread_local with `const {}` triggers this liny use crate::cell::RefCell; use crate::sys::thread::guard::Guard; @@ -9,7 +10,7 @@ struct ThreadInfo { thread: Thread, } -thread_local! { static THREAD_INFO: RefCell> = RefCell::new(None) } +thread_local! { static THREAD_INFO: RefCell> = const { RefCell::new(None) } } impl ThreadInfo { fn with(f: F) -> Option @@ -17,12 +18,13 @@ impl ThreadInfo { F: FnOnce(&mut ThreadInfo) -> R, { THREAD_INFO - .try_with(move |c| { - if c.borrow().is_none() { - *c.borrow_mut() = - Some(ThreadInfo { stack_guard: None, thread: Thread::new(None) }) - } - f(c.borrow_mut().as_mut().unwrap()) + .try_with(move |thread_info| { + let mut thread_info = thread_info.borrow_mut(); + let thread_info = thread_info.get_or_insert_with(|| ThreadInfo { + stack_guard: None, + thread: Thread::new(None), + }); + f(thread_info) }) .ok() } @@ -37,10 +39,9 @@ pub fn stack_guard() -> Option { } pub fn set(stack_guard: Option, thread: Thread) { - THREAD_INFO.with(|c| assert!(c.borrow().is_none())); - THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo { stack_guard, thread })); -} - -pub fn reset_guard(stack_guard: Option) { - THREAD_INFO.with(move |c| c.borrow_mut().as_mut().unwrap().stack_guard = stack_guard); + THREAD_INFO.with(move |thread_info| { + let mut thread_info = thread_info.borrow_mut(); + rtassert!(thread_info.is_none()); + *thread_info = Some(ThreadInfo { stack_guard, thread }); + }); } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index f44df845bf4dd..707a55b625814 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -457,7 +457,9 @@ impl Builder { let stack_size = stack_size.unwrap_or_else(thread::min_stack); - let my_thread = Thread::new(name); + let my_thread = Thread::new(name.map(|name| { + CString::new(name).expect("thread name may not contain interior null bytes") + })); let their_thread = my_thread.clone(); let my_packet: Arc>>> = Arc::new(UnsafeCell::new(None)); @@ -1073,12 +1075,8 @@ pub struct Thread { impl Thread { // Used only internally to construct a thread object without spawning // Panics if the name contains nuls. - pub(crate) fn new(name: Option) -> Thread { - let cname = - name.map(|n| CString::new(n).expect("thread name may not contain interior null bytes")); - Thread { - inner: Arc::new(Inner { name: cname, id: ThreadId::new(), parker: Parker::new() }), - } + pub(crate) fn new(name: Option) -> Thread { + Thread { inner: Arc::new(Inner { name, id: ThreadId::new(), parker: Parker::new() }) } } /// Atomically makes the handle's token available if it is not already. @@ -1455,12 +1453,14 @@ fn _assert_sync_and_send() { /// /// ``` /// # #![allow(dead_code)] -/// #![feature(available_concurrency)] +/// #![feature(available_parallelism)] /// use std::thread; /// -/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1); +/// let count = thread::available_parallelism().map(|n| n.get()).unwrap_or(1); /// ``` -#[unstable(feature = "available_concurrency", issue = "74479")] -pub fn available_concurrency() -> io::Result { - imp::available_concurrency() +#[doc(alias = "hardware_concurrency")] // Alias for C++ `std::thread::hardware_concurrency`. +#[doc(alias = "available_concurrency")] // Alias for a name we gave this API on unstable. +#[unstable(feature = "available_parallelism", issue = "74479")] +pub fn available_parallelism() -> io::Result { + imp::available_parallelism() } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index bf3eb5b30c77d..5efd8c9be5633 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -108,6 +108,7 @@ pub use core::time::FromSecsError; /// | UNIX | [clock_gettime (Monotonic Clock)] | /// | Darwin | [mach_absolute_time] | /// | VXWorks | [clock_gettime (Monotonic Clock)] | +/// | SOLID | `get_tim` | /// | WASI | [__wasi_clock_time_get (Monotonic Clock)] | /// | Windows | [QueryPerformanceCounter] | /// @@ -184,6 +185,7 @@ pub struct Instant(time::Instant); /// | UNIX | [clock_gettime (Realtime Clock)] | /// | Darwin | [gettimeofday] | /// | VXWorks | [clock_gettime (Realtime Clock)] | +/// | SOLID | `SOLID_RTC_ReadTime` | /// | WASI | [__wasi_clock_time_get (Realtime Clock)] | /// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] | /// @@ -472,7 +474,7 @@ impl SystemTime { /// as the system clock being adjusted either forwards or backwards). /// [`Instant`] can be used to measure elapsed time without this risk of failure. /// - /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents + /// If successful, [Ok]\([Duration]) is returned where the duration represents /// the amount of time elapsed from the specified measurement to this one. /// /// Returns an [`Err`] if `earlier` is later than `self`, and the error @@ -499,7 +501,7 @@ impl SystemTime { /// /// This function may fail as the underlying system clock is susceptible to /// drift and updates (e.g., the system clock could go backwards), so this - /// function might not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is + /// function might not always succeed. If successful, [Ok]\([Duration]) is /// returned where the duration represents the amount of time elapsed from /// this time measurement to the current time. /// diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs index 198ae739b5567..64f16245c2b16 100644 --- a/library/std/src/time/monotonic.rs +++ b/library/std/src/time/monotonic.rs @@ -5,7 +5,7 @@ pub(super) fn monotonize(raw: time::Instant) -> time::Instant { inner::monotonize(raw) } -#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))] +#[cfg(any(all(target_has_atomic = "64", not(target_has_atomic = "128")), target_arch = "aarch64"))] pub mod inner { use crate::sync::atomic::AtomicU64; use crate::sync::atomic::Ordering::*; @@ -71,7 +71,7 @@ pub mod inner { } } -#[cfg(target_has_atomic = "128")] +#[cfg(all(target_has_atomic = "128", not(target_arch = "aarch64")))] pub mod inner { use crate::sync::atomic::AtomicU128; use crate::sync::atomic::Ordering::*; diff --git a/library/stdarch b/library/stdarch index 89b0e355bc3cf..5fdbc476afc81 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 89b0e355bc3cff5cddec2290c84f36eb3a026aad +Subproject commit 5fdbc476afc81a789806697fc4a2d9d19b8c9993 diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 80d6072e9b5c2..04dab6b804acc 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -33,3 +33,4 @@ panic_immediate_abort = ["std/panic_immediate_abort"] profiler = ["std/profiler"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] +std_detect_env_override = ["std/std_detect_env_override"] diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index aa24480751419..04057906d1c3e 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -29,7 +29,8 @@ impl JunitFormatter { impl OutputFormatter for JunitFormatter { fn write_run_start(&mut self, _test_count: usize) -> io::Result<()> { // We write xml header on run start - self.write_message(&"") + self.out.write_all(b"\n")?; + self.write_message("") } fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> { @@ -133,6 +134,8 @@ impl OutputFormatter for JunitFormatter { self.write_message("")?; self.write_message("")?; + self.out.write_all(b"\n\n")?; + Ok(state.failed == 0) } } diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs index c39a9b0ec0233..e25f524ec0566 100644 --- a/library/test/src/helpers/concurrency.rs +++ b/library/test/src/helpers/concurrency.rs @@ -9,6 +9,6 @@ pub fn get_concurrency() -> usize { _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", value), } } else { - thread::available_concurrency().map(|n| n.get()).unwrap_or(1) + thread::available_parallelism().map(|n| n.get()).unwrap_or(1) } } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 251f099f28af4..6732c6c61c204 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -23,7 +23,7 @@ #![feature(libc)] #![feature(rustc_private)] #![feature(nll)] -#![feature(available_concurrency)] +#![feature(available_parallelism)] #![feature(bench_black_box)] #![feature(internal_output_capture)] #![feature(panic_unwind)] diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 06384b1592647..25be9e7cc6c0c 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -23,6 +23,7 @@ cfg_if::cfg_if! { unix, windows, target_os = "psp", + target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx"), ))] { mod libunwind; diff --git a/rustfmt.toml b/rustfmt.toml index 480b19a5e9336..053f3e3ee583b 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -19,6 +19,7 @@ ignore = [ "library/backtrace", "library/stdarch", "compiler/rustc_codegen_cranelift", + "compiler/rustc_codegen_gcc", "src/doc/book", "src/doc/edition-guide", "src/doc/embedded-book", diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 57ade88f73306..05d7b0f611f72 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -594,19 +594,23 @@ def fix_bin_or_dylib(self, fname): if ostype != "Linux": return - # Use `/etc/os-release` instead of `/etc/NIXOS`. - # The latter one does not exist on NixOS when using tmpfs as root. - try: - with open("/etc/os-release", "r") as f: - if not any(line.strip() == "ID=nixos" for line in f): - return - except FileNotFoundError: - return - if os.path.exists("/lib"): - return + # If the user has asked binaries to be patched for Nix, then + # don't check for NixOS or `/lib`, just continue to the patching. + if self.get_toml('patch-binaries-for-nix', 'build') != 'true': + # Use `/etc/os-release` instead of `/etc/NIXOS`. + # The latter one does not exist on NixOS when using tmpfs as root. + try: + with open("/etc/os-release", "r") as f: + if not any(line.strip() == "ID=nixos" for line in f): + return + except FileNotFoundError: + return + if os.path.exists("/lib"): + return - # At this point we're pretty sure the user is running NixOS - nix_os_msg = "info: you seem to be running NixOS. Attempting to patch" + # At this point we're pretty sure the user is running NixOS or + # using Nix + nix_os_msg = "info: you seem to be using Nix. Attempting to patch" print(nix_os_msg, fname) # Only build `.nix-deps` once. diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0a6ed2f49b787..1f2109879d121 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -1617,6 +1617,22 @@ impl<'a> Builder<'a> { // Only execute if it's supposed to run as default if desc.default && should_run.is_really_default() { self.ensure(step) } else { None } } + + /// Checks if any of the "should_run" paths is in the `Builder` paths. + pub(crate) fn was_invoked_explicitly(&'a self) -> bool { + let desc = StepDescription::from::(); + let should_run = (desc.should_run)(ShouldRun::new(self)); + + for path in &self.paths { + if should_run.paths.iter().any(|s| s.has(path)) + && !desc.is_excluded(self, &PathSet::Suite(path.clone())) + { + return true; + } + } + + false + } } #[cfg(test)] diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index f66f282bea933..28e7f1fdca7a1 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -243,11 +243,16 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"]) + run.paths(&[ + "compiler/rustc_codegen_cranelift", + "rustc_codegen_cranelift", + "compiler/rustc_codegen_gcc", + "rustc_codegen_gcc", + ]) } fn make_run(run: RunConfig<'_>) { - for &backend in &[INTERNER.intern_str("cranelift")] { + for &backend in &[INTERNER.intern_str("cranelift"), INTERNER.intern_str("gcc")] { run.builder.ensure(CodegenBackend { target: run.target, backend }); } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5706b8f9e7cc6..062820040dc78 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -397,6 +397,7 @@ struct Build { install_stage: Option, dist_stage: Option, bench_stage: Option, + patch_binaries_for_nix: Option, } /// TOML representation of various global install decisions. diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml index 9874fdb767f62..7bc054d3a49fc 100644 --- a/src/bootstrap/defaults/config.library.toml +++ b/src/bootstrap/defaults/config.library.toml @@ -10,6 +10,5 @@ bench-stage = 0 incremental = true [llvm] -# Will download LLVM from CI if available on your platform (Linux only for now) -# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms +# Will download LLVM from CI if available on your platform. download-ci-llvm = "if-available" diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index af3774b7c7586..6f2470b706a64 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -102,18 +102,10 @@ fn open(builder: &Builder<'_>, path: impl AsRef) { // Used for deciding whether a particular step is one requested by the user on // the `x.py doc` command line, which determines whether `--open` will open that // page. -fn components_simplified(path: &PathBuf) -> Vec<&str> { +pub(crate) fn components_simplified(path: &PathBuf) -> Vec<&str> { path.iter().map(|component| component.to_str().unwrap_or("???")).collect() } -fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool { - builder - .paths - .iter() - .map(components_simplified) - .any(|requested| requested.iter().copied().eq(path.split('/'))) -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: TargetSelection, @@ -248,7 +240,7 @@ impl Step for TheBook { invoke_rustdoc(builder, compiler, target, path); } - if is_explicit_request(builder, "src/doc/book") { + if builder.was_invoked_explicitly::() { let out = builder.doc_out(target); let index = out.join("book").join("index.html"); open(builder, &index); @@ -408,7 +400,7 @@ impl Step for Standalone { // We open doc/index.html as the default if invoked as `x.py doc --open` // with no particular explicit doc requested (e.g. library/core). - if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") { + if builder.paths.is_empty() || builder.was_invoked_explicitly::() { let index = out.join("index.html"); open(builder, &index); } @@ -553,7 +545,6 @@ impl Step for Rustc { fn run(self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; - let mut is_explicit_request = false; builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); let paths = builder @@ -562,7 +553,6 @@ impl Step for Rustc { .map(components_simplified) .filter_map(|path| { if path.get(0) == Some(&"compiler") { - is_explicit_request = true; path.get(1).map(|p| p.to_owned()) } else { None @@ -570,7 +560,7 @@ impl Step for Rustc { }) .collect::>(); - if !builder.config.compiler_docs && !is_explicit_request { + if !builder.config.compiler_docs && !builder.was_invoked_explicitly::() { builder.info("\tskipping - compiler/librustdoc docs disabled"); return; } @@ -700,7 +690,14 @@ macro_rules! tool_doc { fn run(self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; - builder.info(&format!("Documenting stage{} {} ({})", stage, stringify!($tool).to_lowercase(), target)); + builder.info( + &format!( + "Documenting stage{} {} ({})", + stage, + stringify!($tool).to_lowercase(), + target, + ), + ); // This is the intended out directory for compiler documentation. let out = builder.compiler_doc_out(target); @@ -708,7 +705,7 @@ macro_rules! tool_doc { let compiler = builder.compiler(stage, builder.config.build); - if !builder.config.compiler_docs { + if !builder.config.compiler_docs && !builder.was_invoked_explicitly::() { builder.info("\tskipping - compiler/tool docs disabled"); return; } @@ -743,6 +740,7 @@ macro_rules! tool_doc { cargo.rustdocflag("--document-private-items"); cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("--show-type-layout"); + cargo.rustdocflag("--generate-link-to-definition"); cargo.rustdocflag("-Zunstable-options"); builder.run(&mut cargo.into()); } @@ -912,7 +910,7 @@ impl Step for RustcBook { name: INTERNER.intern_str("rustc"), src: INTERNER.intern_path(out_base), }); - if is_explicit_request(builder, "src/doc/rustc") { + if builder.was_invoked_explicitly::() { let out = builder.doc_out(self.target); let index = out.join("rustc").join("index.html"); open(builder, &index); diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index a5829dfa9d879..5bc0a505bf695 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -1,3 +1,4 @@ +use crate::TargetSelection; use crate::{t, VERSION}; use std::fmt::Write as _; use std::path::{Path, PathBuf}; @@ -107,6 +108,17 @@ pub fn setup(src_path: &Path, profile: Profile) { let include_path = profile.include_path(src_path); println!("`x.py` will now use the configuration at {}", include_path.display()); + let build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); + let stage_path = ["build", build.rustc_target_arg(), "stage1"].join("/"); + + println!(); + + if !rustup_installed() && profile != Profile::User { + println!("`rustup` is not installed; cannot link `stage1` toolchain"); + } else if stage_dir_exists(&stage_path[..]) { + attempt_toolchain_link(&stage_path[..]); + } + let suggestions = match profile { Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..], Profile::Tools => &[ @@ -139,6 +151,74 @@ pub fn setup(src_path: &Path, profile: Profile) { } } +fn rustup_installed() -> bool { + Command::new("rustup") + .arg("--version") + .stdout(std::process::Stdio::null()) + .output() + .map_or(false, |output| output.status.success()) +} + +fn stage_dir_exists(stage_path: &str) -> bool { + match fs::create_dir(&stage_path[..]) { + Ok(_) => true, + Err(_) => Path::new(&stage_path[..]).exists(), + } +} + +fn attempt_toolchain_link(stage_path: &str) { + if toolchain_is_linked() { + return; + } + + if try_link_toolchain(&stage_path[..]) { + println!( + "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain" + ); + } else { + println!("`rustup` failed to link stage 1 build to `stage1` toolchain"); + println!( + "To manually link stage 1 build to `stage1` toolchain, run:\n + `rustup toolchain link stage1 {}`", + &stage_path[..] + ); + } +} + +fn toolchain_is_linked() -> bool { + match Command::new("rustup") + .args(&["toolchain", "list"]) + .stdout(std::process::Stdio::piped()) + .output() + { + Ok(toolchain_list) => { + if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") { + return false; + } + // The toolchain has already been linked. + println!( + "`stage1` toolchain already linked; not attempting to link `stage1` toolchain" + ); + } + Err(_) => { + // In this case, we don't know if the `stage1` toolchain has been linked; + // but `rustup` failed, so let's not go any further. + println!( + "`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain" + ); + } + } + true +} + +fn try_link_toolchain(stage_path: &str) -> bool { + Command::new("rustup") + .stdout(std::process::Stdio::null()) + .args(&["toolchain", "link", "stage1", &stage_path[..]]) + .output() + .map_or(false, |output| output.status.success()) +} + // Used to get the path for `Subcommand::Setup` pub fn interactive_path() -> io::Result { fn abbrev_all() -> impl Iterator { diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config b/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config index acdf9a0e04185..e047db92652c2 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config +++ b/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config @@ -611,7 +611,7 @@ CT_ISL_V_0_20=y # CT_ISL_V_0_15 is not set # CT_ISL_NO_VERSIONS is not set CT_ISL_VERSION="0.20" -CT_ISL_MIRRORS="http://isl.gforge.inria.fr" +CT_ISL_MIRRORS="https://ci-mirrors.rust-lang.org/rustc" CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}" CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/build-toolchains.sh b/src/ci/docker/host-x86_64/dist-arm-linux/build-toolchains.sh index 3fd882521999a..ad53ba4dd1bc0 100755 --- a/src/ci/docker/host-x86_64/dist-arm-linux/build-toolchains.sh +++ b/src/ci/docker/host-x86_64/dist-arm-linux/build-toolchains.sh @@ -22,7 +22,8 @@ exit 1 mkdir build cd build cp ../arm-linux-gnueabi.config .config -ct-ng oldconfig +# FIXME ct-ng oldconfig is not working as intended. +# ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build diff --git a/src/ci/docker/host-x86_64/dist-armhf-linux/arm-linux-gnueabihf.config b/src/ci/docker/host-x86_64/dist-armhf-linux/arm-linux-gnueabihf.config index 69f86663ec21b..e0f6417793de8 100644 --- a/src/ci/docker/host-x86_64/dist-armhf-linux/arm-linux-gnueabihf.config +++ b/src/ci/docker/host-x86_64/dist-armhf-linux/arm-linux-gnueabihf.config @@ -14,6 +14,7 @@ CT_CONFIGURE_has_autoconf_2_65_or_newer=y CT_CONFIGURE_has_autoreconf_2_65_or_newer=y CT_CONFIGURE_has_automake_1_15_or_newer=y CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y +CT_CONFIGURE_has_python_3_4_or_newer=y CT_CONFIGURE_has_bison_2_7_or_newer=y CT_CONFIGURE_has_python=y CT_CONFIGURE_has_git=y @@ -132,12 +133,6 @@ CT_ARCH_ARM=y # CT_ARCH_XTENSA is not set CT_ARCH="arm" CT_ARCH_CHOICE_KSYM="ARM" -# CT_ARCH_ALPHA_EV4 is not set -# CT_ARCH_ALPHA_EV45 is not set -# CT_ARCH_ALPHA_EV5 is not set -# CT_ARCH_ALPHA_EV56 is not set -# CT_ARCH_ALPHA_EV6 is not set -# CT_ARCH_ALPHA_EV67 is not set CT_ARCH_CPU="" CT_ARCH_TUNE="" CT_ARCH_ARM_SHOW=y @@ -372,8 +367,6 @@ CT_ALL_BINUTILS_CHOICES="BINUTILS" # C-library # CT_LIBC_GLIBC=y -# CT_LIBC_NEWLIB is not set -# CT_LIBC_NONE is not set # CT_LIBC_UCLIBC is not set CT_LIBC="glibc" CT_LIBC_CHOICE_KSYM="GLIBC" @@ -390,6 +383,7 @@ CT_GLIBC_USE="GLIBC" CT_GLIBC_PKG_NAME="glibc" CT_GLIBC_SRC_RELEASE=y CT_GLIBC_PATCH_ORDER="global" +# CT_GLIBC_V_2_29 is not set # CT_GLIBC_V_2_28 is not set # CT_GLIBC_V_2_27 is not set # CT_GLIBC_V_2_26 is not set @@ -408,7 +402,6 @@ CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" CT_GLIBC_SIGNATURE_FORMAT="packed/.sig" CT_GLIBC_2_29_or_older=y CT_GLIBC_older_than_2_29=y -CT_GLIBC_REQUIRE_older_than_2_29=y CT_GLIBC_2_27_or_older=y CT_GLIBC_older_than_2_27=y CT_GLIBC_2_26_or_older=y @@ -448,12 +441,6 @@ CT_GLIBC_FORCE_UNWIND=y CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y # CT_GLIBC_KERNEL_VERSION_CHOSEN is not set CT_GLIBC_MIN_KERNEL="3.2.101" -# CT_GLIBC_SSP_DEFAULT is not set -# CT_GLIBC_SSP_NO is not set -# CT_GLIBC_SSP_YES is not set -# CT_GLIBC_SSP_ALL is not set -# CT_GLIBC_SSP_STRONG is not set -# CT_NEWLIB_USE_REDHAT is not set CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC" CT_LIBC_SUPPORT_THREADS_ANY=y CT_LIBC_SUPPORT_THREADS_NATIVE=y @@ -625,7 +612,7 @@ CT_ISL_V_0_20=y # CT_ISL_V_0_15 is not set # CT_ISL_NO_VERSIONS is not set CT_ISL_VERSION="0.20" -CT_ISL_MIRRORS="http://isl.gforge.inria.fr" +CT_ISL_MIRRORS="https://ci-mirrors.rust-lang.org/rustc" CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}" CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" diff --git a/src/ci/docker/host-x86_64/dist-armhf-linux/build-toolchains.sh b/src/ci/docker/host-x86_64/dist-armhf-linux/build-toolchains.sh index f425efd6057c6..6b5374422a62a 100755 --- a/src/ci/docker/host-x86_64/dist-armhf-linux/build-toolchains.sh +++ b/src/ci/docker/host-x86_64/dist-armhf-linux/build-toolchains.sh @@ -22,7 +22,8 @@ exit 1 mkdir build cd build cp ../arm-linux-gnueabihf.config .config -ct-ng oldconfig +# FIXME ct-ng oldconfig is not working as intended. +# ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build diff --git a/src/ci/docker/host-x86_64/dist-armv7-linux/armv7-linux-gnueabihf.config b/src/ci/docker/host-x86_64/dist-armv7-linux/armv7-linux-gnueabihf.config index e3d032fc7e8fc..2d8167f1f3328 100644 --- a/src/ci/docker/host-x86_64/dist-armv7-linux/armv7-linux-gnueabihf.config +++ b/src/ci/docker/host-x86_64/dist-armv7-linux/armv7-linux-gnueabihf.config @@ -17,8 +17,6 @@ CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y CT_CONFIGURE_has_python_3_4_or_newer=y CT_CONFIGURE_has_bison_2_7_or_newer=y CT_CONFIGURE_has_python=y -CT_CONFIGURE_has_dtc=y -CT_CONFIGURE_has_svn=y CT_CONFIGURE_has_git=y CT_CONFIGURE_has_md5sum=y CT_CONFIGURE_has_sha1sum=y @@ -612,7 +610,7 @@ CT_ISL_V_0_20=y # CT_ISL_V_0_15 is not set # CT_ISL_NO_VERSIONS is not set CT_ISL_VERSION="0.20" -CT_ISL_MIRRORS="http://isl.gforge.inria.fr" +CT_ISL_MIRRORS="https://ci-mirrors.rust-lang.org/rustc" CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}" CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" diff --git a/src/ci/docker/host-x86_64/dist-armv7-linux/build-toolchains.sh b/src/ci/docker/host-x86_64/dist-armv7-linux/build-toolchains.sh index 17dda2dbd1680..602ad8ac87737 100755 --- a/src/ci/docker/host-x86_64/dist-armv7-linux/build-toolchains.sh +++ b/src/ci/docker/host-x86_64/dist-armv7-linux/build-toolchains.sh @@ -22,7 +22,8 @@ exit 1 mkdir build cd build cp ../armv7-linux-gnueabihf.config .config -ct-ng oldconfig +# FIXME ct-ng oldconfig is not working as intended. +# ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile index 42fda98bc7a4b..63836654293f2 100644 --- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile @@ -34,6 +34,11 @@ RUN apt-get update && \ xz-utils \ zlib1g-dev +# Install new Let's Encrypt root CA certificate and remove the expired one. +COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt +RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf +RUN /usr/sbin/update-ca-certificates + ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.config b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.config index 45d5ff756cdca..7400a8a038d0c 100644 --- a/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.config +++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/riscv64-unknown-linux-gnu.config @@ -722,7 +722,7 @@ CT_ISL_V_0_20=y # CT_ISL_V_0_15 is not set # CT_ISL_NO_VERSIONS is not set CT_ISL_VERSION="0.20" -CT_ISL_MIRRORS="http://isl.gforge.inria.fr" +CT_ISL_MIRRORS="https://ci-mirrors.rust-lang.org/rustc" CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}" CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}" CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" 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 e29d990f0f974..7b560aaaaa688 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 @@ -34,6 +34,11 @@ RUN apt-get update && \ xz-utils \ zlib1g-dev +# Install new Let's Encrypt root CA certificate and remove the expired one. +COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt +RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf +RUN /usr/sbin/update-ca-certificates + ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig diff --git a/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt b/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt new file mode 100644 index 0000000000000..b85c8037f6b60 --- /dev/null +++ b/src/ci/docker/host-x86_64/shared/ISRG_Root_X1.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index fd29d3a022ad3..b17398bb6b440 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -61,3 +61,9 @@ elif isWindows && [[ ${CUSTOM_MINGW-0} -ne 1 ]]; then ciCommandSetEnv RUST_CONFIGURE_ARGS \ "${RUST_CONFIGURE_ARGS} --set llvm.clang-cl=$(pwd)/clang-rust/bin/clang-cl.exe" fi + +if isWindows; then + # GitHub image 20210928.2 added LLVM, but it is broken (and we don't want + # to use it anyways). + rm -rf /c/Program\ Files/LLVM +fi diff --git a/src/doc/book b/src/doc/book index fcb5e0ea68112..eb1282ec444db 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit fcb5e0ea68112d85a1d29a7a7335978ef2a02181 +Subproject commit eb1282ec444db94055fa9531b6f3f803e86bb382 diff --git a/src/doc/nomicon b/src/doc/nomicon index fe6227eb3c853..2747c4bb2cbc0 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit fe6227eb3c8533200c52dffa42ef1b6f2f02c40e +Subproject commit 2747c4bb2cbc0639b733793ddb0bf4e9daa2634e diff --git a/src/doc/reference b/src/doc/reference index 0e5ed7a4bec06..13747275bd14c 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 0e5ed7a4bec065f0cc18c35d1c904639e095314d +Subproject commit 13747275bd14c2d2b453100498532f9ae5504769 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 9d4132b56c499..28aca4a36962c 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 9d4132b56c4999cd3ce1aeca5f1b2f2cb0d11c24 +Subproject commit 28aca4a36962c709bce301c03114b5589381dfb8 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 9198465b6ca8b..d1f03cbaa39d9 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 9198465b6ca8bed669df0cbb67c0e6d0b140803c +Subproject commit d1f03cbaa39d9164f5fe4b9b93762668142e0dad diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index bc1873b6836be..8c41835183797 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -14,6 +14,7 @@ - [Tests](tests/index.md) - [Platform Support](platform-support.md) - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) + - [\*-kmc-solid_\*](platform-support/kmc-solid.md) - [Target Tier Policy](target-tier-policy.md) - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 05384117ac175..4f8c4c66f8891 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -435,6 +435,10 @@ Equivalent to the "uppercase" `-fPIC` or `-fPIE` options in other compilers, depending on the produced crate types. \ This is the default model for majority of supported targets. +- `pie` - position independent executable, relocatable code but without support for symbol +interpositioning (replacing symbols by name using `LD_PRELOAD` and similar). Equivalent to the "uppercase" `-fPIE` option in other compilers. `pie` +code cannot be linked into shared libraries (you'll get a linking error on attempt to do this). + #### Special relocation models - `dynamic-no-pic` - relocatable external references, non-relocatable code. \ diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 0f106292e9670..26fef88946251 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -133,8 +133,8 @@ target | std | notes `armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL `armv7-linux-androideabi` | ✓ | ARMv7a Android `armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27) -`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux, MUSL -`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL +`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux with MUSL +`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL, hardfloat `armv7a-none-eabi` | * | Bare ARMv7-A `armv7r-none-eabi` | * | Bare ARMv7-R `armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat @@ -202,6 +202,7 @@ target | std | host | notes -------|:---:|:----:|------- `aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64 `aarch64-apple-tvos` | * | | ARM64 tvOS +[`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ? | | `aarch64-unknown-uefi` | * | | ARM64 UEFI @@ -222,6 +223,8 @@ target | std | host | notes `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD `armv7-unknown-netbsd-eabihf` | ✓ | ✓ | `armv7-wrs-vxworks-eabihf` | ? | | +[`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 +[`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat `armv7s-apple-ios` | ✓ | | `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` diff --git a/src/doc/rustc/src/platform-support/kmc-solid.md b/src/doc/rustc/src/platform-support/kmc-solid.md new file mode 100644 index 0000000000000..bbcd0f711c663 --- /dev/null +++ b/src/doc/rustc/src/platform-support/kmc-solid.md @@ -0,0 +1,65 @@ +# \*-kmc-solid_\* + +**Tier: 3** + +[SOLID] embedded development platform by Kyoto Microcomputer Co., Ltd. + +[SOLID]: https://www.kmckk.co.jp/eng/SOLID/ + +The target names follow this format: `$ARCH-kmc-solid_$KERNEL-$ABI`, where `$ARCH` specifies the target processor architecture, `$KERNEL` the base kernel, and `$ABI` the target ABI (optional). The following targets are currently defined: + +| Target name | `target_arch` | `target_vendor` | `target_os` | +|--------------------------------|---------------|-----------------|--------------| +| `aarch64-kmc-solid_asp3` | `aarch64` | `kmc` | `solid_asp3` | +| `armv7a-kmc-solid_asp3-eabi` | `arm` | `kmc` | `solid_asp3` | +| `armv7a-kmc-solid_asp3-eabihf` | `arm` | `kmc` | `solid_asp3` | + +## Designated Developers + +- [@kawadakk](https://github.com/kawadakk) + +## Requirements + +This target is cross-compiled. +A platform-provided C compiler toolchain is required, though it can be substituted by [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm) for the purpose of building Rust and functional binaries. + +## Building + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["aarch64-kmc-solid_asp3"] +``` + +Make sure `aarch64-kmc-elf-gcc` is included in `$PATH`. Alternatively, you can use GNU Arm Embedded Toolchain by adding the following to `config.toml`: + +```toml +[target.aarch64-kmc-solid_asp3] +cc = "arm-none-eabi-gcc" +``` + +## Cross-compilation + +This target can be cross-compiled from any hosts. + +## Testing + +Currently there is no support to run the rustc test suite for this target. + +## Building Rust programs + +Building executables is not supported yet. + +If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target: + +```shell +$ rustc --target aarch64-kmc-solid_asp3 your-code.rs --crate-type staticlib +$ ls libyour_code.a +``` + +On Rust Nightly it's possible to build without the target artifacts available: + +```text +cargo build -Z build-std --target aarch64-kmc-solid_asp3 +``` diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md index ec23d4fe0dbd3..04e20fdd41c0f 100644 --- a/src/doc/rustc/src/tests/index.md +++ b/src/doc/rustc/src/tests/index.md @@ -161,7 +161,7 @@ The following options affect how tests are executed. Sets the number of threads to use for running tests in parallel. By default, uses the amount of concurrency available on the hardware as indicated by -[`available_concurrency`]. +[`available_parallelism`]. This can also be specified with the `RUST_TEST_THREADS` environment variable. @@ -265,7 +265,7 @@ Experimental support for using custom test harnesses is available on the [`--test` option]: ../command-line-arguments.md#option-test [`-Z panic-abort-tests`]: https://github.com/rust-lang/rust/issues/67650 -[`available_concurrency`]: ../../std/thread/fn.available_concurrency.html +[`available_parallelism`]: ../../std/thread/fn.available_parallelism.html [`cargo test`]: ../../cargo/commands/cargo-test.html [`libtest`]: ../../test/index.html [`main` function]: ../../reference/crates-and-source-files.html#main-functions diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 16b091eb255b0..1773c15464a94 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -70,6 +70,8 @@ This lint **warns by default**. This lint detects when [intra-doc links] from pu For example: ```rust +#![warn(rustdoc::private_intra_doc_links)] // note: unnecessary - warns by default. + /// [private] pub fn public() {} fn private() {} @@ -227,6 +229,8 @@ This lint **warns by default**. It detects code block attributes in documentation examples that have potentially mis-typed values. For example: ```rust +#![warn(rustdoc::invalid_codeblock_attributes)] // note: unnecessary - warns by default. + /// Example. /// /// ```should-panic @@ -344,6 +348,8 @@ This lint is **warn-by-default**. It detects URLs which are not links. For example: ```rust +#![warn(rustdoc::bare_urls)] // note: unnecessary - warns by default. + /// http://example.org /// [http://example.net] pub fn foo() {} diff --git a/src/doc/unstable-book/src/language-features/closure-track-caller.md b/src/doc/unstable-book/src/language-features/closure-track-caller.md new file mode 100644 index 0000000000000..c948810d3e5a1 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/closure-track-caller.md @@ -0,0 +1,12 @@ +# `closure_track_caller` + +The tracking issue for this feature is: [#87417] + +[#87417]: https://github.com/rust-lang/rust/issues/87417 + +------------------------ + +Allows using the `#[track_caller]` attribute on closures and generators. +Calls made to the closure or generator will have caller information +available through `std::panic::Location::caller()`, just like using +`#[track_caller]` on a function. diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py index 7572b8c6f4a8c..7ed317c778fce 100644 --- a/src/etc/check_missing_items.py +++ b/src/etc/check_missing_items.py @@ -9,7 +9,7 @@ import sys import json -crate = json.load(open(sys.argv[1])) +crate = json.load(open(sys.argv[1], encoding="utf-8")) def get_local_item(item_id): diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index c83ca6ba54ce3..1436e51f31820 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -354,7 +354,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { let (poly_trait, output) = (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new)); let new_ty = match poly_trait.trait_ { - Type::ResolvedPath { ref path, ref did, ref is_generic } => { + Type::ResolvedPath { ref path, ref did } => { let mut new_path = path.clone(); let last_segment = new_path.segments.pop().expect("segments were empty"); @@ -389,11 +389,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { .segments .push(PathSegment { name: last_segment.name, args: new_params }); - Type::ResolvedPath { - path: new_path, - did: *did, - is_generic: *is_generic, - } + Type::ResolvedPath { path: new_path, did: *did } } _ => panic!("Unexpected data: {:?}, {:?}", ty, data), }; @@ -563,11 +559,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { Type::QPath { name: left_name, ref self_type, ref trait_, .. } => { let ty = &*self_type; match **trait_ { - Type::ResolvedPath { - path: ref trait_path, - ref did, - ref is_generic, - } => { + Type::ResolvedPath { path: ref trait_path, ref did } => { let mut new_trait_path = trait_path.clone(); if self.is_fn_ty(trait_) && left_name == sym::Output { @@ -612,7 +604,6 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { trait_: Type::ResolvedPath { path: new_trait_path, did: *did, - is_generic: *is_generic, }, generic_params: Vec::new(), }, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 82939c930c4ea..8135d4a2085dd 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -64,7 +64,11 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .instantiate(self.cx.tcx, impl_substs) .predicates .into_iter() - .chain(Some(trait_ref.without_const().to_predicate(infcx.tcx))); + .chain(Some( + ty::Binder::dummy(trait_ref) + .without_const() + .to_predicate(infcx.tcx), + )); for predicate in predicates { debug!("testing predicate {:?}", predicate); let obligation = traits::Obligation::new( diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 15d704eb57f1e..b463c1dc7146b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -318,10 +318,10 @@ fn merge_attrs( } else { Attributes::from_ast(&both, None) }, - both.cfg(cx.sess()), + both.cfg(cx.tcx, &cx.cache.hidden_cfg), ) } else { - (old_attrs.clean(cx), old_attrs.cfg(cx.sess())) + (old_attrs.clean(cx), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg)) } } @@ -389,13 +389,45 @@ crate fn build_impl( } } + let document_hidden = cx.render_options.document_hidden; let predicates = tcx.explicit_predicates_of(did); let (trait_items, generics) = match impl_item { Some(impl_) => ( impl_ .items .iter() - .map(|item| tcx.hir().impl_item(item.id).clean(cx)) + .map(|item| tcx.hir().impl_item(item.id)) + .filter(|item| { + // Filter out impl items whose corresponding trait item has `doc(hidden)` + // not to document such impl items. + // For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs. + + // When `--document-hidden-items` is passed, we don't + // do any filtering, too. + if document_hidden { + return true; + } + if let Some(associated_trait) = associated_trait { + let assoc_kind = match item.kind { + hir::ImplItemKind::Const(..) => ty::AssocKind::Const, + hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, + hir::ImplItemKind::TyAlias(..) => ty::AssocKind::Type, + }; + let trait_item = tcx + .associated_items(associated_trait.def_id) + .find_by_name_and_kind( + tcx, + item.ident, + assoc_kind, + associated_trait.def_id, + ) + .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name. + !tcx.get_attrs(trait_item.def_id).lists(sym::doc).has_word(sym::hidden) + } else { + true + } + }) + .map(|item| item.clean(cx)) .collect::>(), impl_.generics.clean(cx), ), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3ec979c5ae918..969d15dd6a160 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -11,7 +11,7 @@ crate mod utils; use rustc_ast as ast; use rustc_attr as attr; -use rustc_const_eval::const_eval::{is_const_fn, is_unstable_const_fn}; +use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -132,7 +132,7 @@ impl Clean for hir::GenericBound<'_> { hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => { let def_id = cx.tcx.require_lang_item(lang_item, Some(span)); - let trait_ref = ty::TraitRef::identity(cx.tcx, def_id); + let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder(); let generic_args = generic_args.clean(cx); let bindings = match generic_args { @@ -168,7 +168,7 @@ impl Clean for (ty::TraitRef<'_>, &[TypeBinding]) { debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); - ResolvedPath { path, did: trait_ref.def_id, is_generic: false } + ResolvedPath { path, did: trait_ref.def_id } } } @@ -787,7 +787,7 @@ fn clean_fn_or_proc_macro( let mut func = (sig, generics, body_id).clean(cx); let def_id = item.def_id.to_def_id(); func.header.constness = - if is_const_fn(cx.tcx, def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() { + if cx.tcx.is_const_fn(def_id) && is_unstable_const_fn(cx.tcx, def_id).is_none() { hir::Constness::Const } else { hir::Constness::NotConst @@ -1313,7 +1313,7 @@ impl Clean for hir::Ty<'_> { use rustc_hir::*; match self.kind { - TyKind::Never => Never, + TyKind::Never => Primitive(PrimitiveType::Never), TyKind::Ptr(ref m) => RawPointer(m.mutbl, box m.ty.clean(cx)), TyKind::Rptr(ref l, ref m) => { // There are two times a `Fresh` lifetime can be created: @@ -1402,7 +1402,7 @@ impl<'tcx> Clean for Ty<'tcx> { trace!("cleaning type: {:?}", self); let ty = normalize(cx, self).unwrap_or(self); match *ty.kind() { - ty::Never => Never, + ty::Never => Primitive(PrimitiveType::Never), ty::Bool => Primitive(PrimitiveType::Bool), ty::Char => Primitive(PrimitiveType::Char), ty::Int(int_ty) => Primitive(int_ty.into()), @@ -1440,12 +1440,12 @@ impl<'tcx> Clean for Ty<'tcx> { }; inline::record_extern_fqn(cx, did, kind); let path = external_path(cx, did, false, vec![], substs); - ResolvedPath { path, did, is_generic: false } + ResolvedPath { path, did } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); let path = external_path(cx, did, false, vec![], InternalSubsts::empty()); - ResolvedPath { path, did, is_generic: false } + ResolvedPath { path, did } } ty::Dynamic(ref obj, ref reg) => { // HACK: pick the first `did` as the `did` of the trait object. Someone @@ -1471,7 +1471,7 @@ impl<'tcx> Clean for Ty<'tcx> { let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); let bound = PolyTrait { - trait_: ResolvedPath { path, did, is_generic: false }, + trait_: ResolvedPath { path, did }, generic_params: Vec::new(), }; bounds.push(bound); @@ -1488,10 +1488,7 @@ impl<'tcx> Clean for Ty<'tcx> { let path = external_path(cx, did, false, bindings, substs); bounds.insert( 0, - PolyTrait { - trait_: ResolvedPath { path, did, is_generic: false }, - generic_params: Vec::new(), - }, + PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() }, ); DynTrait(bounds, lifetime) @@ -1976,7 +1973,7 @@ fn clean_extern_crate( def_id: crate_def_id.into(), visibility: krate.vis.clean(cx), kind: box ExternCrateItem { src: orig_name }, - cfg: attrs.cfg(cx.sess()), + cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), }] } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index d139b19f5dc43..257af6ab91016 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -11,8 +11,7 @@ //! This module attempts to reconstruct the original where and/or parameter //! bounds by special casing scenarios such as these. Fun! -use std::collections::BTreeMap; - +use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use rustc_middle::ty; use rustc_span::Symbol; @@ -23,8 +22,11 @@ use crate::clean::WherePredicate as WP; use crate::core::DocContext; crate fn where_clauses(cx: &DocContext<'_>, clauses: Vec) -> Vec { - // First, partition the where clause into its separate components - let mut params: BTreeMap<_, (Vec<_>, Vec<_>)> = BTreeMap::new(); + // First, partition the where clause into its separate components. + // + // We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to + // the order of the generated bounds. + let mut params: FxIndexMap, Vec<_>)> = FxIndexMap::default(); let mut lifetimes = Vec::new(); let mut equalities = Vec::new(); let mut tybounds = Vec::new(); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index d23941d77ba4f..5b722175f988c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -230,8 +230,7 @@ impl ExternalCrate { }; if root.is_local() { tcx.hir() - .krate() - .module() + .root_module() .item_ids .iter() .filter_map(|&id| { @@ -297,8 +296,7 @@ impl ExternalCrate { if root.is_local() { tcx.hir() - .krate() - .module() + .root_module() .item_ids .iter() .filter_map(|&id| { @@ -423,7 +421,7 @@ impl Item { kind, box ast_attrs.clean(cx), cx, - ast_attrs.cfg(cx.sess()), + ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), ) } @@ -749,7 +747,7 @@ crate trait AttributesExt { fn other_attrs(&self) -> Vec; - fn cfg(&self, sess: &Session) -> Option>; + fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option>; } impl AttributesExt for [ast::Attribute] { @@ -774,8 +772,41 @@ impl AttributesExt for [ast::Attribute] { self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() } - fn cfg(&self, sess: &Session) -> Option> { - let mut cfg = Cfg::True; + fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option> { + let sess = tcx.sess; + let doc_cfg_active = tcx.features().doc_cfg; + + fn single(it: T) -> Option { + let mut iter = it.into_iter(); + let item = iter.next()?; + if iter.next().is_some() { + return None; + } + Some(item) + } + + let mut cfg = if doc_cfg_active { + let mut doc_cfg = self + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new)) + .filter(|attr| attr.has_name(sym::cfg)) + .peekable(); + if doc_cfg.peek().is_some() { + doc_cfg + .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } else { + self.iter() + .filter(|attr| attr.has_name(sym::cfg)) + .filter_map(|attr| single(attr.meta_item_list()?)) + .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) + .filter(|cfg| !hidden_cfg.contains(cfg)) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } + } else { + Cfg::True + }; for attr in self.iter() { // #[doc] @@ -802,6 +833,8 @@ impl AttributesExt for [ast::Attribute] { } } + // treat #[target_feature(enable = "feat")] attributes as if they were + // #[doc(cfg(target_feature = "feat"))] attributes as well for attr in self.lists(sym::target_feature) { if attr.has_name(sym::enable) { if let Some(feat) = attr.value_str() { @@ -908,18 +941,10 @@ impl<'a> FromIterator<&'a DocFragment> for String { } } -/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`, -/// as well as doc comments. -#[derive(Clone, Debug, Default)] -crate struct Attributes { - crate doc_strings: Vec, - crate other_attrs: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] /// A link that has not yet been rendered. /// /// This link will be turned into a rendered link by [`Item::links`]. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] crate struct ItemLink { /// The original link written in the markdown pub(crate) link: String, @@ -944,6 +969,14 @@ pub struct RenderedLink { pub(crate) href: String, } +/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`, +/// as well as doc comments. +#[derive(Clone, Debug, Default)] +crate struct Attributes { + crate doc_strings: Vec, + crate other_attrs: Vec, +} + impl Attributes { crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> { self.other_attrs.lists(name) @@ -1114,10 +1147,7 @@ impl GenericBound { let path = external_path(cx, did, false, vec![], empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( - PolyTrait { - trait_: ResolvedPath { path, did, is_generic: false }, - generic_params: Vec::new(), - }, + PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() }, hir::TraitBoundModifier::Maybe, ) } @@ -1384,8 +1414,6 @@ crate enum Type { ResolvedPath { path: Path, did: DefId, - /// `true` if is a `T::Name` path for associated types. - is_generic: bool, }, /// `dyn for<'a> Trait<'a> + Send + 'static` DynTrait(Vec, Option), @@ -1401,7 +1429,6 @@ crate enum Type { Slice(Box), /// The `String` field is about the size or the constant representing the array's length. Array(Box, String), - Never, RawPointer(Mutability, Box), BorrowedRef { lifetime: Option, @@ -1424,37 +1451,6 @@ crate enum Type { ImplTrait(Vec), } -#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] -/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't -/// paths, like `Unit`. -crate enum PrimitiveType { - Isize, - I8, - I16, - I32, - I64, - I128, - Usize, - U8, - U16, - U32, - U64, - U128, - F32, - F64, - Char, - Bool, - Str, - Slice, - Array, - Tuple, - Unit, - RawPointer, - Reference, - Fn, - Never, -} - crate trait GetDefId { /// Use this method to get the [`DefId`] of a [`clean`] AST node. /// This will return [`None`] when called on a primitive [`clean::Type`]. @@ -1498,14 +1494,14 @@ impl Type { } RawPointer(..) => Some(PrimitiveType::RawPointer), BareFunction(..) => Some(PrimitiveType::Fn), - Never => Some(PrimitiveType::Never), _ => None, } } - crate fn is_generic(&self) -> bool { - match *self { - ResolvedPath { is_generic, .. } => is_generic, + /// Checks if this is a `T::Name` path for an associated type. + crate fn is_assoc_ty(&self) -> bool { + match self { + ResolvedPath { path, .. } => path.is_assoc_ty(), _ => false, } } @@ -1569,9 +1565,7 @@ impl Type { }; Some((&self_, trait_did, *name)) } -} -impl Type { fn inner_def_id(&self, cache: Option<&Cache>) -> Option { let t: PrimitiveType = match *self { ResolvedPath { did, .. } => return Some(did), @@ -1587,7 +1581,6 @@ impl Type { } } BareFunction(..) => PrimitiveType::Fn, - Never => PrimitiveType::Never, Slice(..) => PrimitiveType::Slice, Array(..) => PrimitiveType::Array, RawPointer(..) => PrimitiveType::RawPointer, @@ -1608,6 +1601,37 @@ impl GetDefId for Type { } } +/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't +/// paths, like `Unit`. +#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)] +crate enum PrimitiveType { + Isize, + I8, + I16, + I32, + I64, + I128, + Usize, + U8, + U16, + U32, + U64, + U128, + F32, + F64, + Char, + Bool, + Str, + Slice, + Array, + Tuple, + Unit, + RawPointer, + Reference, + Fn, + Never, +} + impl PrimitiveType { crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType { use ast::{FloatTy, IntTy, UintTy}; @@ -1994,6 +2018,16 @@ impl Path { String::from(if self.global { "::" } else { "" }) + &self.segments.iter().map(|s| s.name.to_string()).collect::>().join("::") } + + /// Checks if this is a `T::Name` path for an associated type. + crate fn is_assoc_ty(&self) -> bool { + match self.res { + Res::SelfTy(..) if self.segments.len() != 1 => true, + Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true, + Res::Def(DefKind::AssocTy, _) => true, + _ => false, + } + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b0021d1234cd6..2a05787e40cf9 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -26,8 +26,7 @@ mod tests; crate fn krate(cx: &mut DocContext<'_>) -> Crate { use crate::visit_lib::LibEmbargoVisitor; - let krate = cx.tcx.hir().krate(); - let module = crate::visit_ast::RustdocVisitor::new(cx).visit(krate); + let module = crate::visit_ast::RustdocVisitor::new(cx).visit(); let mut externs = Vec::new(); for &cnum in cx.tcx.crates(()).iter() { @@ -159,9 +158,7 @@ pub(super) fn external_path( crate fn strip_type(ty: Type) -> Type { match ty { - Type::ResolvedPath { path, did, is_generic } => { - Type::ResolvedPath { path: strip_path(&path), did, is_generic } - } + Type::ResolvedPath { path, did } => Type::ResolvedPath { path: strip_path(&path), did }, Type::DynTrait(mut bounds, lt) => { let first = bounds.remove(0); let stripped_trait = strip_type(first.trait_); @@ -404,19 +401,15 @@ crate fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String { crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { debug!("resolve_type({:?})", path); - let is_generic = match path.res { - Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)), - Res::SelfTy(..) if path.segments.len() == 1 => { - return Generic(kw::SelfUpper); - } - Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => { - return Generic(path.segments[0].name); + match path.res { + Res::PrimTy(p) => Primitive(PrimitiveType::from(p)), + Res::SelfTy(..) if path.segments.len() == 1 => Generic(kw::SelfUpper), + Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name), + _ => { + let did = register_res(cx, path.res); + ResolvedPath { path, did } } - Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true, - _ => false, - }; - let did = register_res(cx, path.res); - ResolvedPath { path, did, is_generic } + } } crate fn get_auto_trait_and_blanket_impls( diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index ddbe68762ee04..074744b3d11e2 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -25,6 +25,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use std::cell::RefCell; +use std::lazy::SyncLazy; use std::mem; use std::rc::Rc; @@ -271,9 +272,8 @@ crate fn create_config( providers.typeck_item_bodies = |_, _| {}; // hack so that `used_trait_imports` won't try to call typeck providers.used_trait_imports = |_, _| { - lazy_static! { - static ref EMPTY_SET: FxHashSet = FxHashSet::default(); - } + static EMPTY_SET: SyncLazy> = + SyncLazy::new(FxHashSet::default); &EMPTY_SET }; // In case typeck does end up being called, don't ICE in case there were name resolution errors diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index ac760fad103c1..9e64d200b4373 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -853,6 +853,7 @@ impl Collector { fn generate_name(&self, line: usize, filename: &FileName) -> String { let mut item_path = self.names.join("::"); + item_path.retain(|c| c != ' '); if !item_path.is_empty() { item_path.push(' '); } @@ -1122,7 +1123,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { let ast_attrs = self.tcx.hir().attrs(hir_id); let mut attrs = Attributes::from_ast(ast_attrs, None); - if let Some(ref cfg) = ast_attrs.cfg(self.sess) { + if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 56d2ca57218c5..302fc5a677771 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -1,4 +1,4 @@ -use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground}; +use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; use crate::rustc_span::edition::Edition; use std::fs; use std::path::Path; @@ -39,14 +39,32 @@ impl ExternalHtml { let bc = format!( "{}{}", bc, - Markdown(&m_bc, &[], id_map, codes, edition, playground).into_string() + Markdown { + content: &m_bc, + links: &[], + ids: id_map, + error_codes: codes, + edition, + playground, + heading_offset: HeadingOffset::H2, + } + .into_string() ); let ac = load_external_files(after_content, diag)?; let m_ac = load_external_files(md_after_content, diag)?; let ac = format!( "{}{}", ac, - Markdown(&m_ac, &[], id_map, codes, edition, playground).into_string() + Markdown { + content: &m_ac, + links: &[], + ids: id_map, + error_codes: codes, + edition, + playground, + heading_offset: HeadingOffset::H2, + } + .into_string() ); Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac }) } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index bcfcc3d70395c..cc9e081add199 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -119,6 +119,8 @@ crate struct Cache { /// /// Links are indexed by the DefId of the item they document. crate intra_doc_links: FxHashMap>, + /// Cfg that have been hidden via #![doc(cfg_hide(...))] + crate hidden_cfg: FxHashSet, } /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 2fde0017dc80c..bcd78b2adc085 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -752,15 +752,18 @@ fn fmt_type<'cx>( match *t { clean::Generic(name) => write!(f, "{}", name), - clean::ResolvedPath { did, ref path, is_generic } => { + clean::ResolvedPath { did, ref path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. - resolved_path(f, did, path, is_generic, use_absolute, cx) + resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx) } clean::DynTrait(ref bounds, ref lt) => { f.write_str("dyn ")?; fmt::Display::fmt(&tybounds(bounds, lt, cx), f) } clean::Infer => write!(f, "_"), + clean::Primitive(clean::PrimitiveType::Never) => { + primitive_link(f, PrimitiveType::Never, "!", cx) + } clean::Primitive(prim) => primitive_link(f, prim, &*prim.as_sym().as_str(), cx), clean::BareFunction(ref decl) => { if f.alternate() { @@ -819,34 +822,22 @@ fn fmt_type<'cx>( primitive_link(f, PrimitiveType::Array, &format!("; {}]", Escape(n)), cx) } } - clean::Never => primitive_link(f, PrimitiveType::Never, "!", cx), clean::RawPointer(m, ref t) => { let m = match m { hir::Mutability::Mut => "mut", hir::Mutability::Not => "const", }; - match **t { - clean::Generic(_) | clean::ResolvedPath { is_generic: true, .. } => { - if f.alternate() { - primitive_link( - f, - clean::PrimitiveType::RawPointer, - &format!("*{} {:#}", m, t.print(cx)), - cx, - ) - } else { - primitive_link( - f, - clean::PrimitiveType::RawPointer, - &format!("*{} {}", m, t.print(cx)), - cx, - ) - } - } - _ => { - primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?; - fmt::Display::fmt(&t.print(cx), f) - } + + if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() { + let text = if f.alternate() { + format!("*{} {:#}", m, t.print(cx)) + } else { + format!("*{} {}", m, t.print(cx)) + }; + primitive_link(f, clean::PrimitiveType::RawPointer, &text, cx) + } else { + primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?; + fmt::Display::fmt(&t.print(cx), f) } } clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index ece3ee640e2a6..43d1b8f794c30 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -9,8 +9,8 @@ use crate::clean::PrimitiveType; use crate::html::escape::Escape; use crate::html::render::Context; +use std::collections::VecDeque; use std::fmt::{Display, Write}; -use std::iter::Peekable; use rustc_lexer::{LiteralKind, TokenKind}; use rustc_span::edition::Edition; @@ -201,10 +201,57 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) }) } +/// This iterator comes from the same idea than "Peekable" except that it allows to "peek" more than +/// just the next item by using `peek_next`. The `peek` method always returns the next item after +/// the current one whereas `peek_next` will return the next item after the last one peeked. +/// +/// You can use both `peek` and `peek_next` at the same time without problem. +struct PeekIter<'a> { + stored: VecDeque<(TokenKind, &'a str)>, + /// This position is reinitialized when using `next`. It is used in `peek_next`. + peek_pos: usize, + iter: TokenIter<'a>, +} + +impl PeekIter<'a> { + fn new(iter: TokenIter<'a>) -> Self { + Self { stored: VecDeque::new(), peek_pos: 0, iter } + } + /// Returns the next item after the current one. It doesn't interfer with `peek_next` output. + fn peek(&mut self) -> Option<&(TokenKind, &'a str)> { + if self.stored.is_empty() { + if let Some(next) = self.iter.next() { + self.stored.push_back(next); + } + } + self.stored.front() + } + /// Returns the next item after the last one peeked. It doesn't interfer with `peek` output. + fn peek_next(&mut self) -> Option<&(TokenKind, &'a str)> { + self.peek_pos += 1; + if self.peek_pos - 1 < self.stored.len() { + self.stored.get(self.peek_pos - 1) + } else if let Some(next) = self.iter.next() { + self.stored.push_back(next); + self.stored.back() + } else { + None + } + } +} + +impl Iterator for PeekIter<'a> { + type Item = (TokenKind, &'a str); + fn next(&mut self) -> Option { + self.peek_pos = 0; + if let Some(first) = self.stored.pop_front() { Some(first) } else { self.iter.next() } + } +} + /// Processes program tokens, classifying strings of text by highlighting /// category (`Class`). struct Classifier<'a> { - tokens: Peekable>, + tokens: PeekIter<'a>, in_attribute: bool, in_macro: bool, in_macro_nonterminal: bool, @@ -218,7 +265,7 @@ impl<'a> Classifier<'a> { /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code /// file span which will be used later on by the `span_correspondance_map`. fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> { - let tokens = TokenIter { src }.peekable(); + let tokens = PeekIter::new(TokenIter { src }); Classifier { tokens, in_attribute: false, @@ -369,7 +416,7 @@ impl<'a> Classifier<'a> { // Assume that '&' or '*' is the reference or dereference operator // or a reference or pointer type. Unless, of course, it looks like // a logical and or a multiplication operator: `&&` or `* `. - TokenKind::Star => match lookahead { + TokenKind::Star => match self.peek() { Some(TokenKind::Whitespace) => Class::Op, _ => Class::RefKeyWord, }, @@ -480,6 +527,9 @@ impl<'a> Classifier<'a> { None => match text { "Option" | "Result" => Class::PreludeTy, "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, + // "union" is a weak keyword and is only considered as a keyword when declaring + // a union type. + "union" if self.check_if_is_union_keyword() => Class::KeyWord, _ if self.in_macro_nonterminal => { self.in_macro_nonterminal = false; Class::MacroNonTerminal @@ -500,7 +550,17 @@ impl<'a> Classifier<'a> { } fn peek(&mut self) -> Option { - self.tokens.peek().map(|(toke_kind, _text)| *toke_kind) + self.tokens.peek().map(|(token_kind, _text)| *token_kind) + } + + fn check_if_is_union_keyword(&mut self) -> bool { + while let Some(kind) = self.tokens.peek_next().map(|(token_kind, _text)| token_kind) { + if *kind == TokenKind::Whitespace { + continue; + } + return *kind == TokenKind::Ident; + } + false } } diff --git a/src/librustdoc/html/highlight/fixtures/union.html b/src/librustdoc/html/highlight/fixtures/union.html new file mode 100644 index 0000000000000..c0acf31a05d08 --- /dev/null +++ b/src/librustdoc/html/highlight/fixtures/union.html @@ -0,0 +1,8 @@ +union Foo { + i: i8, + u: i8, +} + +fn main() { + let union = 0; +} diff --git a/src/librustdoc/html/highlight/fixtures/union.rs b/src/librustdoc/html/highlight/fixtures/union.rs new file mode 100644 index 0000000000000..269ee115d3f8f --- /dev/null +++ b/src/librustdoc/html/highlight/fixtures/union.rs @@ -0,0 +1,8 @@ +union Foo { + i: i8, + u: i8, +} + +fn main() { + let union = 0; +} diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 68592ae96c187..450bbfea1ea86 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -54,3 +54,13 @@ let y = Self::whatever;"; expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner()); }); } + +#[test] +fn test_union_highlighting() { + create_default_session_globals_then(|| { + let src = include_str!("fixtures/union.rs"); + let mut html = Buffer::new(); + write_code(&mut html, src, Edition::Edition2018, None); + expect_file!["fixtures/union.html"].assert_eq(&html.into_inner()); + }); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c971e231463cd..9f2e282fce1c3 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -8,11 +8,19 @@ //! extern crate rustc_span; //! //! use rustc_span::edition::Edition; -//! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes}; +//! use rustdoc::html::markdown::{HeadingOffset, IdMap, Markdown, ErrorCodes}; //! //! let s = "My *markdown* _text_"; //! let mut id_map = IdMap::new(); -//! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None); +//! let md = Markdown { +//! content: s, +//! links: &[], +//! ids: &mut id_map, +//! error_codes: ErrorCodes::Yes, +//! edition: Edition::Edition2015, +//! playground: &None, +//! heading_offset: HeadingOffset::H2, +//! }; //! let html = md.into_string(); //! // ... something using html //! ``` @@ -47,6 +55,8 @@ use pulldown_cmark::{ #[cfg(test)] mod tests; +const MAX_HEADER_LEVEL: u32 = 6; + /// Options for rendering Markdown in the main body of documentation. pub(crate) fn main_body_opts() -> Options { Options::ENABLE_TABLES @@ -65,20 +75,33 @@ pub(crate) fn summary_opts() -> Options { | Options::ENABLE_SMART_PUNCTUATION } +#[derive(Debug, Clone, Copy)] +pub enum HeadingOffset { + H1 = 0, + H2, + H3, + H4, + H5, + H6, +} + /// When `to_string` is called, this struct will emit the HTML corresponding to /// the rendered version of the contained markdown string. -pub struct Markdown<'a>( - pub &'a str, +pub struct Markdown<'a> { + pub content: &'a str, /// A list of link replacements. - pub &'a [RenderedLink], + pub links: &'a [RenderedLink], /// The current list of used header IDs. - pub &'a mut IdMap, + pub ids: &'a mut IdMap, /// Whether to allow the use of explicit error codes in doctest lang strings. - pub ErrorCodes, + pub error_codes: ErrorCodes, /// Default edition to use when parsing doctests (to add a `fn main`). - pub Edition, - pub &'a Option, -); + pub edition: Edition, + pub playground: &'a Option, + /// Offset at which we render headings. + /// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `

`. + pub heading_offset: HeadingOffset, +} /// A tuple struct like `Markdown` that renders the markdown with a table of contents. crate struct MarkdownWithToc<'a>( crate &'a str, @@ -489,11 +512,17 @@ struct HeadingLinks<'a, 'b, 'ids, I> { toc: Option<&'b mut TocBuilder>, buf: VecDeque>, id_map: &'ids mut IdMap, + heading_offset: HeadingOffset, } impl<'a, 'b, 'ids, I> HeadingLinks<'a, 'b, 'ids, I> { - fn new(iter: I, toc: Option<&'b mut TocBuilder>, ids: &'ids mut IdMap) -> Self { - HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids } + fn new( + iter: I, + toc: Option<&'b mut TocBuilder>, + ids: &'ids mut IdMap, + heading_offset: HeadingOffset, + ) -> Self { + HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids, heading_offset } } } @@ -530,6 +559,7 @@ impl<'a, 'b, 'ids, I: Iterator>> Iterator self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0)); } + let level = std::cmp::min(level + (self.heading_offset as u32), MAX_HEADER_LEVEL); self.buf.push_back((Event::Html(format!("", level).into()), 0..0)); let start_tags = format!( @@ -1005,7 +1035,15 @@ impl LangString { impl Markdown<'_> { pub fn into_string(self) -> String { - let Markdown(md, links, mut ids, codes, edition, playground) = self; + let Markdown { + content: md, + links, + mut ids, + error_codes: codes, + edition, + playground, + heading_offset, + } = self; // This is actually common enough to special-case if md.is_empty() { @@ -1026,7 +1064,7 @@ impl Markdown<'_> { let mut s = String::with_capacity(md.len() * 3 / 2); - let p = HeadingLinks::new(p, None, &mut ids); + let p = HeadingLinks::new(p, None, &mut ids, heading_offset); let p = Footnotes::new(p); let p = LinkReplacer::new(p.map(|(ev, _)| ev), links); let p = TableWrapper::new(p); @@ -1048,7 +1086,7 @@ impl MarkdownWithToc<'_> { let mut toc = TocBuilder::new(); { - let p = HeadingLinks::new(p, Some(&mut toc), &mut ids); + let p = HeadingLinks::new(p, Some(&mut toc), &mut ids, HeadingOffset::H1); let p = Footnotes::new(p); let p = TableWrapper::new(p.map(|(ev, _)| ev)); let p = CodeBlocks::new(p, codes, edition, playground); @@ -1077,7 +1115,7 @@ impl MarkdownHtml<'_> { let mut s = String::with_capacity(md.len() * 3 / 2); - let p = HeadingLinks::new(p, None, &mut ids); + let p = HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1); let p = Footnotes::new(p); let p = TableWrapper::new(p.map(|(ev, _)| ev)); let p = CodeBlocks::new(p, codes, edition, playground); @@ -1295,7 +1333,7 @@ crate fn markdown_links(md: &str) -> Vec { // There's no need to thread an IdMap through to here because // the IDs generated aren't going to be emitted anywhere. let mut ids = IdMap::new(); - let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids)); + let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1)); for ev in iter { if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 { @@ -1316,8 +1354,7 @@ crate struct RustCodeBlock { /// The range in the markdown that the code within the code block occupies. crate code: Range, crate is_fenced: bool, - crate syntax: Option, - crate is_ignore: bool, + crate lang_string: LangString, } /// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or @@ -1333,7 +1370,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec { let syntax = syntax.as_ref(); let lang_string = if syntax.is_empty() { @@ -1344,8 +1381,6 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec (offset.start, offset.end), Some((_, sub_offset)) => { @@ -1354,8 +1389,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec) -> Vec) -> Vec { // The ending of the offset goes too far sometime so we reduce it by one in // these cases. if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") { ( - None, + LangString::default(), offset.start, offset.end, Range { start: offset.start, end: offset.end - 1 }, false, - false, ) } else { - (None, offset.start, offset.end, offset, false, false) + (LangString::default(), offset.start, offset.end, offset, false) } } }; @@ -1398,8 +1430,7 @@ crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> VecFoo bar

", + "

Foo bar

", ); t( "## Foo-bar_baz qux", - "

\ - Foo-bar_baz qux

", + "

\ + Foo-bar_baz qux

", ); t( "### **Foo** *bar* baz!?!& -_qux_-%", - "

\ + "

\ Foo \ bar baz!?!& -qux-%\ -

", + ", ); t( "#### **Foo?** & \\*bar?!* _`baz`_ ❤ #qux", - "

\ + "

\ Foo? & *bar?!* \ baz ❤ #qux\ -
", + ", ); } @@ -181,40 +189,48 @@ fn test_header() { fn test_header_ids_multiple_blocks() { let mut map = IdMap::new(); fn t(map: &mut IdMap, input: &str, expect: &str) { - let output = - Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); + let output = Markdown { + content: input, + links: &[], + ids: map, + error_codes: ErrorCodes::Yes, + edition: DEFAULT_EDITION, + playground: &None, + heading_offset: HeadingOffset::H2, + } + .into_string(); assert_eq!(output, expect, "original: {}", input); } t( &mut map, "# Example", - "

Example

", + "

Example

", ); t( &mut map, "# Panics", - "

Panics

", + "

Panics

", ); t( &mut map, "# Example", - "

Example

", + "

Example

", ); t( &mut map, "# Main", - "

Main

", + "

Main

", ); t( &mut map, "# Example", - "

Example

", + "

Example

", ); t( &mut map, "# Panics", - "

Panics

", + "

Panics

", ); } diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 1c083522beaa9..edd1d8b98fc64 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -244,7 +244,6 @@ fn get_index_type_name(clean_type: &clean::Type, accept_generic: bool) -> Option | clean::Tuple(_) | clean::Slice(_) | clean::Array(_, _) - | clean::Never | clean::RawPointer(_, _) | clean::QPath { .. } | clean::Infer diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 1f27357f6c6ea..11682afdf899b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -67,7 +67,7 @@ use crate::html::format::{ href, print_abi_with_space, print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace, }; -use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine}; +use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine}; /// A pair of name and its optional document. crate type NameDoc = (String, Option); @@ -470,32 +470,45 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result, item: &clean::Item, parent: Option<&clean::Item>) { +fn document( + w: &mut Buffer, + cx: &Context<'_>, + item: &clean::Item, + parent: Option<&clean::Item>, + heading_offset: HeadingOffset, +) { if let Some(ref name) = item.name { info!("Documenting {}", name); } document_item_info(w, cx, item, parent); if parent.is_none() { - document_full_collapsible(w, item, cx); + document_full_collapsible(w, item, cx, heading_offset); } else { - document_full(w, item, cx); + document_full(w, item, cx, heading_offset); } } /// Render md_text as markdown. -fn render_markdown(w: &mut Buffer, cx: &Context<'_>, md_text: &str, links: Vec) { +fn render_markdown( + w: &mut Buffer, + cx: &Context<'_>, + md_text: &str, + links: Vec, + heading_offset: HeadingOffset, +) { let mut ids = cx.id_map.borrow_mut(); write!( w, "
{}
", - Markdown( - md_text, - &links, - &mut ids, - cx.shared.codes, - cx.shared.edition(), - &cx.shared.playground - ) + Markdown { + content: md_text, + links: &links, + ids: &mut ids, + error_codes: cx.shared.codes, + edition: cx.shared.edition(), + playground: &cx.shared.playground, + heading_offset, + } .into_string() ) } @@ -531,15 +544,31 @@ fn document_short( } } -fn document_full_collapsible(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) { - document_full_inner(w, item, cx, true); +fn document_full_collapsible( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + heading_offset: HeadingOffset, +) { + document_full_inner(w, item, cx, true, heading_offset); } -fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) { - document_full_inner(w, item, cx, false); +fn document_full( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + heading_offset: HeadingOffset, +) { + document_full_inner(w, item, cx, false, heading_offset); } -fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_collapsible: bool) { +fn document_full_inner( + w: &mut Buffer, + item: &clean::Item, + cx: &Context<'_>, + is_collapsible: bool, + heading_offset: HeadingOffset, +) { if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) { debug!("Doc block: =====\n{}\n=====", s); if is_collapsible { @@ -549,10 +578,10 @@ fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_ Expand description\ ", ); - render_markdown(w, cx, &s, item.links(cx)); + render_markdown(w, cx, &s, item.links(cx), heading_offset); w.write_str(""); } else { - render_markdown(w, cx, &s, item.links(cx)); + render_markdown(w, cx, &s, item.links(cx), heading_offset); } } } @@ -599,14 +628,14 @@ fn short_item_info( let mut extra_info = vec![]; let error_codes = cx.shared.codes; - if let Some(Deprecation { note, since, is_since_rustc_version, suggestion: _ }) = + if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) = item.deprecation(cx.tcx()) { // We display deprecation messages for #[deprecated] and #[rustc_deprecated] // but only display the future-deprecation messages for #[rustc_deprecated]. let mut message = if let Some(since) = since { let since = &since.as_str(); - if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) { + if !stability::deprecation_in_effect(&depr) { if *since == "TBD" { String::from("Deprecating in a future Rust version") } else { @@ -1321,7 +1350,7 @@ fn render_impl( // because impls can't have a stability. if item.doc_value().is_some() { document_item_info(&mut info_buffer, cx, it, Some(parent)); - document_full(&mut doc_buffer, item, cx); + document_full(&mut doc_buffer, item, cx, HeadingOffset::H5); short_documented = false; } else { // In case the item isn't documented, @@ -1339,7 +1368,7 @@ fn render_impl( } else { document_item_info(&mut info_buffer, cx, item, Some(parent)); if rendering_params.show_def_docs { - document_full(&mut doc_buffer, item, cx); + document_full(&mut doc_buffer, item, cx, HeadingOffset::H5); short_documented = false; } } @@ -1573,14 +1602,15 @@ fn render_impl( write!( w, "
{}
", - Markdown( - &*dox, - &i.impl_item.links(cx), - &mut ids, - cx.shared.codes, - cx.shared.edition(), - &cx.shared.playground - ) + Markdown { + content: &*dox, + links: &i.impl_item.links(cx), + ids: &mut ids, + error_codes: cx.shared.codes, + edition: cx.shared.edition(), + playground: &cx.shared.playground, + heading_offset: HeadingOffset::H2 + } .into_string() ); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 3104cb3a3dd01..cab3fca708b2e 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -30,10 +30,12 @@ use crate::html::format::{ }; use crate::html::highlight; use crate::html::layout::Page; -use crate::html::markdown::MarkdownSummaryLine; +use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; const ITEM_TABLE_OPEN: &'static str = "
"; const ITEM_TABLE_CLOSE: &'static str = "
"; +const ITEM_TABLE_ROW_OPEN: &'static str = "
"; +const ITEM_TABLE_ROW_CLOSE: &'static str = "
"; pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, page: &Page<'_>) { debug_assert!(!item.is_stripped()); @@ -173,7 +175,7 @@ fn toggle_close(w: &mut Buffer) { } fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) { - document(w, cx, item, None); + document(w, cx, item, None, HeadingOffset::H2); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>(); @@ -256,9 +258,6 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl debug!("{:?}", indices); let mut curty = None; - // See: https://github.com/rust-lang/rust/issues/88545 - let item_table_block_size = 900usize; - let mut item_table_nth_element = 0usize; for &idx in &indices { let myitem = &items[idx]; @@ -285,13 +284,13 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl id = cx.derive_id(short.to_owned()), name = name ); - item_table_nth_element = 0; } match *myitem.kind { clean::ExternCrateItem { ref src } => { use crate::html::format::anchor; + w.write_str(ITEM_TABLE_ROW_OPEN); match *src { Some(ref src) => write!( w, @@ -312,6 +311,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl ), } w.write_str(""); + w.write_str(ITEM_TABLE_ROW_CLOSE); } clean::ImportItem(ref import) => { @@ -323,7 +323,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let import_item = clean::Item { def_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.sess()), + cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg), ..myitem.clone() }; @@ -336,6 +336,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let add = if stab.is_some() { " " } else { "" }; + w.write_str(ITEM_TABLE_ROW_OPEN); write!( w, "
\ @@ -348,6 +349,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl imp = import.print(cx), stab_tags = stab_tags.unwrap_or_default(), ); + w.write_str(ITEM_TABLE_ROW_CLOSE); } _ => { @@ -368,6 +370,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let add = if stab.is_some() { " " } else { "" }; let doc_value = myitem.doc_value().unwrap_or_default(); + w.write_str(ITEM_TABLE_ROW_OPEN); write!( w, "
\ @@ -390,15 +393,9 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl .collect::>() .join(" "), ); + w.write_str(ITEM_TABLE_ROW_CLOSE); } } - - item_table_nth_element += 1; - if item_table_nth_element > item_table_block_size { - w.write_str(ITEM_TABLE_CLOSE); - w.write_str(ITEM_TABLE_OPEN); - item_table_nth_element = 0; - } } if curty.is_some() { @@ -418,10 +415,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> // The trailing space after each tag is to space it properly against the rest of the docs. if let Some(depr) = &item.deprecation(tcx) { let mut message = "Deprecated"; - if !stability::deprecation_in_effect( - depr.is_since_rustc_version, - depr.since.map(|s| s.as_str()).as_deref(), - ) { + if !stability::deprecation_in_effect(depr) { message = "Deprecation planned"; } tags += &tag_html("deprecated", "", message); @@ -488,7 +482,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: notable_traits = notable_traits_decl(&f.decl, cx), ); }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { @@ -611,7 +605,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra }); // Trait documentation - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { write!( @@ -629,7 +623,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); let mut content = Buffer::empty_from(w); - document(&mut content, cx, m, Some(t)); + document(&mut content, cx, m, Some(t), HeadingOffset::H5); let toggled = !content.is_empty(); if toggled { write!(w, "
"); @@ -712,11 +706,10 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra let mut implementor_dups: FxHashMap = FxHashMap::default(); for implementor in implementors { match implementor.inner_impl().for_ { - clean::ResolvedPath { ref path, did, is_generic: false, .. } + clean::ResolvedPath { ref path, did, .. } | clean::BorrowedRef { - type_: box clean::ResolvedPath { ref path, did, is_generic: false, .. }, - .. - } => { + type_: box clean::ResolvedPath { ref path, did, .. }, .. + } if !path.is_assoc_ty() => { let &mut (prev_did, ref mut has_duplicates) = implementor_dups.entry(path.last()).or_insert((did, false)); if prev_did != did { @@ -844,7 +837,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -866,7 +859,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean: ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -897,7 +890,7 @@ fn item_typedef( ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); let def_id = it.def_id.expect_def_id(); // Render any items associated directly to this alias, as otherwise they @@ -915,7 +908,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni }); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); let mut fields = s .fields @@ -948,7 +941,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni if let Some(stability_class) = field.stability_class(cx.tcx()) { write!(w, "", stab = stability_class); } - document(w, cx, field, Some(it)); + document(w, cx, field, Some(it), HeadingOffset::H2); } } let def_id = it.def_id.expect_def_id(); @@ -1030,7 +1023,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum }); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); if !e.variants.is_empty() { write!( @@ -1059,7 +1052,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum w.write_str(""); render_stability_since(w, variant, it, cx.tcx()); w.write_str("
"); - document(w, cx, variant, Some(it)); + document(w, cx, variant, Some(it), HeadingOffset::H2); document_non_exhaustive(w, variant); use crate::clean::Variant; @@ -1099,7 +1092,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum f = field.name.as_ref().unwrap(), t = ty.print(cx) ); - document(w, cx, field, Some(variant)); + document(w, cx, field, Some(variant), HeadingOffset::H2); } _ => unreachable!(), } @@ -1126,7 +1119,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac None, ); }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) { @@ -1156,11 +1149,11 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean }); } } - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All) } @@ -1199,7 +1192,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean:: } }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) { @@ -1210,7 +1203,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St }); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); let mut fields = s .fields @@ -1246,7 +1239,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St name = field_name, ty = ty.print(cx) ); - document(w, cx, field, Some(it)); + document(w, cx, field, Some(it), HeadingOffset::H2); } } } @@ -1267,7 +1260,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St typ = s.type_.print(cx) ); }); - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { @@ -1282,13 +1275,13 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { ); }); - document(w, cx, it, None); + document(w, cx, it, None, HeadingOffset::H2); render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All) } fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) { - document(w, cx, it, None) + document(w, cx, it, None, HeadingOffset::H2) } /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order). @@ -1410,11 +1403,12 @@ fn render_implementor( // If there's already another implementor that has the same abridged name, use the // full path, for example in `std::iter::ExactSizeIterator` let use_absolute = match implementor.inner_impl().for_ { - clean::ResolvedPath { ref path, is_generic: false, .. } - | clean::BorrowedRef { - type_: box clean::ResolvedPath { ref path, is_generic: false, .. }, - .. - } => implementor_dups[&path.last()].1, + clean::ResolvedPath { ref path, .. } + | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path, .. }, .. } + if !path.is_assoc_ty() => + { + implementor_dups[&path.last()].1 + } _ => false, }; render_impl( diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index eb7cc9309f416..5d33681847a41 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -126,7 +126,7 @@ h2 { h3 { font-size: 1.3em; } -h1, h2, h3, h4 { +h1, h2, h3, h4, h5, h6 { font-weight: 500; margin: 20px 0 15px 0; padding-bottom: 6px; @@ -179,7 +179,7 @@ div.impl-items > div { padding-left: 0; } -h1, h2, h3, h4, +h1, h2, h3, h4, h5, h6, .sidebar, a.source, .search-input, .search-results .result-name, .content table td:first-child > a, .item-left > a, @@ -501,21 +501,20 @@ nav.sub { white-space: pre-wrap; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom: 1px solid; } -.top-doc .docblock h1 { font-size: 1.3em; } -.top-doc .docblock h2 { font-size: 1.15em; } -.top-doc .docblock h3, +.top-doc .docblock h2 { font-size: 1.3em; } +.top-doc .docblock h3 { font-size: 1.15em; } .top-doc .docblock h4, -.top-doc .docblock h5 { +.top-doc .docblock h5, +.top-doc .docblock h6 { font-size: 1em; } -.docblock h1 { font-size: 1em; } -.docblock h2 { font-size: 0.95em; } -.docblock h3, .docblock h4, .docblock h5 { font-size: 0.9em; } +.docblock h5 { font-size: 1em; } +.docblock h6 { font-size: 0.95em; } .docblock { margin-left: 24px; @@ -773,22 +772,18 @@ h2.small-section-header > .anchor { .block a.current.crate { font-weight: 500; } .item-table { - display: grid; - column-gap: 1.2rem; - row-gap: 0.0rem; - grid-template-columns: auto 1fr; + display: table-row; /* align content left */ justify-items: start; } - +.item-row { + display: table-row; +} .item-left, .item-right { - display: block; + display: table-cell; } .item-left { - grid-column: 1; -} -.item-right { - grid-column: 2; + padding-right: 1.2rem; } .search-container { @@ -1891,6 +1886,9 @@ details.undocumented[open] > summary::before { /* Display an alternating layout on tablets and phones */ .item-table { + display: block; + } + .item-row { display: flex; flex-flow: column wrap; } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index c79801e830876..0fd6462a8f5dd 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -136,7 +136,7 @@ pre, .rustdoc.source .example-wrap { border-right: 1px solid #ffb44c; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom-color: #5c6773; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index d2e54070acd68..d863701dd73c7 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -93,7 +93,7 @@ pre, .rustdoc.source .example-wrap { background-color: #0a042f !important; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom-color: #DDD; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 25d810560c146..28d2e99a3d073 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -93,7 +93,7 @@ pre, .rustdoc.source .example-wrap { background-color: #f6fdb0 !important; } -.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { +.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 { border-bottom-color: #ddd; } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f8ea7a499b234..731fc4ff3ce00 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -218,6 +218,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)), MacroItem(m) => ItemEnum::Macro(m.source), ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)), + PrimitiveItem(p) => ItemEnum::PrimitiveType(p.as_sym().to_string()), AssocConstItem(t, s) => ItemEnum::AssocConst { type_: t.into_tcx(tcx), default: s }, AssocTypeItem(g, t) => ItemEnum::AssocType { bounds: g.into_iter().map(|x| x.into_tcx(tcx)).collect(), @@ -225,7 +226,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { }, // `convert_item` early returns `None` for striped items StrippedItem(_) => unreachable!(), - PrimitiveItem(_) | KeywordItem(_) => { + KeywordItem(_) => { panic!("{:?} is not supported for JSON output", item) } ExternCrateItem { ref src } => ItemEnum::ExternCrate { @@ -387,7 +388,7 @@ impl FromWithTcx for Type { fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { use clean::Type::*; match ty { - ResolvedPath { path, did, is_generic: _ } => Type::ResolvedPath { + ResolvedPath { path, did } => Type::ResolvedPath { name: path.whole_name(), id: from_item_id(did.into()), args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))), @@ -417,13 +418,13 @@ impl FromWithTcx for Type { } } Generic(s) => Type::Generic(s.to_string()), + Primitive(clean::PrimitiveType::Never) => Type::Never, Primitive(p) => Type::Primitive(p.as_sym().to_string()), BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()), Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s }, ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()), - Never => Type::Never, Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { mutable: mutability == ast::Mutability::Mut, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 5089cc30a1e39..040a880ace947 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -69,7 +69,21 @@ impl JsonRenderer<'tcx> { .iter() .filter_map(|i| { let item = &i.impl_item; - if item.def_id.is_local() { + + // HACK(hkmatsumoto): For impls of primitive types, we index them + // regardless of whether they're local. This is because users can + // document primitive items in an arbitrary crate by using + // `doc(primitive)`. + let mut is_primitive_impl = false; + if let clean::types::ItemKind::ImplItem(ref impl_) = *item.kind { + if impl_.trait_.is_none() { + if let clean::types::Type::Primitive(_) = impl_.for_ { + is_primitive_impl = true; + } + } + } + + if item.def_id.is_local() || is_primitive_impl { self.item(item.clone()).unwrap(); Some(from_item_id(item.def_id)) } else { @@ -169,6 +183,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { s.impls = self.get_impls(id.expect_def_id()) } else if let types::ItemEnum::Enum(ref mut e) = new_item.inner { e.impls = self.get_impls(id.expect_def_id()) + } else if let types::ItemEnum::Union(ref mut u) = new_item.inner { + u.impls = self.get_impls(id.expect_def_id()) } let removed = self.index.borrow_mut().insert(from_item_id(id), new_item.clone()); @@ -189,6 +205,11 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { fn after_krate(&mut self) -> Result<(), Error> { debug!("Done with crate"); + + for primitive in Rc::clone(&self.cache).primitive_locations.values() { + self.get_impls(primitive.clone()); + } + let mut index = (*self.index).clone().into_inner(); index.extend(self.get_trait_items()); // This needs to be the default HashMap for compatibility with the public interface for @@ -234,7 +255,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { ) }) .collect(), - format_version: 7, + format_version: 8, }; let mut p = self.out_path.clone(); p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5cfd21046f5d7..ff0a6ef6cb74f 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -15,11 +15,10 @@ #![feature(never_type)] #![feature(once_cell)] #![feature(type_ascription)] +#![feature(iter_intersperse)] #![recursion_limit = "256"] #![warn(rustc::internal)] -#[macro_use] -extern crate lazy_static; #[macro_use] extern crate tracing; diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 2ae4897dc3496..47b24d40edc27 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -10,7 +10,9 @@ use crate::config::{Options, RenderOptions}; use crate::doctest::{Collector, TestOptions}; use crate::html::escape::Escape; use crate::html::markdown; -use crate::html::markdown::{find_testable_code, ErrorCodes, IdMap, Markdown, MarkdownWithToc}; +use crate::html::markdown::{ + find_testable_code, ErrorCodes, HeadingOffset, IdMap, Markdown, MarkdownWithToc, +}; /// Separate any lines at the start of the file that begin with `# ` or `%`. fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { @@ -70,7 +72,16 @@ crate fn render>( let text = if !options.markdown_no_toc { MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string() } else { - Markdown(text, &[], &mut ids, error_codes, edition, &playground).into_string() + Markdown { + content: text, + links: &[], + ids: &mut ids, + error_codes, + edition, + playground: &playground, + heading_offset: HeadingOffset::H1, + } + .into_string() }; let err = write!( diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 721af3313d27f..5e3bd41b85c7e 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -2,7 +2,7 @@ use crate::clean; use crate::core::DocContext; use crate::fold::{self, DocFolder}; use crate::html::markdown::{find_testable_code, ErrorCodes}; -use crate::passes::doc_test_lints::{should_have_doc_example, Tests}; +use crate::passes::check_doc_test_visibility::{should_have_doc_example, Tests}; use crate::passes::Pass; use rustc_hir as hir; use rustc_lint::builtin::MISSING_DOCS; diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index c9f66d096f06c..d2b3c5239c778 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -4,7 +4,7 @@ use rustc_middle::lint::LintDiagnosticBuilder; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{FileName, InnerSpan}; +use rustc_span::{hygiene::AstPass, ExpnData, ExpnKind, FileName, InnerSpan, DUMMY_SP}; use crate::clean; use crate::core::DocContext; @@ -36,12 +36,22 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { let source = dox[code_block.code].to_owned(); let sess = ParseSess::with_span_handler(handler, sm); + let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition()); + let expn_data = ExpnData::default( + ExpnKind::AstPass(AstPass::TestHarness), + DUMMY_SP, + edition, + None, + None, + ); + let span = DUMMY_SP.fresh_expansion(expn_data, self.cx.tcx.create_stable_hashing_context()); + let is_empty = rustc_driver::catch_fatal_errors(|| { parse_stream_from_source_str( FileName::Custom(String::from("doctest")), source, &sess, - None, + Some(span), ) .is_empty() }) @@ -61,8 +71,8 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { }; let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id); - let empty_block = code_block.syntax.is_none() && code_block.is_fenced; - let is_ignore = code_block.is_ignore; + let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; + let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; // The span and whether it is precise or not. let (sp, precise_span) = match super::source_span_for_markdown_range( diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/check_doc_test_visibility.rs similarity index 90% rename from src/librustdoc/passes/doc_test_lints.rs rename to src/librustdoc/passes/check_doc_test_visibility.rs index 279d0dbda82ee..1f7d6054233dd 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -1,6 +1,6 @@ //! This pass is overloaded and runs two different lints. //! -//! - MISSING_DOC_CODE_EXAMPLES: this lint is **UNSTABLE** and looks for public items missing doctests +//! - MISSING_DOC_CODE_EXAMPLES: this lint is **UNSTABLE** and looks for public items missing doctests. //! - PRIVATE_DOC_TESTS: this lint is **STABLE** and looks for private items with doctests. use super::Pass; @@ -15,23 +15,23 @@ use rustc_middle::lint::LintLevelSource; use rustc_session::lint; use rustc_span::symbol::sym; -crate const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { - name: "check-private-items-doc-tests", - run: check_private_items_doc_tests, - description: "check private items doc tests", +crate const CHECK_DOC_TEST_VISIBILITY: Pass = Pass { + name: "check_doc_test_visibility", + run: check_doc_test_visibility, + description: "run various visibility-related lints on doctests", }; -struct PrivateItemDocTestLinter<'a, 'tcx> { +struct DocTestVisibilityLinter<'a, 'tcx> { cx: &'a mut DocContext<'tcx>, } -crate fn check_private_items_doc_tests(krate: Crate, cx: &mut DocContext<'_>) -> Crate { - let mut coll = PrivateItemDocTestLinter { cx }; +crate fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) -> Crate { + let mut coll = DocTestVisibilityLinter { cx }; coll.fold_crate(krate) } -impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> { +impl<'a, 'tcx> DocFolder for DocTestVisibilityLinter<'a, 'tcx> { fn fold_item(&mut self, item: Item) -> Option { let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 3edd96a3364db..318c897bcbdf6 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -759,7 +759,7 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) - let mut resolver = cx.resolver.borrow_mut(); let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| { resolver.access(|resolver| { - let parent_scope = &ParentScope::module(resolver.get_module(module), resolver); + let parent_scope = &ParentScope::module(resolver.expect_module(module), resolver); resolver .traits_in_scope(None, parent_scope, SyntaxContext::root(), None) .into_iter() diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index a0144a5298eba..a3fde92d7655d 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -52,7 +52,7 @@ fn drop_tag( continue; } let last_tag_name_low = last_tag_name.to_lowercase(); - if ALLOWED_UNCLOSED.iter().any(|&at| at == last_tag_name_low) { + if ALLOWED_UNCLOSED.contains(&last_tag_name_low.as_str()) { continue; } // `tags` is used as a queue, meaning that everything after `pos` is included inside it. @@ -207,7 +207,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { for (tag, range) in tags.iter().filter(|(t, _)| { let t = t.to_lowercase(); - ALLOWED_UNCLOSED.iter().find(|&&at| at == t).is_none() + !ALLOWED_UNCLOSED.contains(&t.as_str()) }) { report_diag(&format!("unclosed HTML tag `{}`", tag), range); } diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 0e86fe45640f8..99ac87db4ff3f 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -33,8 +33,8 @@ crate use self::propagate_doc_cfg::PROPAGATE_DOC_CFG; crate mod collect_intra_doc_links; crate use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; -mod doc_test_lints; -crate use self::doc_test_lints::CHECK_PRIVATE_ITEMS_DOC_TESTS; +mod check_doc_test_visibility; +crate use self::check_doc_test_visibility::CHECK_DOC_TEST_VISIBILITY; mod collect_trait_impls; crate use self::collect_trait_impls::COLLECT_TRAIT_IMPLS; @@ -79,7 +79,7 @@ crate enum Condition { /// The full list of passes. crate const PASSES: &[Pass] = &[ - CHECK_PRIVATE_ITEMS_DOC_TESTS, + CHECK_DOC_TEST_VISIBILITY, STRIP_HIDDEN, UNINDENT_COMMENTS, STRIP_PRIVATE, @@ -97,7 +97,7 @@ crate const PASSES: &[Pass] = &[ crate const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::always(COLLECT_TRAIT_IMPLS), ConditionalPass::always(UNINDENT_COMMENTS), - ConditionalPass::always(CHECK_PRIVATE_ITEMS_DOC_TESTS), + ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index a93880453ba27..90300dbd16b13 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -128,7 +128,7 @@ impl<'a> DocFolder for ImplStripper<'a> { return None; } if let Some(did) = imp.for_.def_id() { - if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did.into()) + if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into()) { debug!("ImplStripper: impl item for stripped type; removing"); return None; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 897b9140fc8bc..36b1a14f6c1ea 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -6,6 +6,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::Node; +use rustc_hir::CRATE_HIR_ID; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; use rustc_span; @@ -15,7 +16,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; -use crate::clean::{self, AttributesExt, NestedAttributesExt}; +use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt}; use crate::core; use crate::doctree::*; @@ -71,12 +72,12 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did)); } - crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> { - let span = krate.module().inner; + crate fn visit(mut self) -> Module<'tcx> { + let span = self.cx.tcx.def_span(CRATE_DEF_ID); let mut top_level_module = self.visit_mod_contents( &Spanned { span, node: hir::VisibilityKind::Public }, hir::CRATE_HIR_ID, - &krate.module(), + self.cx.tcx.hir().root_module(), self.cx.tcx.crate_name(LOCAL_CRATE), ); @@ -97,6 +98,31 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } } + + self.cx.cache.hidden_cfg = self + .cx + .tcx + .hir() + .attrs(CRATE_HIR_ID) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) + .filter(|attr| attr.has_name(sym::cfg_hide)) + .flat_map(|attr| { + attr.meta_item_list() + .unwrap_or(&[]) + .iter() + .filter_map(|attr| { + Some( + Cfg::parse(attr.meta_item()?) + .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) + .ok()?, + ) + }) + .collect::>() + }) + .collect(); + self.cx.cache.exact_paths = self.exact_paths; top_level_module } diff --git a/src/llvm-project b/src/llvm-project index 86c7daa627aef..a7348ae0df3c7 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 86c7daa627aefda1371568b948eba21edf720747 +Subproject commit a7348ae0df3c71581dbe3d355fc0fb6ce6332dd0 diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 37cdc94441df7..22debd296c236 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -221,6 +221,8 @@ pub enum ItemEnum { Macro(String), ProcMacro(ProcMacro), + PrimitiveType(String), + AssocConst { #[serde(rename = "type")] type_: Type, diff --git a/src/test/assembly/asm/aarch64-outline-atomics.rs b/src/test/assembly/asm/aarch64-outline-atomics.rs new file mode 100644 index 0000000000000..93dda712e1b9b --- /dev/null +++ b/src/test/assembly/asm/aarch64-outline-atomics.rs @@ -0,0 +1,16 @@ +// min-llvm-version: 12.0 +// assembly-output: emit-asm +// compile-flags: -O +// compile-flags: --target aarch64-unknown-linux-gnu +// needs-llvm-components: aarch64 +// only-aarch64 + +#![crate_type = "rlib"] + +use std::sync::atomic::{AtomicI32, Ordering::*}; + +pub fn compare_exchange(a: &AtomicI32) { + // On AArch64 LLVM should outline atomic operations. + // CHECK: __aarch64_cas4_relax + let _ = a.compare_exchange(0, 10, Relaxed, Relaxed); +} diff --git a/src/test/assembly/pic-relocation-model.rs b/src/test/assembly/pic-relocation-model.rs new file mode 100644 index 0000000000000..72471ffcdb0cb --- /dev/null +++ b/src/test/assembly/pic-relocation-model.rs @@ -0,0 +1,35 @@ +// revisions: x64 +// assembly-output: emit-asm +// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pic +// [x64] needs-llvm-components: x86 + + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type="rlib"] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +// CHECK-LABEL: call_other_fn: +// CHECK: {{(jmpq|callq)}} *other_fn@GOTPCREL(%rip) +#[no_mangle] +pub fn call_other_fn() -> u8 { + unsafe { + other_fn() + } +} + +// CHECK-LABEL: other_fn: +// CHECK: callq *foreign_fn@GOTPCREL(%rip) +#[no_mangle] +#[inline(never)] +pub fn other_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +extern "C" {fn foreign_fn() -> u8;} diff --git a/src/test/assembly/pie-relocation-model.rs b/src/test/assembly/pie-relocation-model.rs new file mode 100644 index 0000000000000..e40797e038d4b --- /dev/null +++ b/src/test/assembly/pie-relocation-model.rs @@ -0,0 +1,38 @@ +// revisions: x64 +// assembly-output: emit-asm +// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pie +// [x64] needs-llvm-components: x86 + + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type="rlib"] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +// CHECK-LABEL: call_other_fn: +// With PIE local functions are called "directly". +// CHECK: {{(jmp|callq)}} other_fn +#[no_mangle] +pub fn call_other_fn() -> u8 { + unsafe { + other_fn() + } +} + +// CHECK-LABEL: other_fn: +// External functions are still called through GOT, since we don't know if the symbol +// is defined in the binary or in the shared library. +// CHECK: callq *foreign_fn@GOTPCREL(%rip) +#[no_mangle] +#[inline(never)] +pub fn other_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +extern "C" {fn foreign_fn() -> u8;} diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index 8b0448ec47085..c73d2a10a967b 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -1,9 +1,10 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/extern-drop-glue +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus -Copt-level=0 #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/extern-generic.rs b/src/test/codegen-units/partitioning/extern-generic.rs index c96df6e102ac3..638ec079a0bce 100644 --- a/src/test/codegen-units/partitioning/extern-generic.rs +++ b/src/test/codegen-units/partitioning/extern-generic.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y +// incremental +// compile-flags:-Zprint-mono-items=eager -Zshare-generics=y #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/incremental-merging.rs b/src/test/codegen-units/partitioning/incremental-merging.rs index 91ae602293198..118b7bdf4da8b 100644 --- a/src/test/codegen-units/partitioning/incremental-merging.rs +++ b/src/test/codegen-units/partitioning/incremental-merging.rs @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/incremental-merging +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Ccodegen-units=3 #![crate_type = "rlib"] diff --git a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs index b86e325537b81..1cc21632e4818 100644 --- a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/inlining-from-extern-crate +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index 78d69fdb7d814..2fd853a44b8ff 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -1,8 +1,9 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-drop-glue +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus -Copt-level=0 #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/local-generic.rs b/src/test/codegen-units/partitioning/local-generic.rs index 9a7743bbf4686..38aec7291df3f 100644 --- a/src/test/codegen-units/partitioning/local-generic.rs +++ b/src/test/codegen-units/partitioning/local-generic.rs @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/local-generic +// incremental +// compile-flags:-Zprint-mono-items=eager #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs index d53f7b6229132..318f0c28a5981 100644 --- a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs +++ b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining-but-not-all +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus=no #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index 1ea804b2f9d82..841a428e9dd2f 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index 56d108074e40d..03c37954d1513 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -1,7 +1,8 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-transitive-inlining +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus #![allow(dead_code)] diff --git a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs index e67090303a363..8220dc12ee0c6 100644 --- a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs +++ b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs @@ -4,9 +4,10 @@ // ignore-test // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/methods-are-with-self-type +// incremental +// compile-flags:-Zprint-mono-items=lazy #![allow(dead_code)] #![feature(start)] diff --git a/src/test/codegen-units/partitioning/regular-modules.rs b/src/test/codegen-units/partitioning/regular-modules.rs index f9b8f52b0bb9e..ce7fe9c3a4ff3 100644 --- a/src/test/codegen-units/partitioning/regular-modules.rs +++ b/src/test/codegen-units/partitioning/regular-modules.rs @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/regular-modules +// incremental +// compile-flags:-Zprint-mono-items=eager #![allow(dead_code)] #![crate_type="lib"] diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs index 17c1fbb2f739b..ebe96bfb746af 100644 --- a/src/test/codegen-units/partitioning/shared-generics.rs +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -2,7 +2,8 @@ // no-prefer-dynamic // NOTE: We always compile this test with -Copt-level=0 because higher opt-levels // prevent drop-glue from participating in share-generics. -// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Cincremental=tmp/partitioning-tests/shared-generics-exe -Copt-level=0 +// incremental +// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Copt-level=0 #![crate_type="rlib"] diff --git a/src/test/codegen-units/partitioning/statics.rs b/src/test/codegen-units/partitioning/statics.rs index 02d6467577f4c..b11d6696dc00a 100644 --- a/src/test/codegen-units/partitioning/statics.rs +++ b/src/test/codegen-units/partitioning/statics.rs @@ -1,6 +1,7 @@ -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/statics +// incremental +// compile-flags:-Zprint-mono-items=lazy #![crate_type="rlib"] diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index f6ae46b0551c2..cedcca804b365 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -1,8 +1,9 @@ // -// We specify -C incremental here because we want to test the partitioning for +// We specify incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/vtable-through-const +// incremental +// compile-flags:-Zprint-mono-items=lazy // compile-flags:-Zinline-in-all-cgus // This test case makes sure, that references made through constants are diff --git a/src/test/codegen/alloc-optimisation.rs b/src/test/codegen/alloc-optimisation.rs index 5b27f3f45457d..aee93b93e3737 100644 --- a/src/test/codegen/alloc-optimisation.rs +++ b/src/test/codegen/alloc-optimisation.rs @@ -1,4 +1,5 @@ // +// no-system-llvm // min-llvm-version: 10.0.1 // compile-flags: -O #![crate_type="lib"] diff --git a/src/test/codegen/panic-in-drop-abort.rs b/src/test/codegen/panic-in-drop-abort.rs index 62d093507ddee..39f73c4e3967e 100644 --- a/src/test/codegen/panic-in-drop-abort.rs +++ b/src/test/codegen/panic-in-drop-abort.rs @@ -1,8 +1,17 @@ -// compile-flags: -Z panic-in-drop=abort -O +// compile-flags: -Z panic-in-drop=abort -O -Z new-llvm-pass-manager=no // Ensure that unwinding code paths are eliminated from the output after // optimization. +// This test uses -Z new-llvm-pass-manager=no, because the expected optimization does not happen +// on targets using SEH exceptions (i.e. MSVC) anymore. The core issue is that Rust promises that +// the drop_in_place() function can't unwind, but implements it in a way that *can*, because we +// currently go out of our way to allow longjmps, which also use the unwinding mechanism on MSVC +// targets. We should either forbid longjmps, or not assume nounwind, making this optimization +// incompatible with the current behavior of running cleanuppads on longjmp unwinding. + +// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output + #![crate_type = "lib"] use std::any::Any; use std::mem::forget; @@ -35,8 +44,6 @@ impl Drop for AssertNeverDrop { } } -// CHECK-LABEL: normal_drop -// CHECK-NOT: should_not_appear_in_output #[no_mangle] pub fn normal_drop(x: ExternDrop) { let guard = AssertNeverDrop; @@ -44,8 +51,6 @@ pub fn normal_drop(x: ExternDrop) { forget(guard); } -// CHECK-LABEL: indirect_drop -// CHECK-NOT: should_not_appear_in_output #[no_mangle] pub fn indirect_drop(x: Box) { let guard = AssertNeverDrop; diff --git a/src/test/codegen/pic-relocation-model.rs b/src/test/codegen/pic-relocation-model.rs new file mode 100644 index 0000000000000..6e1d5a6c3f271 --- /dev/null +++ b/src/test/codegen/pic-relocation-model.rs @@ -0,0 +1,16 @@ +// compile-flags: -C relocation-model=pic + +#![crate_type = "rlib"] + +// CHECK: define i8 @call_foreign_fn() +#[no_mangle] +pub fn call_foreign_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +// CHECK: declare zeroext i8 @foreign_fn() +extern "C" {fn foreign_fn() -> u8;} + +// CHECK: !{i32 7, !"PIC Level", i32 2} diff --git a/src/test/codegen/pie-relocation-model.rs b/src/test/codegen/pie-relocation-model.rs new file mode 100644 index 0000000000000..a843202a94f82 --- /dev/null +++ b/src/test/codegen/pie-relocation-model.rs @@ -0,0 +1,22 @@ +// compile-flags: -C relocation-model=pie +// only-x86_64-unknown-linux-gnu + +#![crate_type = "rlib"] + +// With PIE we know local functions cannot be interpositioned, we can mark them +// as dso_local. +// CHECK: define dso_local i8 @call_foreign_fn() +#[no_mangle] +pub fn call_foreign_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +// External functions are still marked as non-dso_local, since we don't know if the symbol +// is defined in the binary or in the shared library. +// CHECK: declare zeroext i8 @foreign_fn() +extern "C" {fn foreign_fn() -> u8;} + +// CHECK: !{i32 7, !"PIC Level", i32 2} +// CHECK: !{i32 7, !"PIE Level", i32 2} diff --git a/src/test/debuginfo/borrowed-struct.rs b/src/test/debuginfo/borrowed-struct.rs index 7f97d96b8db93..fe945266b13ca 100644 --- a/src/test/debuginfo/borrowed-struct.rs +++ b/src/test/debuginfo/borrowed-struct.rs @@ -63,7 +63,6 @@ // lldbr-check:(f64) *unique_val_interior_ref_2 = 26.5 #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -79,7 +78,7 @@ fn main() { let stack_val_interior_ref_2: &f64 = &stack_val.y; let ref_to_unnamed: &SomeStruct = &SomeStruct { x: 11, y: 24.5 }; - let unique_val: Box<_> = box SomeStruct { x: 13, y: 26.5 }; + let unique_val: Box<_> = Box::new(SomeStruct { x: 13, y: 26.5 }); let unique_val_ref: &SomeStruct = &*unique_val; let unique_val_interior_ref_1: &isize = &unique_val.x; let unique_val_interior_ref_2: &f64 = &unique_val.y; diff --git a/src/test/debuginfo/borrowed-tuple.rs b/src/test/debuginfo/borrowed-tuple.rs index be4895ef5363e..cc28e49c44745 100644 --- a/src/test/debuginfo/borrowed-tuple.rs +++ b/src/test/debuginfo/borrowed-tuple.rs @@ -37,7 +37,6 @@ #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -46,7 +45,7 @@ fn main() { let stack_val_ref: &(i16, f32) = &stack_val; let ref_to_unnamed: &(i16, f32) = &(-15, -20f32); - let unique_val: Box<(i16, f32)> = box (-17, -22f32); + let unique_val: Box<(i16, f32)> = Box::new((-17, -22f32)); let unique_val_ref: &(i16, f32) = &*unique_val; zzz(); // #break diff --git a/src/test/debuginfo/borrowed-unique-basic.rs b/src/test/debuginfo/borrowed-unique-basic.rs index f927a54f02aa6..b39f24e029e31 100644 --- a/src/test/debuginfo/borrowed-unique-basic.rs +++ b/src/test/debuginfo/borrowed-unique-basic.rs @@ -116,51 +116,50 @@ // lldbr-check:(f64) *f64_ref = 3.5 #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { - let bool_box: Box = box true; + let bool_box: Box = Box::new(true); let bool_ref: &bool = &*bool_box; - let int_box: Box = box -1; + let int_box: Box = Box::new(-1); let int_ref: &isize = &*int_box; - let char_box: Box = box 'a'; + let char_box: Box = Box::new('a'); let char_ref: &char = &*char_box; - let i8_box: Box = box 68; + let i8_box: Box = Box::new(68); let i8_ref: &i8 = &*i8_box; - let i16_box: Box = box -16; + let i16_box: Box = Box::new(-16); let i16_ref: &i16 = &*i16_box; - let i32_box: Box = box -32; + let i32_box: Box = Box::new(-32); let i32_ref: &i32 = &*i32_box; - let i64_box: Box = box -64; + let i64_box: Box = Box::new(-64); let i64_ref: &i64 = &*i64_box; - let uint_box: Box = box 1; + let uint_box: Box = Box::new(1); let uint_ref: &usize = &*uint_box; - let u8_box: Box = box 100; + let u8_box: Box = Box::new(100); let u8_ref: &u8 = &*u8_box; - let u16_box: Box = box 16; + let u16_box: Box = Box::new(16); let u16_ref: &u16 = &*u16_box; - let u32_box: Box = box 32; + let u32_box: Box = Box::new(32); let u32_ref: &u32 = &*u32_box; - let u64_box: Box = box 64; + let u64_box: Box = Box::new(64); let u64_ref: &u64 = &*u64_box; - let f32_box: Box = box 2.5; + let f32_box: Box = Box::new(2.5); let f32_ref: &f32 = &*f32_box; - let f64_box: Box = box 3.5; + let f64_box: Box = Box::new(3.5); let f64_ref: &f64 = &*f64_box; zzz(); // #break diff --git a/src/test/debuginfo/box.rs b/src/test/debuginfo/box.rs index e443b67ebfb31..3713c8c135d2e 100644 --- a/src/test/debuginfo/box.rs +++ b/src/test/debuginfo/box.rs @@ -24,13 +24,12 @@ // lldbr-check:((i32, f64)) *b = { 0 = 2 1 = 3.5 } #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] fn main() { - let a = box 1; - let b = box (2, 3.5f64); + let a = Box::new(1); + let b = Box::new((2, 3.5f64)); zzz(); // #break } diff --git a/src/test/debuginfo/boxed-struct.rs b/src/test/debuginfo/boxed-struct.rs index 155088c61fe31..64bc124756d6d 100644 --- a/src/test/debuginfo/boxed-struct.rs +++ b/src/test/debuginfo/boxed-struct.rs @@ -28,7 +28,6 @@ // lldbr-check:(boxed_struct::StructWithDestructor) *boxed_with_dtor = { x = 77 y = 777 z = 7777 w = 77777 } #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -52,9 +51,19 @@ impl Drop for StructWithDestructor { fn main() { - let boxed_with_padding: Box<_> = box StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }; - - let boxed_with_dtor: Box<_> = box StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }; + let boxed_with_padding: Box<_> = Box::new(StructWithSomePadding { + x: 99, + y: 999, + z: 9999, + w: 99999, + }); + + let boxed_with_dtor: Box<_> = Box::new(StructWithDestructor { + x: 77, + y: 777, + z: 7777, + w: 77777, + }); zzz(); // #break } diff --git a/src/test/debuginfo/closure-in-generic-function.rs b/src/test/debuginfo/closure-in-generic-function.rs index 239055b3a78b6..91d7ddc5416d8 100644 --- a/src/test/debuginfo/closure-in-generic-function.rs +++ b/src/test/debuginfo/closure-in-generic-function.rs @@ -39,7 +39,6 @@ // lldbr-check:(i32) *y = 110 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] diff --git a/src/test/debuginfo/destructured-fn-argument.rs b/src/test/debuginfo/destructured-fn-argument.rs index a776f51907158..9cd3874a5dfb7 100644 --- a/src/test/debuginfo/destructured-fn-argument.rs +++ b/src/test/debuginfo/destructured-fn-argument.rs @@ -358,7 +358,6 @@ #![allow(unused_variables)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -480,7 +479,7 @@ fn main() { managed_box(&(34, 35)); borrowed_pointer(&(36, 37)); contained_borrowed_pointer((&38, 39)); - unique_pointer(box (40, 41, 42)); + unique_pointer(Box::new((40, 41, 42))); ref_binding((43, 44, 45)); ref_binding_in_tuple((46, (47, 48))); ref_binding_in_struct(Struct { a: 49, b: 50 }); diff --git a/src/test/debuginfo/destructured-for-loop-variable.rs b/src/test/debuginfo/destructured-for-loop-variable.rs index 1532c83dfac3a..15cb88ef25d5b 100644 --- a/src/test/debuginfo/destructured-for-loop-variable.rs +++ b/src/test/debuginfo/destructured-for-loop-variable.rs @@ -173,7 +173,6 @@ #![allow(unused_variables)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -214,7 +213,7 @@ fn main() { y: -300001.5, z: true }, - box 854237.5); + Box::new(854237.5)); for &(v1, &Struct { x: x1, y: ref y1, z: z1 }, diff --git a/src/test/debuginfo/destructured-local.rs b/src/test/debuginfo/destructured-local.rs index 712168b5baa87..3a2a889777ea0 100644 --- a/src/test/debuginfo/destructured-local.rs +++ b/src/test/debuginfo/destructured-local.rs @@ -285,7 +285,6 @@ #![allow(unused_variables)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -345,7 +344,7 @@ fn main() { let (&cc, _) = (&38, 39); // unique pointer - let box dd = box (40, 41, 42); + let box dd = Box::new((40, 41, 42)); // ref binding let ref ee = (43, 44, 45); diff --git a/src/test/debuginfo/generic-method-on-generic-struct.rs b/src/test/debuginfo/generic-method-on-generic-struct.rs index 85fe8ac08f3c4..97609ef5d9341 100644 --- a/src/test/debuginfo/generic-method-on-generic-struct.rs +++ b/src/test/debuginfo/generic-method-on-generic-struct.rs @@ -123,7 +123,6 @@ // lldbr-check:(f32) arg2 = -10.5 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -155,7 +154,7 @@ fn main() { let _ = stack.self_by_ref(-1, 2_u16); let _ = stack.self_by_val(-3, -4_i16); - let owned: Box<_> = box Struct { x: 1234.5f64 }; + let owned: Box<_> = Box::new(Struct { x: 1234.5f64 }); let _ = owned.self_by_ref(-5, -6_i32); let _ = owned.self_by_val(-7, -8_i64); let _ = owned.self_owned(-9, -10.5_f32); diff --git a/src/test/debuginfo/method-on-enum.rs b/src/test/debuginfo/method-on-enum.rs index 80f4c2e1150ec..aaa9bd9d6f97a 100644 --- a/src/test/debuginfo/method-on-enum.rs +++ b/src/test/debuginfo/method-on-enum.rs @@ -107,7 +107,6 @@ // lldb-check:[...]$14 = -10 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -140,7 +139,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Enum::Variant1{ x: 1799, y: 1799 }; + let owned: Box<_> = Box::new(Enum::Variant1{ x: 1799, y: 1799 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/method-on-generic-struct.rs b/src/test/debuginfo/method-on-generic-struct.rs index 80cbf7430ca6e..bf047449164b0 100644 --- a/src/test/debuginfo/method-on-generic-struct.rs +++ b/src/test/debuginfo/method-on-generic-struct.rs @@ -123,8 +123,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -156,7 +154,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 1234.5f64 }; + let owned: Box<_> = Box::new(Struct { x: 1234.5f64 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/method-on-struct.rs b/src/test/debuginfo/method-on-struct.rs index c764cf6832378..deed4f9cc0ad9 100644 --- a/src/test/debuginfo/method-on-struct.rs +++ b/src/test/debuginfo/method-on-struct.rs @@ -121,8 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -154,7 +152,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 200 }; + let owned: Box<_> = Box::new(Struct { x: 200 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/method-on-trait.rs b/src/test/debuginfo/method-on-trait.rs index 6dcf28967776f..7ebebfa72b92b 100644 --- a/src/test/debuginfo/method-on-trait.rs +++ b/src/test/debuginfo/method-on-trait.rs @@ -121,8 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -160,7 +158,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 200 }; + let owned: Box<_> = Box::new(Struct { x: 200 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/method-on-tuple-struct.rs b/src/test/debuginfo/method-on-tuple-struct.rs index d06b606e973e8..a5a87b2ad6f26 100644 --- a/src/test/debuginfo/method-on-tuple-struct.rs +++ b/src/test/debuginfo/method-on-tuple-struct.rs @@ -121,8 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue - -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -152,7 +150,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box TupleStruct(200, -200.5); + let owned: Box<_> = Box::new(TupleStruct(200, -200.5)); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/recursive-struct.rs b/src/test/debuginfo/recursive-struct.rs index c0bd67367012f..eb14af8c588de 100644 --- a/src/test/debuginfo/recursive-struct.rs +++ b/src/test/debuginfo/recursive-struct.rs @@ -52,20 +52,20 @@ // gdb-command:print long_cycle4.value // gdb-check:$18 = 29.5 -// gdbr-command:print long_cycle_w_anonymous_types.value +// gdbr-command:print long_cycle_w_anon_types.value // gdb-check:$19 = 30 -// gdbr-command:print long_cycle_w_anonymous_types.next.val.value +// gdbr-command:print long_cycle_w_anon_types.next.val.value // gdb-check:$20 = 31 // gdb-command:continue #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] use self::Opt::{Empty, Val}; +use std::boxed::Box as B; enum Opt { Empty, @@ -120,75 +120,75 @@ struct LongCycleWithAnonymousTypes { fn main() { let stack_unique: UniqueNode = UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 1, - } + }) }, value: 0, }; - let unique_unique: Box> = box UniqueNode { + let unique_unique: Box> = Box::new(UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 3, - } + }) }, value: 2, - }; + }); let vec_unique: [UniqueNode; 1] = [UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 7.5, - } + }) }, value: 6.5, }]; let borrowed_unique: &UniqueNode = &UniqueNode { next: Val { - val: box UniqueNode { + val: Box::new(UniqueNode { next: Empty, value: 9.5, - } + }) }, value: 8.5, }; // LONG CYCLE let long_cycle1: LongCycle1 = LongCycle1 { - next: box LongCycle2 { - next: box LongCycle3 { - next: box LongCycle4 { + next: Box::new(LongCycle2 { + next: Box::new(LongCycle3 { + next: Box::new(LongCycle4 { next: None, value: 23, - }, + }), value: 22, - }, + }), value: 21 - }, + }), value: 20 }; let long_cycle2: LongCycle2 = LongCycle2 { - next: box LongCycle3 { - next: box LongCycle4 { + next: Box::new(LongCycle3 { + next: Box::new(LongCycle4 { next: None, value: 26, - }, + }), value: 25, - }, + }), value: 24 }; let long_cycle3: LongCycle3 = LongCycle3 { - next: box LongCycle4 { + next: Box::new(LongCycle4 { next: None, value: 28, - }, + }), value: 27, }; @@ -199,15 +199,15 @@ fn main() { // It's important that LongCycleWithAnonymousTypes is encountered only at the end of the // `box` chain. - let long_cycle_w_anonymous_types = box box box box box LongCycleWithAnonymousTypes { + let long_cycle_w_anon_types = B::new(B::new(B::new(B::new(B::new(LongCycleWithAnonymousTypes { next: Val { - val: box box box box box LongCycleWithAnonymousTypes { + val: Box::new(Box::new(Box::new(Box::new(Box::new(LongCycleWithAnonymousTypes { next: Empty, value: 31, - } + }))))) }, value: 30 - }; + }))))); zzz(); // #break } diff --git a/src/test/debuginfo/self-in-default-method.rs b/src/test/debuginfo/self-in-default-method.rs index e15c08577e15a..b8b5add0996aa 100644 --- a/src/test/debuginfo/self-in-default-method.rs +++ b/src/test/debuginfo/self-in-default-method.rs @@ -121,7 +121,6 @@ // lldbr-check:(isize) arg2 = -10 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -154,7 +153,7 @@ fn main() { let _ = stack.self_by_ref(-1, -2); let _ = stack.self_by_val(-3, -4); - let owned: Box<_> = box Struct { x: 200 }; + let owned: Box<_> = Box::new(Struct { x: 200 }); let _ = owned.self_by_ref(-5, -6); let _ = owned.self_by_val(-7, -8); let _ = owned.self_owned(-9, -10); diff --git a/src/test/debuginfo/self-in-generic-default-method.rs b/src/test/debuginfo/self-in-generic-default-method.rs index 7634e3247d591..efce449e312ed 100644 --- a/src/test/debuginfo/self-in-generic-default-method.rs +++ b/src/test/debuginfo/self-in-generic-default-method.rs @@ -121,7 +121,6 @@ // lldbr-check:(f32) arg2 = -10.5 // lldb-command:continue -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -155,7 +154,7 @@ fn main() { let _ = stack.self_by_ref(-1, 2_u16); let _ = stack.self_by_val(-3, -4_i16); - let owned: Box<_> = box Struct { x: 879 }; + let owned: Box<_> = Box::new(Struct { x: 879 }); let _ = owned.self_by_ref(-5, -6_i32); let _ = owned.self_by_val(-7, -8_i64); let _ = owned.self_owned(-9, -10.5_f32); diff --git a/src/test/debuginfo/trait-pointers.rs b/src/test/debuginfo/trait-pointers.rs index a44f30abd6859..e12daaf114e14 100644 --- a/src/test/debuginfo/trait-pointers.rs +++ b/src/test/debuginfo/trait-pointers.rs @@ -5,7 +5,6 @@ // lldb-command:run #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -24,5 +23,5 @@ impl Trait for Struct {} fn main() { let stack_struct = Struct { a:0, b: 1.0 }; let reference: &Trait = &stack_struct as &Trait; - let unique: Box = box Struct { a:2, b: 3.0 } as Box; + let unique: Box = Box::new(Struct { a:2, b: 3.0 }) as Box; } diff --git a/src/test/debuginfo/type-names.rs b/src/test/debuginfo/type-names.rs index 3497f0afb2cb0..2c10360fc924e 100644 --- a/src/test/debuginfo/type-names.rs +++ b/src/test/debuginfo/type-names.rs @@ -262,7 +262,6 @@ // cdb-check:struct ForeignType2 * foreign2 = [...] // cdb-check:struct ForeignType1 * foreign1 = [...] -#![feature(box_syntax)] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -373,8 +372,8 @@ fn main() { let tuple2 = ((Struct1, mod1::mod2::Struct3), mod1::Variant1, 'x'); // Box - let box1 = (box 1f32, 0i32); - let box2 = (box mod1::mod2::Variant2(1f32), 0i32); + let box1 = (Box::new(1f32), 0i32); + let box2 = (Box::new(mod1::mod2::Variant2(1f32)), 0i32); // References let ref1 = (&Struct1, 0i32); @@ -404,14 +403,14 @@ fn main() { let slice2 = &*vec2; // Trait Objects - let box_trait = (box 0_isize) as Box; + let box_trait = Box::new(0_isize) as Box; let ref_trait = &0_isize as &dyn Trait1; let mut mut_int1 = 0_isize; let mut_ref_trait = (&mut mut_int1) as &mut dyn Trait1; - let no_principal_trait = (box 0_isize) as Box<(dyn Send + Sync)>; + let no_principal_trait = Box::new(0_isize) as Box<(dyn Send + Sync)>; let has_associated_type_trait = &0_isize as &(dyn Trait3 + Send); - let generic_box_trait = (box 0_isize) as Box>; + let generic_box_trait = Box::new(0_isize) as Box>; let generic_ref_trait = (&0_isize) as &dyn Trait2; let mut generic_mut_ref_trait_impl = 0_isize; diff --git a/src/test/debuginfo/unique-enum.rs b/src/test/debuginfo/unique-enum.rs index 9d938b6e36919..d7dfaeefe2b77 100644 --- a/src/test/debuginfo/unique-enum.rs +++ b/src/test/debuginfo/unique-enum.rs @@ -32,7 +32,6 @@ // lldbr-check:(unique_enum::Univariant) *univariant = { TheOnlyCase = { = 123234 } } #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -59,15 +58,15 @@ fn main() { // 0b01111100011111000111110001111100 = 2088533116 // 0b0111110001111100 = 31868 // 0b01111100 = 124 - let the_a: Box<_> = box ABC::TheA { x: 0, y: 8970181431921507452 }; + let the_a: Box<_> = Box::new(ABC::TheA { x: 0, y: 8970181431921507452 }); // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441 // 0b00010001000100010001000100010001 = 286331153 // 0b0001000100010001 = 4369 // 0b00010001 = 17 - let the_b: Box<_> = box ABC::TheB (0, 286331153, 286331153); + let the_b: Box<_> = Box::new(ABC::TheB (0, 286331153, 286331153)); - let univariant: Box<_> = box Univariant::TheOnlyCase(123234); + let univariant: Box<_> = Box::new(Univariant::TheOnlyCase(123234)); zzz(); // #break } diff --git a/src/test/debuginfo/var-captured-in-nested-closure.rs b/src/test/debuginfo/var-captured-in-nested-closure.rs index a2778fc6090d2..d811915c38767 100644 --- a/src/test/debuginfo/var-captured-in-nested-closure.rs +++ b/src/test/debuginfo/var-captured-in-nested-closure.rs @@ -133,7 +133,6 @@ // cdb-check:closure_local : 8 [Type: [...]] #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -154,7 +153,7 @@ fn main() { }; let struct_ref = &a_struct; - let owned: Box<_> = box 6; + let owned: Box<_> = Box::new(6); let mut closure = || { let closure_local = 8; diff --git a/src/test/debuginfo/var-captured-in-sendable-closure.rs b/src/test/debuginfo/var-captured-in-sendable-closure.rs index bd7c2bfe2c3ff..39930e04e4c5f 100644 --- a/src/test/debuginfo/var-captured-in-sendable-closure.rs +++ b/src/test/debuginfo/var-captured-in-sendable-closure.rs @@ -34,7 +34,6 @@ // lldbr-check:(isize) *owned = 5 #![allow(unused_variables)] -#![feature(box_syntax)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -53,7 +52,7 @@ fn main() { c: 4 }; - let owned: Box<_> = box 5; + let owned: Box<_> = Box::new(5); let closure = move || { zzz(); // #break diff --git a/src/test/debuginfo/var-captured-in-stack-closure.rs b/src/test/debuginfo/var-captured-in-stack-closure.rs index 1bbb79c37a4e7..d68409a9d5205 100644 --- a/src/test/debuginfo/var-captured-in-stack-closure.rs +++ b/src/test/debuginfo/var-captured-in-stack-closure.rs @@ -115,7 +115,6 @@ // cdb-command: dx owned // cdb-check:owned : 0x[...] : 6 [Type: [...] *] -#![feature(box_syntax)] #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -137,7 +136,7 @@ fn main() { }; let struct_ref = &a_struct; - let owned: Box<_> = box 6; + let owned: Box<_> = Box::new(6); { let mut first_closure = || { diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index cfbd3a58637c0..c6187879ab0a9 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -3,64 +3,78 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/box_expr.rs:6:11: 6:11 let _1: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:9: 7:10 - let mut _2: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 - let _3: (); // in scope 0 at $DIR/box_expr.rs:8:5: 8:12 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:8:10: 8:11 + let mut _2: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _3: usize; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _4: *mut u8; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let mut _5: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:7:13: 7:25 + let _6: (); // in scope 0 at $DIR/box_expr.rs:8:5: 8:12 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/box_expr.rs:8:10: 8:11 scope 1 { debug x => _1; // in scope 1 at $DIR/box_expr.rs:7:9: 7:10 } + scope 2 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10 - StorageLive(_2); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - _2 = Box(S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - (*_2) = S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + _2 = SizeOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25 + _3 = AlignOf(S); // scope 2 at $DIR/box_expr.rs:7:13: 7:25 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/box_expr.rs:7:13: 7:25 // mir::Constant - // + span: $DIR/box_expr.rs:7:17: 7:23 - // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } + // + span: $DIR/box_expr.rs:7:13: 7:25 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - _1 = move _2; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - drop(_2) -> bb2; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + StorageLive(_5); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + _5 = ShallowInitBox(move _4, S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + (*_5) = S::new() -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + // mir::Constant + // + span: $DIR/box_expr.rs:7:17: 7:23 + // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } } bb2: { - StorageDead(_2); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 - StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 - StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _3 = std::mem::drop::>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + _1 = move _5; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + drop(_5) -> bb3; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + } + + bb3: { + StorageDead(_5); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + StorageLive(_6); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + StorageLive(_7); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 + _7 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 + _6 = std::mem::drop::>(move _7) -> [return: bb4, unwind: bb6]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 // + literal: Const { ty: fn(std::boxed::Box) {std::mem::drop::>}, val: Value(Scalar()) } } - bb3: { - StorageDead(_4); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 - StorageDead(_3); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 + bb4: { + StorageDead(_7); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 + StorageDead(_6); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 _0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2 - drop(_1) -> bb4; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_1) -> bb5; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb4: { + bb5: { StorageDead(_1); // scope 0 at $DIR/box_expr.rs:9:1: 9:2 return; // scope 0 at $DIR/box_expr.rs:9:2: 9:2 } - bb5 (cleanup): { - drop(_4) -> bb6; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 - } - bb6 (cleanup): { - drop(_1) -> bb8; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_7) -> bb7; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 } bb7 (cleanup): { - drop(_2) -> bb8; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + drop(_1) -> bb9; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } bb8 (cleanup): { + drop(_5) -> bb9; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + } + + bb9 (cleanup): { resume; // scope 0 at $DIR/box_expr.rs:6:1: 9:2 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir index a64c960b9f716..bec0fa9c04957 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir @@ -1,7 +1,7 @@ // MIR for `BAR::promoted[0]` after SimplifyCfg-elaborate-drops promoted[0] in BAR: &[&i32; 1] = { - let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 let mut _3: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 @@ -16,8 +16,8 @@ promoted[0] in BAR: &[&i32; 1] = { // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) } _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 49d0a7ff45503..bdd62f1029f51 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -3,21 +3,21 @@ static mut BAR: *const &i32 = { let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:9:17: 9:28 - let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 let _5: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 -+ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 ++ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 bb0: { - StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 - StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 - StorageLive(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 - _5 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34 -+ _6 = const BAR::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 ++ _6 = const BAR::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 // ty::Const - // + ty: &i32 - // + val: Value(Scalar(alloc1)) @@ -28,11 +28,11 @@ - // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) } - _4 = &(*_5); // scope 0 at $DIR/const-promotion-extern-static.rs:9:32: 9:34 - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 -- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 -+ // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35 +- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 ++ // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:44 + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[55e6]::BAR), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) } -+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 ++ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 + _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir index 8b3c5d332f251..c01b31525b6a6 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir @@ -1,7 +1,7 @@ // MIR for `FOO::promoted[0]` after SimplifyCfg-elaborate-drops promoted[0] in FOO: &[&i32; 1] = { - let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 let mut _3: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 @@ -16,8 +16,8 @@ promoted[0] in FOO: &[&i32; 1] = { // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) } _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:41: 13:43 _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + return; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index f2504ae880eab..94b337806aff8 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -3,23 +3,23 @@ static mut FOO: *const &i32 = { let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:13:17: 13:28 - let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 let _5: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 -+ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 ++ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 scope 1 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 - StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 - StorageLive(_5); // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 - _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 -+ _6 = const FOO::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 ++ _6 = const FOO::promoted[0]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 // ty::Const - // + ty: *const i32 - // + val: Value(Scalar(alloc3)) @@ -30,11 +30,11 @@ - // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) } - _4 = &(*_5); // scope 1 at $DIR/const-promotion-extern-static.rs:13:41: 13:43 - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 -- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 -+ // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46 +- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 ++ // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:55 + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[55e6]::FOO), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) } -+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 ++ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 + _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 _0 = core::slice::::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff index 9fcbd32ca686d..342c987343eac 100644 --- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff @@ -6,34 +6,51 @@ let _1: i32; // in scope 0 at $DIR/boxes.rs:12:9: 12:10 let mut _2: i32; // in scope 0 at $DIR/boxes.rs:12:13: 12:22 let mut _3: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _4: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _5: usize; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _6: *mut u8; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/boxes.rs:12:14: 12:22 scope 1 { debug x => _1; // in scope 1 at $DIR/boxes.rs:12:9: 12:10 } + scope 2 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/boxes.rs:12:9: 12:10 StorageLive(_2); // scope 0 at $DIR/boxes.rs:12:13: 12:22 StorageLive(_3); // scope 0 at $DIR/boxes.rs:12:14: 12:22 - StorageLive(_4); // scope 0 at $DIR/boxes.rs:12:14: 12:22 - _4 = Box(i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22 - (*_4) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21 - _3 = move _4; // scope 0 at $DIR/boxes.rs:12:14: 12:22 - StorageDead(_4); // scope 0 at $DIR/boxes.rs:12:21: 12:22 +- _4 = SizeOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22 +- _5 = AlignOf(i32); // scope 2 at $DIR/boxes.rs:12:14: 12:22 +- _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _4 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _5 = const 4_usize; // scope 2 at $DIR/boxes.rs:12:14: 12:22 ++ _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22 + // mir::Constant + // + span: $DIR/boxes.rs:12:14: 12:22 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } + } + + bb1: { + StorageLive(_7); // scope 0 at $DIR/boxes.rs:12:14: 12:22 + _7 = ShallowInitBox(move _6, i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22 + (*_7) = const 42_i32; // scope 0 at $DIR/boxes.rs:12:19: 12:21 + _3 = move _7; // scope 0 at $DIR/boxes.rs:12:14: 12:22 + StorageDead(_7); // scope 0 at $DIR/boxes.rs:12:21: 12:22 _2 = (*_3); // scope 0 at $DIR/boxes.rs:12:13: 12:22 _1 = Add(move _2, const 0_i32); // scope 0 at $DIR/boxes.rs:12:13: 12:26 StorageDead(_2); // scope 0 at $DIR/boxes.rs:12:25: 12:26 - drop(_3) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/boxes.rs:12:26: 12:27 + drop(_3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/boxes.rs:12:26: 12:27 } - bb1: { + bb2: { StorageDead(_3); // scope 0 at $DIR/boxes.rs:12:26: 12:27 nop; // scope 0 at $DIR/boxes.rs:11:11: 13:2 StorageDead(_1); // scope 0 at $DIR/boxes.rs:13:1: 13:2 return; // scope 0 at $DIR/boxes.rs:13:2: 13:2 } - bb2 (cleanup): { + bb3 (cleanup): { resume; // scope 0 at $DIR/boxes.rs:11:1: 13:2 } } diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index f305d602bbde1..dfb5b98d5c97c 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -12,6 +12,7 @@ let mut _7: usize; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 let mut _8: bool; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 let mut _9: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let mut _10: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 bb0: { StorageLive(_1); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 @@ -27,14 +28,16 @@ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _10 = _3; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 StorageDead(_3); // scope 0 at $DIR/slice_len.rs:5:18: 5:19 StorageLive(_6); // scope 0 at $DIR/slice_len.rs:5:31: 5:32 _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32 -- _7 = Len((*_2)); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageDead(_10); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - 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:5:5: 5:33 -+ _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:5:5: 5: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:5:5: 5:33 } diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index f305d602bbde1..dfb5b98d5c97c 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -12,6 +12,7 @@ let mut _7: usize; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 let mut _8: bool; // in scope 0 at $DIR/slice_len.rs:5:5: 5:33 let mut _9: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 + let mut _10: &[u32; 3]; // in scope 0 at $DIR/slice_len.rs:5:6: 5:19 bb0: { StorageLive(_1); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 @@ -27,14 +28,16 @@ // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + StorageLive(_10); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 + _10 = _3; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 StorageDead(_3); // scope 0 at $DIR/slice_len.rs:5:18: 5:19 StorageLive(_6); // scope 0 at $DIR/slice_len.rs:5:31: 5:32 _6 = const 1_usize; // scope 0 at $DIR/slice_len.rs:5:31: 5:32 -- _7 = Len((*_2)); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + StorageDead(_10); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 - 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:5:5: 5:33 -+ _7 = const 3_usize; // scope 0 at $DIR/slice_len.rs:5:5: 5:33 + _8 = const true; // scope 0 at $DIR/slice_len.rs:5:5: 5: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:5:5: 5:33 } diff --git a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff index 48a37a8496cb7..7695afded3da3 100644 --- a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff +++ b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff @@ -5,7 +5,7 @@ debug s => _1; // in scope 0 at $DIR/deduplicate_blocks.rs:2:36: 2:37 let mut _0: bool; // return place in scope 0 at $DIR/deduplicate_blocks.rs:2:48: 2:52 let mut _2: &[u8]; // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 - let mut _3: &str; // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:12 + let mut _3: &str; // in scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 let mut _4: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 let mut _5: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:5:9: 5:31 let mut _6: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:4:9: 4:37 @@ -19,8 +19,8 @@ bb0: { StorageLive(_2); // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 - StorageLive(_3); // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:12 - _3 = _1; // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:12 + StorageLive(_3); // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 + _3 = _1; // scope 0 at $DIR/deduplicate_blocks.rs:3:11: 3:23 StorageLive(_8); // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23 _8 = _3; // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23 - _2 = transmute::<&str, &[u8]>(move _8) -> bb14; // scope 2 at $DIR/deduplicate_blocks.rs:3:11: 3:23 diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index fd29e14a04161..000bc6343257b 100644 --- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -7,9 +7,9 @@ debug upper => _3; // in scope 0 at $DIR/funky_arms.rs:11:69: 11:74 let mut _0: std::result::Result<(), std::fmt::Error>; // return place in scope 0 at $DIR/funky_arms.rs:11:85: 11:91 let _4: bool; // in scope 0 at $DIR/funky_arms.rs:15:9: 15:19 - let mut _5: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:15:22: 15:25 + let mut _5: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:15:22: 15:37 let mut _7: std::option::Option; // in scope 0 at $DIR/funky_arms.rs:24:30: 24:45 - let mut _8: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:24:30: 24:33 + let mut _8: &std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:24:30: 24:45 let mut _9: isize; // in scope 0 at $DIR/funky_arms.rs:24:12: 24:27 let mut _11: &mut std::fmt::Formatter; // in scope 0 at $DIR/funky_arms.rs:26:43: 26:46 let mut _12: &T; // in scope 0 at $DIR/funky_arms.rs:26:48: 26:51 @@ -36,8 +36,8 @@ bb0: { StorageLive(_4); // scope 0 at $DIR/funky_arms.rs:15:9: 15:19 - StorageLive(_5); // scope 0 at $DIR/funky_arms.rs:15:22: 15:25 - _5 = &(*_1); // scope 0 at $DIR/funky_arms.rs:15:22: 15:25 + StorageLive(_5); // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 + _5 = &(*_1); // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 _4 = Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37 // mir::Constant // + span: $DIR/funky_arms.rs:15:26: 15:35 @@ -62,8 +62,8 @@ bb4: { StorageLive(_7); // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 - StorageLive(_8); // scope 2 at $DIR/funky_arms.rs:24:30: 24:33 - _8 = &(*_1); // scope 2 at $DIR/funky_arms.rs:24:30: 24:33 + StorageLive(_8); // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 + _8 = &(*_1); // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 _7 = Formatter::precision(move _8) -> bb5; // scope 2 at $DIR/funky_arms.rs:24:30: 24:45 // mir::Constant // + span: $DIR/funky_arms.rs:24:34: 24:43 diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff index 0c220eb91a4b1..137a1de522b83 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff @@ -4,23 +4,37 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - let mut _2: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 -+ let mut _4: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ let mut _7: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 scope 1 { debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11 } -+ scope 2 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + scope 2 { + } ++ scope 3 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = Vec::::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageLive(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + // mir::Constant + // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } + } + + bb1: { + StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 +- (*_5) = Vec::::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ ((*_7).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 + // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -30,32 +44,32 @@ - // + literal: Const { ty: fn() -> std::vec::Vec {std::vec::Vec::::new}, val: Value(Scalar()) } - } - -- bb1: { +- bb2: { + // + span: $DIR/inline-into-box-place.rs:8:33: 8:43 + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageDead(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 - _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 -- drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 +- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } -- bb2: { -+ bb1: { +- bb3: { ++ bb2: { StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } -- bb3 (cleanup): { -+ bb2 (cleanup): { +- bb4 (cleanup): { ++ bb3 (cleanup): { resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 - } - -- bb4 (cleanup): { -- _3 = alloc::alloc::box_free::, std::alloc::Global>(move (_2.0: std::ptr::Unique>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- bb5 (cleanup): { +- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff index 7f3a72ee5ad75..26327d0557461 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff @@ -4,23 +4,37 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11 let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - let mut _2: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - let mut _3: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 -+ let mut _4: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ let mut _7: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 scope 1 { debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11 } -+ scope 2 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + scope 2 { + } ++ scope 3 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11 - StorageLive(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - _2 = Box(std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 -- (*_2) = Vec::::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageLive(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ _4 = &mut (*_2); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ ((*_4).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43 + // mir::Constant + // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } + } + + bb1: { + StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 +- (*_5) = Vec::::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ ((*_7).0: alloc::raw_vec::RawVec) = const alloc::raw_vec::RawVec:: { ptr: Unique:: { pointer: {0x4 as *const u32}, _marker: PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 + // ty::Const + // + ty: alloc::raw_vec::RawVec + // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -30,32 +44,32 @@ - // + literal: Const { ty: fn() -> std::vec::Vec {std::vec::Vec::::new}, val: Value(Scalar()) } - } - -- bb1: { +- bb2: { + // + span: $DIR/inline-into-box-place.rs:8:33: 8:43 + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ StorageDead(_4); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 - _1 = move _2; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 - StorageDead(_2); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 ++ ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43 ++ StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 + _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43 + StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2 -- drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 -+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 +- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 ++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 } -- bb2: { -+ bb1: { +- bb3: { ++ bb2: { StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2 return; // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2 } -- bb3 (cleanup): { -+ bb2 (cleanup): { +- bb4 (cleanup): { ++ bb3 (cleanup): { resume; // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2 - } - -- bb4 (cleanup): { -- _3 = alloc::alloc::box_free::, std::alloc::Global>(move (_2.0: std::ptr::Unique>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- bb5 (cleanup): { +- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 - // + literal: Const { ty: unsafe fn(std::ptr::Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff index 3bdd4f4ff56cc..7379d5f219c48 100644 --- a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff +++ b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff @@ -4,13 +4,13 @@ fn clone(_1: fn(A, B)) -> fn(A, B) { debug f => _1; // in scope 0 at $DIR/inline-shims.rs:5:20: 5:21 let mut _0: fn(A, B); // return place in scope 0 at $DIR/inline-shims.rs:5:36: 5:44 - let mut _2: &fn(A, B); // in scope 0 at $DIR/inline-shims.rs:6:5: 6:6 + let mut _2: &fn(A, B); // in scope 0 at $DIR/inline-shims.rs:6:5: 6:14 + scope 1 (inlined ::clone - shim(fn(A, B))) { // at $DIR/inline-shims.rs:6:5: 6:14 + } bb0: { - StorageLive(_2); // scope 0 at $DIR/inline-shims.rs:6:5: 6:6 - _2 = &_1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:6 + StorageLive(_2); // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 + _2 = &_1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 - _0 = ::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14 - // mir::Constant - // + span: $DIR/inline-shims.rs:6:7: 6:12 diff --git a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir index eada5ac13476e..0be979901ac03 100644 --- a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir @@ -3,11 +3,11 @@ fn test(_1: &dyn X) -> u32 { debug x => _1; // in scope 0 at $DIR/inline-trait-method.rs:8:9: 8:10 let mut _0: u32; // return place in scope 0 at $DIR/inline-trait-method.rs:8:23: 8:26 - let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method.rs:9:5: 9:6 + let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 bb0: { - StorageLive(_2); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:6 - _2 = &(*_1); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:6 + StorageLive(_2); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 + _2 = &(*_1); // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 _0 = ::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10 // mir::Constant // + span: $DIR/inline-trait-method.rs:9:7: 9:8 diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir index 651855f802454..1b5153daa8ba8 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir @@ -5,7 +5,7 @@ fn a(_1: &mut [T]) -> &mut [T] { let mut _0: &mut [T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:2:29: 2:37 let mut _2: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 let mut _3: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 - let mut _4: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 + let mut _4: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 scope 1 (inlined <[T] as AsMut<[T]>>::as_mut) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 debug self => _4; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 let mut _5: &mut [T]; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 @@ -14,8 +14,8 @@ fn a(_1: &mut [T]) -> &mut [T] { bb0: { StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 - StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 - _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:6 + StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 + _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 StorageLive(_5); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 _5 = &mut (*_4); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 _3 = &mut (*_5); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15 diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir index c67ea7e00b760..257ddec780e93 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir @@ -5,7 +5,7 @@ fn b(_1: &mut Box) -> &mut T { let mut _0: &mut T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:7:32: 7:38 let mut _2: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 let mut _3: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 - let mut _4: &mut std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 + let mut _4: &mut std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 scope 1 (inlined as AsMut>::as_mut) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 debug self => _4; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 let mut _5: &mut T; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 @@ -15,8 +15,8 @@ fn b(_1: &mut Box) -> &mut T { bb0: { StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 - StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 - _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:6 + StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 + _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageLive(_5); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 StorageLive(_6); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 _6 = &mut (*(*_4)); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15 diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir index 16fae453ac936..9817e8cd5fa4d 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir @@ -4,15 +4,15 @@ fn c(_1: &[T]) -> &[T] { debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:12:13: 12:14 let mut _0: &[T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:12:25: 12:29 let _2: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 - let mut _3: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:6 + let mut _3: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 scope 1 (inlined <[T] as AsRef<[T]>>::as_ref) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 debug self => _3; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 } bb0: { StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 - StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:6 - _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:6 + StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 + _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 _2 = _3; // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15 StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:14: 13:15 diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir index e9ca7095a43ab..e49c91581b3cd 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir @@ -4,15 +4,15 @@ fn d(_1: &Box) -> &T { debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:17:13: 17:14 let mut _0: &T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:17:28: 17:30 let _2: &T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 - let mut _3: &std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:6 + let mut _3: &std::boxed::Box; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 scope 1 (inlined as AsRef>::as_ref) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 debug self => _3; // in scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 } bb0: { StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 - StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:6 - _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:6 + StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 + _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 _2 = &(*(*_3)); // scope 1 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15 StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:14: 18:15 diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index 95efa74289d85..dde49c77ae7f5 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -3,106 +3,120 @@ fn test() -> Option> { let mut _0: std::option::Option>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30 let mut _1: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _2: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _3: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - let mut _4: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - let mut _5: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _6: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _7: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _8: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _9: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _2: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _3: usize; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _4: *mut u8; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _5: std::boxed::Box; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + let mut _6: std::ops::ControlFlow, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _7: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + let mut _8: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _9: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _10: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let mut _11: std::option::Option; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _12: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 scope 1 { - debug residual => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20 - scope 2 { + } + scope 2 { + debug residual => _9; // in scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + scope 3 { } } - scope 3 { - debug val => _9; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20 - scope 4 { + scope 4 { + debug val => _12; // in scope 4 at $DIR/issue-62289.rs:9:15: 9:20 + scope 5 { } } bb0: { StorageLive(_1); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - StorageLive(_2); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - _2 = Box(u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as Try>::branch(move _4) -> [return: bb1, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _2 = SizeOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 + _3 = AlignOf(u32); // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 + _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:9:10: 9:21 // mir::Constant - // + span: $DIR/issue-62289.rs:9:15: 9:20 - // + literal: Const { ty: fn(std::option::Option) -> std::ops::ControlFlow< as std::ops::Try>::Residual, as std::ops::Try>::Output> { as std::ops::Try>::branch}, val: Value(Scalar()) } + // + span: $DIR/issue-62289.rs:9:10: 9:21 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - StorageDead(_4); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _5 = discriminant(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_5); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + _5 = ShallowInitBox(move _4, u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_7); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _7 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _6 = as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + // mir::Constant + // + span: $DIR/issue-62289.rs:9:15: 9:20 + // + literal: Const { ty: fn(std::option::Option) -> std::ops::ControlFlow< as std::ops::Try>::Residual, as std::ops::Try>::Output> { as std::ops::Try>::branch}, val: Value(Scalar()) } } bb2: { - StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - _9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - (*_2) = _9; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 - StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - drop(_2) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_7); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = discriminant(_6); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 } bb3: { - unreachable; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + StorageLive(_12); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _12 = ((_6 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + (*_5) = _12; // scope 5 at $DIR/issue-62289.rs:9:15: 9:20 + StorageDead(_12); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _1 = move _5; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 + drop(_5) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb4: { - StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _6 = ((_3 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as FromResidual>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 - // mir::Constant - // + span: $DIR/issue-62289.rs:9:19: 9:20 - // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, val: Value(Scalar()) } + unreachable; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 } bb5: { - StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _9 = ((_6 as Break).0: std::option::Option); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + StorageLive(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + _11 = _9; // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = > as FromResidual>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:9:15: 9:20 + // mir::Constant + // + span: $DIR/issue-62289.rs:9:19: 9:20 + // + literal: Const { ty: fn(std::option::Option) -> std::option::Option> {> as std::ops::FromResidual>>::from_residual}, val: Value(Scalar()) } } bb6: { - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 - _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - drop(_1) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_11); // scope 3 at $DIR/issue-62289.rs:9:19: 9:20 + StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + drop(_5) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { - StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb8: { - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb9: { - return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb10 (cleanup): { - drop(_1) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + bb10: { + return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } bb11 (cleanup): { - drop(_2) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } bb12 (cleanup): { + drop(_5) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + } + + bb13 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff index 96adadbe030d1..97c549dc9c8ae 100644 --- a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff +++ b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -22,6 +22,7 @@ let mut _20: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 let mut _21: *const T; // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84 let mut _22: !; // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL + let mut _23: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 scope 1 { debug v => _2; // in scope 1 at $DIR/issue_76432.rs:7:9: 7:10 let _13: &T; // in scope 1 at $DIR/issue_76432.rs:9:10: 9:16 @@ -51,16 +52,17 @@ StorageDead(_6); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 _4 = &_5; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 _3 = _4; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_23); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + _23 = _3; // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 _2 = move _3 as &[T] (Pointer(Unsize)); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 StorageDead(_3); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 StorageDead(_4); // scope 0 at $DIR/issue_76432.rs:7:29: 7:30 StorageLive(_9); // scope 1 at $DIR/issue_76432.rs:8:5: 11:6 - _10 = Len((*_2)); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + _10 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + StorageDead(_23); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 _11 = const 3_usize; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -- _12 = Eq(move _10, const 3_usize); // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -- switchInt(move _12) -> [false: bb1, otherwise: bb2]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -+ nop; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 -+ switchInt(move _10) -> [3_usize: bb2, otherwise: bb1]; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + _12 = const true; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 + goto -> bb2; // scope 1 at $DIR/issue_76432.rs:9:9: 9:33 } bb1: { diff --git a/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff new file mode 100644 index 0000000000000..c7226573d75c5 --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff @@ -0,0 +1,66 @@ +- // MIR for `array_bound` before InstCombine ++ // MIR for `array_bound` after InstCombine + + fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:6:36: 6:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:6:50: 6:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:6:70: 6:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _7 = _2; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _11 = _7; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:7:20: 7:21 +- _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + } + + bb1: { + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + } + + bb2: { + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb3: { + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:10:9: 10:11 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 + return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff new file mode 100644 index 0000000000000..d6c1c92cd9177 --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff @@ -0,0 +1,68 @@ +- // MIR for `array_bound` before NormalizeArrayLen ++ // MIR for `array_bound` after NormalizeArrayLen + + fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:6:36: 6:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:6:50: 6:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:6:70: 6:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _11 = _7; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:7:20: 7:21 +- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 + } + + bb1: { + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + } + + bb2: { + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 + _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + } + + bb3: { + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb4: { + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:10:9: 10:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb5: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 + return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff new file mode 100644 index 0000000000000..5cf3312cd641b --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff @@ -0,0 +1,73 @@ +- // MIR for `array_bound` before SimplifyLocals ++ // MIR for `array_bound` after SimplifyLocals + + fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:6:36: 6:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:6:50: 6:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:6:70: 6:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 ++ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 ++ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- _7 = _2; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- _11 = _7; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:7:20: 7:21 + _5 = const N; // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:7:16: 7:27 +- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:7:26: 7:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:7:8: 7:27 + } + + bb1: { +- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 +- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 ++ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:8:15: 8:20 ++ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 + } + + bb2: { +- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 +- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 ++ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:8:9: 8:21 ++ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:9:5: 9:6 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb3: { + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:10:9: 10:11 + goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:7:5: 11:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:11:5: 11:6 + return; // scope 0 at $DIR/lower_array_len.rs:12:2: 12:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff new file mode 100644 index 0000000000000..5622d48453213 --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff @@ -0,0 +1,79 @@ +- // MIR for `array_bound_mut` before InstCombine ++ // MIR for `array_bound_mut` after InstCombine + + fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:17:40: 17:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:17:54: 17:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:17:78: 17:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _14 = _7; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:18:20: 18:21 +- _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + } + + bb1: { + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + } + + bb2: { + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb3: { + StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ _12 = const N; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb4; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + } + + bb4: { + (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 + StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:23:9: 23:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb5: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 + return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff new file mode 100644 index 0000000000000..11fc20aa693c7 --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff @@ -0,0 +1,81 @@ +- // MIR for `array_bound_mut` before NormalizeArrayLen ++ // MIR for `array_bound_mut` after NormalizeArrayLen + + fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:17:40: 17:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:17:54: 17:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:17:78: 17:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ _14 = _7; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:18:20: 18:21 +- _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 + } + + bb1: { + StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + switchInt(move _3) -> [false: bb4, otherwise: bb2]; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + } + + bb2: { + StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + _8 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 + _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + } + + bb3: { + _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 + goto -> bb6; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb4: { + StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 + _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb5; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + } + + bb5: { + (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 + StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:23:9: 23:11 + goto -> bb6; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb6: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 + return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff new file mode 100644 index 0000000000000..f72aee0e50280 --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff @@ -0,0 +1,96 @@ +- // MIR for `array_bound_mut` before SimplifyLocals ++ // MIR for `array_bound_mut` after SimplifyLocals + + fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:17:40: 17:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:17:54: 17:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:17:78: 17:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 ++ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 ++ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ let _9: usize; // in scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 ++ let mut _10: usize; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ let mut _11: bool; // in scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + _4 = _1; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- _14 = _7; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:18:20: 18:21 + _5 = const N; // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:18:16: 18:27 +- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:18:26: 18:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:18:8: 18:27 + } + + bb1: { +- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 +- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 ++ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:19:15: 19:20 ++ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 + } + + bb2: { +- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 +- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 ++ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:19:9: 19:21 ++ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:20:5: 20:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb3: { +- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 +- _12 = const N; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- _13 = Lt(const 0_usize, _12); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ StorageLive(_9); // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 ++ _9 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:21:15: 21:16 ++ _10 = const N; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ _11 = Lt(const 0_usize, _10); // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 ++ assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:17 + } + + bb4: { +- (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 +- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 ++ (*_2)[_9] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:21:9: 21:22 ++ StorageDead(_9); // scope 0 at $DIR/lower_array_len.rs:21:22: 21:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:23:9: 23:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:18:5: 24:6 + } + + bb5: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:24:5: 24:6 + return; // scope 0 at $DIR/lower_array_len.rs:25:2: 25:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff new file mode 100644 index 0000000000000..a818de39bcc84 --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff @@ -0,0 +1,27 @@ +- // MIR for `array_len` before InstCombine ++ // MIR for `array_len` after InstCombine + + fn array_len(_1: &[u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:30:34: 30:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:30:52: 30:57 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _3 = _1; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _4 = _3; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:31:7: 31:8 +- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 + return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff new file mode 100644 index 0000000000000..892fdda818ebd --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff @@ -0,0 +1,30 @@ +- // MIR for `array_len` before NormalizeArrayLen ++ // MIR for `array_len` after NormalizeArrayLen + + fn array_len(_1: &[u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:30:34: 30:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:30:52: 30:57 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:31:7: 31:8 +- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 ++ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + } + + bb1: { + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 + return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff new file mode 100644 index 0000000000000..20e2685aba59f --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff @@ -0,0 +1,25 @@ +- // MIR for `array_len` before SimplifyLocals ++ // MIR for `array_len` after SimplifyLocals + + fn array_len(_1: &[u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:30:34: 30:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:30:52: 30:57 +- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- _3 = _1; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- _4 = _3; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:31:7: 31:8 + _0 = const N; // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:31:5: 31:14 +- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:31:13: 31:14 + return; // scope 0 at $DIR/lower_array_len.rs:32:2: 32:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff new file mode 100644 index 0000000000000..ce12531e84bbf --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff @@ -0,0 +1,26 @@ +- // MIR for `array_len_by_value` before InstCombine ++ // MIR for `array_len_by_value` after InstCombine + + fn array_len_by_value(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:37:43: 37:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:37:60: 37:65 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _4 = _3; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:38:7: 38:8 +- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 + return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff new file mode 100644 index 0000000000000..201fffbf0d45a --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff @@ -0,0 +1,30 @@ +- // MIR for `array_len_by_value` before NormalizeArrayLen ++ // MIR for `array_len_by_value` after NormalizeArrayLen + + fn array_len_by_value(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:37:43: 37:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:37:60: 37:65 + let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:38:7: 38:8 +- _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 ++ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + } + + bb1: { + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 + return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff new file mode 100644 index 0000000000000..7e7b708145f40 --- /dev/null +++ b/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff @@ -0,0 +1,25 @@ +- // MIR for `array_len_by_value` before SimplifyLocals ++ // MIR for `array_len_by_value` after SimplifyLocals + + fn array_len_by_value(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:37:43: 37:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:37:60: 37:65 +- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- _4 = _3; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:38:7: 38:8 + _0 = const N; // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:38:5: 38:14 +- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:38:13: 38:14 + return; // scope 0 at $DIR/lower_array_len.rs:39:2: 39:2 + } + } + diff --git a/src/test/mir-opt/lower_array_len.rs b/src/test/mir-opt/lower_array_len.rs new file mode 100644 index 0000000000000..fc12ee75fcfcd --- /dev/null +++ b/src/test/mir-opt/lower_array_len.rs @@ -0,0 +1,47 @@ +// compile-flags: -Z mir-opt-level=4 + +// EMIT_MIR lower_array_len.array_bound.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_bound.SimplifyLocals.diff +// EMIT_MIR lower_array_len.array_bound.InstCombine.diff +pub fn array_bound(index: usize, slice: &[u8; N]) -> u8 { + if index < slice.len() { + slice[index] + } else { + 42 + } +} + +// EMIT_MIR lower_array_len.array_bound_mut.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_bound_mut.SimplifyLocals.diff +// EMIT_MIR lower_array_len.array_bound_mut.InstCombine.diff +pub fn array_bound_mut(index: usize, slice: &mut [u8; N]) -> u8 { + if index < slice.len() { + slice[index] + } else { + slice[0] = 42; + + 42 + } +} + +// EMIT_MIR lower_array_len.array_len.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_len.SimplifyLocals.diff +// EMIT_MIR lower_array_len.array_len.InstCombine.diff +pub fn array_len(arr: &[u8; N]) -> usize { + arr.len() +} + +// EMIT_MIR lower_array_len.array_len_by_value.NormalizeArrayLen.diff +// EMIT_MIR lower_array_len.array_len_by_value.SimplifyLocals.diff +// EMIT_MIR lower_array_len.array_len_by_value.InstCombine.diff +pub fn array_len_by_value(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/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff index 25db3b98c2562..13241d882f210 100644 --- a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff +++ b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff @@ -8,7 +8,7 @@ let mut _3: bool; // in scope 0 at $DIR/lower_slice_len.rs:5:8: 5:27 let mut _4: usize; // in scope 0 at $DIR/lower_slice_len.rs:5:8: 5:13 let mut _5: usize; // in scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - let mut _6: &[u8]; // in scope 0 at $DIR/lower_slice_len.rs:5:16: 5:21 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 let _7: usize; // in scope 0 at $DIR/lower_slice_len.rs:6:15: 6:20 let mut _8: usize; // in scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 let mut _9: bool; // in scope 0 at $DIR/lower_slice_len.rs:6:9: 6:21 @@ -18,8 +18,8 @@ StorageLive(_4); // scope 0 at $DIR/lower_slice_len.rs:5:8: 5:13 _4 = _1; // scope 0 at $DIR/lower_slice_len.rs:5:8: 5:13 StorageLive(_5); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - StorageLive(_6); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:21 - _6 = &(*_2); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:21 + StorageLive(_6); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 + _6 = &(*_2); // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - _5 = core::slice::::len(move _6) -> bb1; // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27 - // mir::Constant - // + span: $DIR/lower_slice_len.rs:5:22: 5:25 diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir index 7bdf7b6a6482e..5c55ee4b9bb40 100644 --- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir @@ -4,13 +4,13 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/no-spurious-drop-after-call.rs:8:11: 8:11 let _1: (); // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 let mut _2: std::string::String; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 - let mut _3: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 + let mut _3: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 let _4: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 bb0: { StorageLive(_1); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 StorageLive(_2); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 - StorageLive(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 + StorageLive(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 StorageLive(_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 _4 = const ""; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 // ty::Const @@ -19,7 +19,7 @@ fn main() -> () { // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [], len: Size { raw: 0 } }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 0 }) } - _3 = &(*_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:22 + _3 = &(*_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 _2 = ::to_string(move _3) -> bb1; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32 diff --git a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir index f54c8f8ab4a2e..f1a1f388c501a 100644 --- a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir +++ b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir @@ -10,15 +10,15 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/receiver-ptr-mutability.rs:13:11: 13:11 let _1: *mut Test as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 let _2: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 - let mut _3: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 + let mut _3: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 let mut _4: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 let _6: &&&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:34: 18:41 let _7: &&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:35: 18:41 let _8: &&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:36: 18:41 let _9: &*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:18:37: 18:41 let _10: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 - let mut _11: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 - let mut _12: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 + let mut _11: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + let mut _12: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 scope 1 { debug ptr => _1; // in scope 1 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 let _5: &&&&*mut Test as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 1 at $DIR/receiver-ptr-mutability.rs:18:9: 18:16 @@ -39,10 +39,10 @@ fn main() -> () { FakeRead(ForLet(None), _1); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:9: 14:12 AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/receiver-ptr-mutability.rs:14:14: 14:23 StorageLive(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 - StorageLive(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 + StorageLive(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 StorageLive(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 _4 = _1; // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 - _3 = move _4 as *const Test (Pointer(MutToConstPointer)); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:8 + _3 = move _4 as *const Test (Pointer(MutToConstPointer)); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 StorageDead(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:15:7: 15:8 _2 = Test::x(move _3) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12 // mir::Constant @@ -67,10 +67,10 @@ fn main() -> () { AscribeUserType(_5, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:18: 18:31 StorageDead(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:18:41: 18:42 StorageLive(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 - StorageLive(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 - StorageLive(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 - _12 = (*(*(*(*_5)))); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 - _11 = move _12 as *const Test (Pointer(MutToConstPointer)); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:12 + StorageLive(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + StorageLive(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + _12 = (*(*(*(*_5)))); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 + _11 = move _12 as *const Test (Pointer(MutToConstPointer)); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 StorageDead(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:19:11: 19:12 _10 = Test::x(move _11) -> [return: bb3, unwind: bb4]; // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16 // mir::Constant diff --git a/src/test/mir-opt/remove-never-const.rs b/src/test/mir-opt/remove-never-const.rs index 1673f14b45ce4..017746647ab0d 100644 --- a/src/test/mir-opt/remove-never-const.rs +++ b/src/test/mir-opt/remove-never-const.rs @@ -5,7 +5,6 @@ // Force generation of optimized mir for functions that do not reach codegen. // compile-flags: --emit mir,link -#![feature(const_panic)] #![feature(never_type)] #![warn(const_err)] diff --git a/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir b/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir index 6f4a024d20f93..bf62c8441fd11 100644 --- a/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir +++ b/src/test/mir-opt/remove_never_const.no_codegen.PreCodegen.after.mir @@ -1,11 +1,11 @@ // MIR for `no_codegen` after PreCodegen fn no_codegen() -> () { - let mut _0: (); // return place in scope 0 at $DIR/remove-never-const.rs:19:20: 19:20 + let mut _0: (); // return place in scope 0 at $DIR/remove-never-const.rs:18:20: 18:20 scope 1 { } bb0: { - unreachable; // scope 0 at $DIR/remove-never-const.rs:20:13: 20:33 + unreachable; // scope 0 at $DIR/remove-never-const.rs:19:13: 19:33 } } diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index cdf7282c8c3c4..6bb92c5e6bca0 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -4,7 +4,7 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/retag.rs:29:11: 29:11 let mut _1: i32; // in scope 0 at $DIR/retag.rs:30:9: 30:14 let _2: (); // in scope 0 at $DIR/retag.rs:31:5: 37:6 - let mut _4: &Test; // in scope 0 at $DIR/retag.rs:32:17: 32:24 + let mut _4: &Test; // in scope 0 at $DIR/retag.rs:32:17: 32:36 let _5: Test; // in scope 0 at $DIR/retag.rs:32:17: 32:24 let mut _6: &mut i32; // in scope 0 at $DIR/retag.rs:32:29: 32:35 let mut _7: &mut i32; // in scope 0 at $DIR/retag.rs:32:29: 32:35 @@ -15,7 +15,7 @@ fn main() -> () { let mut _17: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 let _18: &i32; // in scope 0 at $DIR/retag.rs:44:16: 44:18 let _19: &i32; // in scope 0 at $DIR/retag.rs:47:5: 47:24 - let mut _20: &Test; // in scope 0 at $DIR/retag.rs:47:5: 47:12 + let mut _20: &Test; // in scope 0 at $DIR/retag.rs:47:5: 47:24 let _21: Test; // in scope 0 at $DIR/retag.rs:47:5: 47:12 let mut _22: &i32; // in scope 0 at $DIR/retag.rs:47:21: 47:23 let _23: &i32; // in scope 0 at $DIR/retag.rs:47:21: 47:23 @@ -60,11 +60,11 @@ fn main() -> () { _1 = const 0_i32; // scope 0 at $DIR/retag.rs:30:17: 30:18 StorageLive(_2); // scope 1 at $DIR/retag.rs:31:5: 37:6 StorageLive(_3); // scope 1 at $DIR/retag.rs:32:13: 32:14 - StorageLive(_4); // scope 1 at $DIR/retag.rs:32:17: 32:24 + StorageLive(_4); // scope 1 at $DIR/retag.rs:32:17: 32:36 StorageLive(_5); // scope 1 at $DIR/retag.rs:32:17: 32:24 _5 = Test(const 0_i32); // scope 1 at $DIR/retag.rs:32:17: 32:24 - _4 = &_5; // scope 1 at $DIR/retag.rs:32:17: 32:24 - Retag(_4); // scope 1 at $DIR/retag.rs:32:17: 32:24 + _4 = &_5; // scope 1 at $DIR/retag.rs:32:17: 32:36 + Retag(_4); // scope 1 at $DIR/retag.rs:32:17: 32:36 StorageLive(_6); // scope 1 at $DIR/retag.rs:32:29: 32:35 StorageLive(_7); // scope 1 at $DIR/retag.rs:32:29: 32:35 _7 = &mut _1; // scope 1 at $DIR/retag.rs:32:29: 32:35 @@ -140,11 +140,11 @@ fn main() -> () { StorageDead(_16); // scope 6 at $DIR/retag.rs:44:18: 44:19 StorageDead(_18); // scope 6 at $DIR/retag.rs:44:19: 44:20 StorageLive(_19); // scope 7 at $DIR/retag.rs:47:5: 47:24 - StorageLive(_20); // scope 7 at $DIR/retag.rs:47:5: 47:12 + StorageLive(_20); // scope 7 at $DIR/retag.rs:47:5: 47:24 StorageLive(_21); // scope 7 at $DIR/retag.rs:47:5: 47:12 _21 = Test(const 0_i32); // scope 7 at $DIR/retag.rs:47:5: 47:12 - _20 = &_21; // scope 7 at $DIR/retag.rs:47:5: 47:12 - Retag(_20); // scope 7 at $DIR/retag.rs:47:5: 47:12 + _20 = &_21; // scope 7 at $DIR/retag.rs:47:5: 47:24 + Retag(_20); // scope 7 at $DIR/retag.rs:47:5: 47:24 StorageLive(_22); // scope 7 at $DIR/retag.rs:47:21: 47:23 StorageLive(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 _28 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:47:21: 47:23 diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index 7f81d9fc482ff..d7d2cdf9b0c75 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -4,80 +4,108 @@ fn move_out_by_subslice() -> () { let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:10:27: 10:27 let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - let mut _3: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - let mut _5: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 scope 1 { debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:11:9: 11:10 - let _6: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 - scope 2 { - debug _y => _6; // in scope 2 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + let _12: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + scope 4 { + debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:12:10: 12:17 } } + scope 2 { + } + scope 3 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 - _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 - StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 - _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 } bb2: { - StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 - _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb3: { - StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 } bb4: { + StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 + drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb5: { + StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb6: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 - StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 - _6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 + _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb5: { - StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + bb7: { + StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb6: { + bb8: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + bb9 (cleanup): { + drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + bb10 (cleanup): { + drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + bb11 (cleanup): { + drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } - bb10 (cleanup): { + bb12 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir index 62ab494c06628..18bc1a17c1b50 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir @@ -4,80 +4,108 @@ fn move_out_from_end() -> () { let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:4:24: 4:24 let _1: [std::boxed::Box; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 let mut _2: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - let mut _3: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - let mut _4: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - let mut _5: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _6: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + let mut _7: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 scope 1 { debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:5:9: 5:10 - let _6: std::boxed::Box; // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 - scope 2 { - debug _y => _6; // in scope 2 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + let _12: std::boxed::Box; // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + scope 4 { + debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:6:14: 6:16 } } + scope 2 { + } + scope 3 { + } bb0: { StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - StorageLive(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 - _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 - drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb1: { - StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 - StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 - _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 - drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 } bb2: { - StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 - _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 - drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + // mir::Constant + // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26 + // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar()) } } bb3: { - StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 - drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 } bb4: { + StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 + drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb5: { + StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb6: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 - StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 - _6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 + _12 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2 - drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb5: { - StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + bb7: { + StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb6: { + bb8: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2 } - bb7 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + bb9 (cleanup): { + drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb8 (cleanup): { - drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + bb10 (cleanup): { + drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } - bb9 (cleanup): { - drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + bb11 (cleanup): { + drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } - bb10 (cleanup): { + bb12 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2 } } diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index d3862309ce46f..7c16f7bdaf7c1 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -2,11 +2,12 @@ #![deny(warnings)] extern crate rustc_codegen_ssa; -extern crate rustc_errors; -extern crate rustc_middle; extern crate rustc_data_structures; extern crate rustc_driver; +extern crate rustc_errors; extern crate rustc_hir; +extern crate rustc_metadata; +extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; extern crate rustc_symbol_mangling; @@ -16,8 +17,8 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_codegen_ssa::{CodegenResults, CrateInfo}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorReported; +use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::ty::TyCtxt; use rustc_session::config::OutputFilenames; use rustc_session::Session; diff --git a/src/test/run-make-fulldeps/obtain-borrowck/driver.rs b/src/test/run-make-fulldeps/obtain-borrowck/driver.rs index 961ea518c13ab..a288b90d7924e 100644 --- a/src/test/run-make-fulldeps/obtain-borrowck/driver.rs +++ b/src/test/run-make-fulldeps/obtain-borrowck/driver.rs @@ -48,7 +48,6 @@ fn main() { pub struct CompilerCalls; impl rustc_driver::Callbacks for CompilerCalls { - // In this callback we override the mir_borrowck query. fn config(&mut self, config: &mut Config) { assert!(config.override_queries.is_none()); @@ -64,12 +63,10 @@ impl rustc_driver::Callbacks for CompilerCalls { ) -> Compilation { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - // Collect definition ids of MIR bodies. let hir = tcx.hir(); - let krate = hir.krate(); let mut visitor = HirVisitor { bodies: Vec::new() }; - krate.visit_all_item_likes(&mut visitor); + hir.visit_all_item_likes(&mut visitor); // Trigger borrow checking of all bodies. for def_id in visitor.bodies { diff --git a/src/test/run-make-fulldeps/target-specs/foo.rs b/src/test/run-make-fulldeps/target-specs/foo.rs index 9ff33e24d04d7..d576a1dd28192 100644 --- a/src/test/run-make-fulldeps/target-specs/foo.rs +++ b/src/test/run-make-fulldeps/target-specs/foo.rs @@ -11,7 +11,7 @@ trait Sized {} auto trait Freeze {} #[lang = "start"] -fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { +fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/src/test/run-make/issue-85441/Makefile b/src/test/run-make/issue-85441/Makefile new file mode 100644 index 0000000000000..c7ae708c173c1 --- /dev/null +++ b/src/test/run-make/issue-85441/Makefile @@ -0,0 +1,9 @@ +# only-windows-msvc + +-include ../../run-make-fulldeps/tools.mk + +# Tests that WS2_32.dll is not unnecessarily linked, see issue #85441 + +all: + $(RUSTC) empty.rs + objdump -p $(TMPDIR)/empty.exe | $(CGREP) -v -i "WS2_32.dll" diff --git a/src/test/run-make/issue-85441/empty.rs b/src/test/run-make/issue-85441/empty.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/src/test/run-make/issue-85441/empty.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/src/test/rustdoc-gui/huge-collection-of-constants.goml b/src/test/rustdoc-gui/huge-collection-of-constants.goml new file mode 100644 index 0000000000000..924fab1ea9106 --- /dev/null +++ b/src/test/rustdoc-gui/huge-collection-of-constants.goml @@ -0,0 +1,5 @@ +goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html + +// Make sure that the last two entries are more than 12 pixels apart and not stacked on each other. + +compare-elements-position-near-false: ("//*[@class='item-table']//div[last()-1]", "//*[@class='item-table']//div[last()-3]", {"y": 12}) diff --git a/src/test/rustdoc-gui/src/test_docs/Cargo.toml b/src/test/rustdoc-gui/src/test_docs/Cargo.toml index 7f3c65746fcf8..5f527078e79a8 100644 --- a/src/test/rustdoc-gui/src/test_docs/Cargo.toml +++ b/src/test/rustdoc-gui/src/test_docs/Cargo.toml @@ -3,5 +3,7 @@ name = "test_docs" version = "0.1.0" edition = "2018" +build = "build.rs" + [lib] path = "lib.rs" diff --git a/src/test/rustdoc-gui/src/test_docs/build.rs b/src/test/rustdoc-gui/src/test_docs/build.rs new file mode 100644 index 0000000000000..16c96ded9120c --- /dev/null +++ b/src/test/rustdoc-gui/src/test_docs/build.rs @@ -0,0 +1,15 @@ +//! generate 2000 constants for testing + +use std::{fs::write, path::PathBuf}; + +fn main() -> std::io::Result<()> { + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is not defined"); + + let mut output = String::new(); + for i in 0..2000 { + let line = format!("/// Some const A{0}\npub const A{0}: isize = 0;\n", i); + output.push_str(&*line); + }; + + write(&[&*out_dir, "huge_amount_of_consts.rs"].iter().collect::(), output) +} diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs index af4f28047fc0d..0aa1426a36abf 100644 --- a/src/test/rustdoc-gui/src/test_docs/lib.rs +++ b/src/test/rustdoc-gui/src/test_docs/lib.rs @@ -116,3 +116,7 @@ pub mod keyword {} /// Just some type alias. pub type SomeType = u32; + +pub mod huge_amount_of_consts { + include!(concat!(env!("OUT_DIR"), "/huge_amount_of_consts.rs")); +} diff --git a/src/test/rustdoc-json/primitive.rs b/src/test/rustdoc-json/primitive.rs new file mode 100644 index 0000000000000..3a7d6d18c1bd0 --- /dev/null +++ b/src/test/rustdoc-json/primitive.rs @@ -0,0 +1,14 @@ +// edition:2018 + +#![feature(doc_primitive)] + +#[doc(primitive = "usize")] +mod usize {} + +// @set local_crate_id = primitive.json "$.index[*][?(@.name=='primitive')].crate_id" + +// @has - "$.index[*][?(@.name=='log10')]" +// @!is - "$.index[*][?(@.name=='log10')].crate_id" $local_crate_id +// @has - "$.index[*][?(@.name=='checked_add')]" +// @!is - "$.index[*][?(@.name=='checked_add')]" $local_crate_id +// @!has - "$.index[*][?(@.name=='is_ascii_uppercase')]" diff --git a/src/test/rustdoc-json/unions/impl.rs b/src/test/rustdoc-json/unions/impl.rs new file mode 100644 index 0000000000000..0388b4a8c3c3b --- /dev/null +++ b/src/test/rustdoc-json/unions/impl.rs @@ -0,0 +1,15 @@ +#![no_std] + +// @has impl.json "$.index[*][?(@.name=='Ux')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='Ux')].kind" \"union\" +pub union Ux { + a: u32, + b: u64 +} + +// @has - "$.index[*][?(@.name=='Num')].visibility" \"public\" +// @has - "$.index[*][?(@.name=='Num')].kind" \"trait\" +pub trait Num {} + +// @count - "$.index[*][?(@.name=='Ux')].inner.impls" 1 +impl Num for Ux {} diff --git a/src/test/rustdoc-ui/doc-cfg.rs b/src/test/rustdoc-ui/doc-cfg.rs new file mode 100644 index 0000000000000..354d76bc3c433 --- /dev/null +++ b/src/test/rustdoc-ui/doc-cfg.rs @@ -0,0 +1,9 @@ +#![feature(doc_cfg)] + +#[doc(cfg(), cfg(foo, bar))] +//~^ ERROR +//~^^ ERROR +#[doc(cfg(foo), cfg(bar))] // ok! +#[doc(cfg())] //~ ERROR +#[doc(cfg(foo, bar))] //~ ERROR +pub fn foo() {} diff --git a/src/test/rustdoc-ui/doc-cfg.stderr b/src/test/rustdoc-ui/doc-cfg.stderr new file mode 100644 index 0000000000000..b379f6febe29f --- /dev/null +++ b/src/test/rustdoc-ui/doc-cfg.stderr @@ -0,0 +1,26 @@ +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:3:7 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^^^ + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:3:23 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^ + +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:7:7 + | +LL | #[doc(cfg())] + | ^^^^^ + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:8:16 + | +LL | #[doc(cfg(foo, bar))] + | ^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/rustdoc-ui/doctest-edition.rs b/src/test/rustdoc-ui/doctest-edition.rs new file mode 100644 index 0000000000000..b0787be972f2f --- /dev/null +++ b/src/test/rustdoc-ui/doctest-edition.rs @@ -0,0 +1,16 @@ +// edition:2021 + +#![deny(rustdoc::invalid_rust_codeblocks)] +//~^ NOTE lint level is defined here + +// By default, rustdoc should use the edition of the crate. +//! ``` +//! foo'b' +//! ``` +//~^^^ ERROR could not parse +//~| NOTE prefix `foo` is unknown + +// Rustdoc should respect `edition2018` when highlighting syntax. +//! ```edition2018 +//! foo'b' +//! ``` diff --git a/src/test/rustdoc-ui/doctest-edition.stderr b/src/test/rustdoc-ui/doctest-edition.stderr new file mode 100644 index 0000000000000..1643d605375a1 --- /dev/null +++ b/src/test/rustdoc-ui/doctest-edition.stderr @@ -0,0 +1,22 @@ +error: could not parse code block as Rust code + --> $DIR/doctest-edition.rs:7:5 + | +LL | //! ``` + | _____^ +LL | | //! foo'b' +LL | | //! ``` + | |_______^ + | +note: the lint level is defined here + --> $DIR/doctest-edition.rs:3:9 + | +LL | #![deny(rustdoc::invalid_rust_codeblocks)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: error from rustc: prefix `foo` is unknown +help: mark blocks that do not contain Rust code as text + | +LL | //! ```text + | ++++ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs new file mode 100644 index 0000000000000..17812018b9b7a --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs @@ -0,0 +1,7 @@ +#![doc(cfg_hide(test))] +//~^ ERROR `#[doc(cfg_hide)]` is experimental + +#[cfg(not(test))] +pub fn public_fn() {} +#[cfg(test)] +pub fn internal_use_only() {} diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr new file mode 100644 index 0000000000000..ba42c7bbb05bc --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr @@ -0,0 +1,14 @@ +error[E0658]: `#[doc(cfg_hide)]` is experimental + --> $DIR/feature-gate-doc_cfg_hide.rs:1:1 + | +LL | #![doc(cfg_hide(test))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg_hide)]` to the crate attributes to enable + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/rustdoc/cross-crate-primitive-doc.rs b/src/test/rustdoc/cross-crate-primitive-doc.rs index 120b6e9747f4a..4ba296ee04a1a 100644 --- a/src/test/rustdoc/cross-crate-primitive-doc.rs +++ b/src/test/rustdoc/cross-crate-primitive-doc.rs @@ -1,6 +1,6 @@ // aux-build:primitive-doc.rs // compile-flags: --extern-html-root-url=primitive_doc=../ -Z unstable-options -// ignore-windows +// only-linux #![feature(no_core)] #![no_core] diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs new file mode 100644 index 0000000000000..b9d0d32313723 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-hide.rs @@ -0,0 +1,32 @@ +#![crate_name = "oud"] +#![feature(doc_cfg, doc_cfg_hide)] + +#![doc(cfg_hide(feature = "solecism"))] + +// @has 'oud/struct.Solecism.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="solecism" +#[cfg(feature = "solecism")] +pub struct Solecism; + +// @has 'oud/struct.Scribacious.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature solecism' +#[cfg(feature = "solecism")] +#[doc(cfg(feature = "solecism"))] +pub struct Scribacious; + +// @has 'oud/struct.Hyperdulia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature hyperdulia' +// compile-flags:--cfg feature="hyperdulia" +#[cfg(feature = "solecism")] +#[cfg(feature = "hyperdulia")] +pub struct Hyperdulia; + +// @has 'oud/struct.Oystercatcher.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate features solecism and oystercatcher' +// compile-flags:--cfg feature="oystercatcher" +#[cfg(all(feature = "solecism", feature = "oystercatcher"))] +pub struct Oystercatcher; diff --git a/src/test/rustdoc/doc-cfg-implicit-gate.rs b/src/test/rustdoc/doc-cfg-implicit-gate.rs new file mode 100644 index 0000000000000..92804d3729bba --- /dev/null +++ b/src/test/rustdoc/doc-cfg-implicit-gate.rs @@ -0,0 +1,7 @@ +// compile-flags:--cfg feature="worricow" +#![crate_name = "xenogenous"] + +// @has 'xenogenous/struct.Worricow.html' +// @count - '//*[@class="stab portability"]' 0 +#[cfg(feature = "worricow")] +pub struct Worricow; diff --git a/src/test/rustdoc/doc-cfg-implicit.rs b/src/test/rustdoc/doc-cfg-implicit.rs new file mode 100644 index 0000000000000..36c2025785d0f --- /dev/null +++ b/src/test/rustdoc/doc-cfg-implicit.rs @@ -0,0 +1,31 @@ +#![crate_name = "funambulism"] +#![feature(doc_cfg)] + +// @has 'funambulism/struct.Disorbed.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature disorbed' +// compile-flags:--cfg feature="disorbed" +#[cfg(feature = "disorbed")] +pub struct Disorbed; + +// @has 'funambulism/struct.Aesthesia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature aesthesia' +// compile-flags:--cfg feature="aesthesia" +#[doc(cfg(feature = "aesthesia"))] +pub struct Aesthesia; + +// @has 'funambulism/struct.Pliothermic.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature pliothermic' +// compile-flags:--cfg feature="epopoeist" +#[cfg(feature = "epopoeist")] +#[doc(cfg(feature = "pliothermic"))] +pub struct Pliothermic; + +// @has 'funambulism/struct.Simillimum.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="simillimum" +#[cfg(feature = "simillimum")] +#[doc(cfg(all()))] +pub struct Simillimum; diff --git a/src/test/rustdoc/external-cross.rs b/src/test/rustdoc/external-cross.rs index 056ed3534624b..3f8e16882911a 100644 --- a/src/test/rustdoc/external-cross.rs +++ b/src/test/rustdoc/external-cross.rs @@ -6,5 +6,5 @@ extern crate external_cross; // @has host/struct.NeedMoreDocs.html -// @has - '//h1' 'Cross-crate imported docs' +// @has - '//h2' 'Cross-crate imported docs' pub use external_cross::NeedMoreDocs; diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs index fc29cb252e26c..bd322d67a370d 100644 --- a/src/test/rustdoc/external-doc.rs +++ b/src/test/rustdoc/external-doc.rs @@ -1,6 +1,6 @@ // @has external_doc/struct.IncludeStrDocs.html -// @has - '//h1' 'External Docs' -// @has - '//h2' 'Inline Docs' +// @has - '//h2' 'External Docs' +// @has - '//h3' 'Inline Docs' #[doc = include_str!("auxiliary/external-doc.md")] /// ## Inline Docs pub struct IncludeStrDocs; @@ -8,7 +8,7 @@ pub struct IncludeStrDocs; macro_rules! dir { () => { "auxiliary" } } // @has external_doc/struct.EagerExpansion.html -// @has - '//h1' 'External Docs' +// @has - '//h2' 'External Docs' #[doc = include_str!(concat!(dir!(), "/external-doc.md"))] /// ## Inline Docs pub struct EagerExpansion; diff --git a/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs b/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs new file mode 100644 index 0000000000000..95b3e9b652303 --- /dev/null +++ b/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs @@ -0,0 +1,31 @@ +// compile-flags: -Z unstable-options --document-hidden-items + +// test for trait methods with `doc(hidden)` with `--document-hidden-items` passed. +#![crate_name = "foo"] + +// @has foo/trait.Trait.html +// @has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @has - '//*[@id="tymethod.f"]' 'fn f()' +// @has - '//*[@id="tymethod.g"]' 'fn g()' +pub trait Trait { + #[doc(hidden)] + type Foo; + type Bar; + #[doc(hidden)] + fn f(); + fn g(); +} + +// @has foo/struct.S.html +// @has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @has - '//*[@id="method.f"]' 'fn f()' +// @has - '//*[@id="method.g"]' 'fn g()' +pub struct S; +impl Trait for S { + type Foo = (); + type Bar = (); + fn f() {} + fn g() {} +} diff --git a/src/test/rustdoc/hidden-trait-methods.rs b/src/test/rustdoc/hidden-trait-methods.rs new file mode 100644 index 0000000000000..e924ba7d0acde --- /dev/null +++ b/src/test/rustdoc/hidden-trait-methods.rs @@ -0,0 +1,29 @@ +// test for trait methods with `doc(hidden)`. +#![crate_name = "foo"] + +// @has foo/trait.Trait.html +// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @!has - '//*[@id="tymethod.f"]' 'fn f()' +// @has - '//*[@id="tymethod.g"]' 'fn g()' +pub trait Trait { + #[doc(hidden)] + type Foo; + type Bar; + #[doc(hidden)] + fn f(); + fn g(); +} + +// @has foo/struct.S.html +// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo' +// @has - '//*[@id="associatedtype.Bar"]' 'type Bar' +// @!has - '//*[@id="method.f"]' 'fn f()' +// @has - '//*[@id="method.g"]' 'fn g()' +pub struct S; +impl Trait for S { + type Foo = (); + type Bar = (); + fn f() {} + fn g() {} +} diff --git a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs index 5a92a28556ede..9d869984bbd7c 100644 --- a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs +++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs @@ -1,7 +1,7 @@ // aux-build:my-core.rs // build-aux-docs // ignore-cross-compile -// ignore-windows +// only-linux #![deny(broken_intra_doc_links)] #![feature(no_core, lang_items)] diff --git a/src/test/rustdoc/issue-42760.rs b/src/test/rustdoc/issue-42760.rs index b07dc3f6e967b..4944f8157014e 100644 --- a/src/test/rustdoc/issue-42760.rs +++ b/src/test/rustdoc/issue-42760.rs @@ -1,5 +1,5 @@ // @has issue_42760/struct.NonGen.html -// @has - '//h1' 'Example' +// @has - '//h2' 'Example' /// Item docs. /// diff --git a/src/test/rustdoc/issue-89309-heading-levels.rs b/src/test/rustdoc/issue-89309-heading-levels.rs new file mode 100644 index 0000000000000..bb706c28ffa51 --- /dev/null +++ b/src/test/rustdoc/issue-89309-heading-levels.rs @@ -0,0 +1,29 @@ +#![crate_name = "foo"] + +// @has foo/trait.Read.html +// @has - '//h2' 'Trait examples' +/// # Trait examples +pub trait Read { + // @has - '//h5' 'Function examples' + /// # Function examples + fn read(&mut self, buf: &mut [u8]) -> Result; +} + +pub struct Foo; + +// @has foo/struct.Foo.html +impl Foo { + // @has - '//h5' 'Implementation header' + /// # Implementation header + pub fn bar(&self) -> usize { + 1 + } +} + +impl Read for Foo { + // @has - '//h5' 'Trait implementation header' + /// # Trait implementation header + fn read(&mut self, buf: &mut [u8]) -> Result { + Ok(1) + } +} diff --git a/src/test/rustdoc/macro-document-private-duplicate.rs b/src/test/rustdoc/macro-document-private-duplicate.rs index 460785ed979de..7576c1326b8e4 100644 --- a/src/test/rustdoc/macro-document-private-duplicate.rs +++ b/src/test/rustdoc/macro-document-private-duplicate.rs @@ -1,3 +1,5 @@ +// ignore-test (fails spuriously, see issue #89228) + // FIXME: If two macros in the same module have the same name // (yes, that's a thing), rustdoc lists both of them on the index page, // but only documents the first one on the page for the macro. diff --git a/src/test/rustdoc/short-docblock.rs b/src/test/rustdoc/short-docblock.rs index 74fa783174da8..17c44eab091a6 100644 --- a/src/test/rustdoc/short-docblock.rs +++ b/src/test/rustdoc/short-docblock.rs @@ -2,7 +2,7 @@ // @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'fooo' // @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h1' 'fooo' -// @has foo/fn.foo.html '//h1[@id="fooo"]/a[@href="#fooo"]' 'fooo' +// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'fooo' /// # fooo /// @@ -11,7 +11,7 @@ pub fn foo() {} // @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'mooood' // @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h2' 'mooood' -// @has foo/foo/index.html '//h2[@id="mooood"]/a[@href="#mooood"]' 'mooood' +// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'mooood' /// ## mooood /// diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs index 5319892c99c23..7ae5bd6994579 100644 --- a/src/test/rustdoc/smart-punct.rs +++ b/src/test/rustdoc/smart-punct.rs @@ -21,7 +21,7 @@ //! ``` // @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?" -// @has "foo/index.html" "//h1" "Header with “smart punct’”" +// @has "foo/index.html" "//h2" "Header with “smart punct’”" // @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!" // @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\"" // @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";" diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs index 0b68d5e04f7a2..8051c58898e49 100644 --- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs @@ -1,4 +1,4 @@ -#![feature(box_syntax, plugin, rustc_private)] +#![feature(plugin, rustc_private)] #![crate_type = "dylib"] extern crate rustc_ast_pretty; @@ -21,7 +21,7 @@ use rustc_span::source_map; #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&MISSING_ALLOWED_ATTR]); - reg.lint_store.register_late_pass(|| box MissingAllowedAttrPass); + reg.lint_store.register_late_pass(|| Box::new(MissingAllowedAttrPass)); } declare_lint! { diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs index 0015a826126ff..e726f8402ef9d 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs @@ -1,7 +1,6 @@ // force-host #![feature(rustc_private)] -#![feature(box_syntax)] extern crate rustc_driver; extern crate rustc_hir; @@ -14,6 +13,7 @@ extern crate rustc_ast; use rustc_ast::attr; use rustc_driver::plugin::Registry; use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass}; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::Symbol; macro_rules! fake_lint_pass { @@ -27,13 +27,14 @@ macro_rules! fake_lint_pass { } impl LateLintPass<'_> for $struct { - fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) { + fn check_crate(&mut self, cx: &LateContext) { let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); + let span = cx.tcx.def_span(CRATE_DEF_ID); $( if !cx.sess().contains_name(attrs, $attr) { cx.lint(CRATE_NOT_OKAY, |lint| { let msg = format!("crate is not marked with #![{}]", $attr); - lint.build(&msg).set_span(krate.module().inner).emit() + lint.build(&msg).set_span(span).emit() }); } )* @@ -73,7 +74,7 @@ fn __rustc_plugin_registrar(reg: &mut Registry) { &CRATE_NOT_GREY, &CRATE_NOT_GREEN, ]); - reg.lint_store.register_late_pass(|| box PassOkay); - reg.lint_store.register_late_pass(|| box PassRedBlue); - reg.lint_store.register_late_pass(|| box PassGreyGreen); + reg.lint_store.register_late_pass(|| Box::new(PassOkay)); + reg.lint_store.register_late_pass(|| Box::new(PassRedBlue)); + reg.lint_store.register_late_pass(|| Box::new(PassGreyGreen)); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index 87c90b53648c7..4bbed5029802d 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -1,7 +1,6 @@ // force-host #![feature(rustc_private)] -#![feature(box_syntax)] extern crate rustc_driver; extern crate rustc_hir; @@ -9,13 +8,13 @@ extern crate rustc_hir; extern crate rustc_lint; #[macro_use] extern crate rustc_session; -extern crate rustc_span; extern crate rustc_ast; +extern crate rustc_span; use rustc_driver::plugin::Registry; -use rustc_lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::symbol::Symbol; -use rustc_ast::attr; declare_lint! { CRATE_NOT_OKAY, @@ -26,13 +25,12 @@ declare_lint! { declare_lint_pass!(Pass => [CRATE_NOT_OKAY]); impl<'tcx> LateLintPass<'tcx> for Pass { - fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) { + fn check_crate(&mut self, cx: &LateContext) { let attrs = cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); + let span = cx.tcx.def_span(CRATE_DEF_ID); if !cx.sess().contains_name(attrs, Symbol::intern("crate_okay")) { cx.lint(CRATE_NOT_OKAY, |lint| { - lint.build("crate is not marked with #![crate_okay]") - .set_span(krate.module().inner) - .emit() + lint.build("crate is not marked with #![crate_okay]").set_span(span).emit() }); } } @@ -41,5 +39,5 @@ impl<'tcx> LateLintPass<'tcx> for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]); - reg.lint_store.register_late_pass(|| box Pass); + reg.lint_store.register_late_pass(|| Box::new(Pass)); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs index f6ae560411b8e..253855fd2edd4 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs @@ -1,6 +1,6 @@ // force-host -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] // Load rustc as a plugin to get macros. extern crate rustc_driver; @@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]); - reg.lint_store.register_late_pass(|| box Pass); + reg.lint_store.register_late_pass(|| Box::new(Pass)); reg.lint_store.register_group( true, "lint_me", diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs index 32326bc8a5e50..42368ec36a028 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs @@ -1,6 +1,6 @@ // force-host -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_ast; @@ -31,5 +31,5 @@ impl EarlyLintPass for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_LINT]); - reg.lint_store.register_early_pass(|| box Pass); + reg.lint_store.register_early_pass(|| Box::new(Pass)); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs index 42c1c851de823..81feddf571323 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs @@ -1,4 +1,4 @@ -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_ast; @@ -46,7 +46,7 @@ impl EarlyLintPass for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_RUSTC_TOOL_LINT, &TEST_LINT, &TEST_GROUP]); - reg.lint_store.register_early_pass(|| box Pass); + reg.lint_store.register_early_pass(|| Box::new(Pass)); reg.lint_store.register_group( true, "clippy::group", diff --git a/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs b/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs index d0eedf23cafe9..e83dfe80463d8 100644 --- a/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs +++ b/src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs @@ -1,6 +1,6 @@ // force-host -#![feature(box_syntax, rustc_private)] +#![feature(rustc_private)] extern crate rustc_middle; extern crate rustc_driver; @@ -20,5 +20,5 @@ impl Drop for Foo { #[no_mangle] fn __rustc_plugin_registrar(_: &mut Registry) { thread_local!(static FOO: RefCell>> = RefCell::new(None)); - FOO.with(|s| *s.borrow_mut() = Some(box Foo { foo: 10 } as Box)); + FOO.with(|s| *s.borrow_mut() = Some(Box::new(Foo { foo: 10 }) as Box)); } diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs index 119fa3d6fa8ef..fab2031d95235 100644 --- a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs +++ b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs @@ -1,7 +1,6 @@ // run-pass #![allow(unused_imports)] -#![feature(box_syntax)] #![feature(rustc_private)] extern crate rustc_macros; diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.rs b/src/test/ui-fulldeps/hash-stable-is-unstable.rs index d93e21cf7916c..1be08191bc912 100644 --- a/src/test/ui-fulldeps/hash-stable-is-unstable.rs +++ b/src/test/ui-fulldeps/hash-stable-is-unstable.rs @@ -2,10 +2,10 @@ extern crate rustc_data_structures; //~^ use of unstable library feature 'rustc_private' -extern crate rustc_middle; -//~^ use of unstable library feature 'rustc_private' extern crate rustc_macros; //~^ use of unstable library feature 'rustc_private' +extern crate rustc_query_system; +//~^ use of unstable library feature 'rustc_private' use rustc_macros::HashStable; //~^ use of unstable library feature 'rustc_private' diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr index 212f63f709ec5..d25657691ed4d 100644 --- a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr +++ b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr @@ -10,7 +10,7 @@ LL | extern crate rustc_data_structures; error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:5:1 | -LL | extern crate rustc_middle; +LL | extern crate rustc_macros; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #27812 for more information @@ -19,8 +19,8 @@ LL | extern crate rustc_middle; error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:7:1 | -LL | extern crate rustc_macros; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | extern crate rustc_query_system; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #27812 for more information = help: add `#![feature(rustc_private)]` to the crate attributes to enable diff --git a/src/test/ui/alignment-gep-tup-like-1.rs b/src/test/ui/alignment-gep-tup-like-1.rs index adbd05ed8c175..eb503dcf3b63b 100644 --- a/src/test/ui/alignment-gep-tup-like-1.rs +++ b/src/test/ui/alignment-gep-tup-like-1.rs @@ -3,8 +3,6 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -#![feature(box_syntax)] - struct pair { a: A, b: B } @@ -25,10 +23,10 @@ impl Invokable for Invoker { } fn f(a: A, b: u16) -> Box+'static> { - box Invoker { + Box::new(Invoker { a: a, b: b, - } as Box+'static> + }) as Box+'static> } pub fn main() { diff --git a/src/test/ui/anon-params/anon-params-deprecated.stderr b/src/test/ui/anon-params/anon-params-deprecated.stderr index 98d52d659a9d3..474b14f59e3ab 100644 --- a/src/test/ui/anon-params/anon-params-deprecated.stderr +++ b/src/test/ui/anon-params/anon-params-deprecated.stderr @@ -1,4 +1,4 @@ -warning: anonymous parameters are deprecated and will be removed in the next edition. +warning: anonymous parameters are deprecated and will be removed in the next edition --> $DIR/anon-params-deprecated.rs:9:12 | LL | fn foo(i32); @@ -12,7 +12,7 @@ LL | #![warn(anonymous_parameters)] = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #41686 -warning: anonymous parameters are deprecated and will be removed in the next edition. +warning: anonymous parameters are deprecated and will be removed in the next edition --> $DIR/anon-params-deprecated.rs:12:30 | LL | fn bar_with_default_impl(String, String) {} @@ -21,7 +21,7 @@ LL | fn bar_with_default_impl(String, String) {} = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #41686 -warning: anonymous parameters are deprecated and will be removed in the next edition. +warning: anonymous parameters are deprecated and will be removed in the next edition --> $DIR/anon-params-deprecated.rs:12:38 | LL | fn bar_with_default_impl(String, String) {} diff --git a/src/test/ui/array-slice-vec/vec-dst.rs b/src/test/ui/array-slice-vec/vec-dst.rs index e741201652ba0..c58ddbc423946 100644 --- a/src/test/ui/array-slice-vec/vec-dst.rs +++ b/src/test/ui/array-slice-vec/vec-dst.rs @@ -1,11 +1,9 @@ // run-pass -#![feature(box_syntax)] - pub fn main() { - // Tests for indexing into box/& [T; n] + // Tests for indexing into Box<[T; n]>/& [T; n] let x: [isize; 3] = [1, 2, 3]; - let mut x: Box<[isize; 3]> = box x; + let mut x: Box<[isize; 3]> = x.into(); assert_eq!(x[0], 1); assert_eq!(x[1], 2); assert_eq!(x[2], 3); diff --git a/src/test/ui/array-slice-vec/vec-mut-iter-borrow.stderr b/src/test/ui/array-slice-vec/vec-mut-iter-borrow.stderr index 679fd8997733b..0ec263c850e9e 100644 --- a/src/test/ui/array-slice-vec/vec-mut-iter-borrow.stderr +++ b/src/test/ui/array-slice-vec/vec-mut-iter-borrow.stderr @@ -7,7 +7,7 @@ LL | for x in &mut xs { | first mutable borrow occurs here | first borrow later used here LL | xs.push(1) - | ^^ second mutable borrow occurs here + | ^^^^^^^^^^ second mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/array-slice-vec/vector-no-ann-2.rs b/src/test/ui/array-slice-vec/vector-no-ann-2.rs index dd8f402f3f6a5..e2055f551acc4 100644 --- a/src/test/ui/array-slice-vec/vector-no-ann-2.rs +++ b/src/test/ui/array-slice-vec/vector-no-ann-2.rs @@ -2,6 +2,6 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - -pub fn main() { let _quux: Box> = box Vec::new(); } +pub fn main() { + let _quux: Box> = Box::new(Vec::new()); +} diff --git a/src/test/ui/asm/aarch64/bad-options.rs b/src/test/ui/asm/aarch64/bad-options.rs new file mode 100644 index 0000000000000..8775eba4a7884 --- /dev/null +++ b/src/test/ui/asm/aarch64/bad-options.rs @@ -0,0 +1,39 @@ +// only-aarch64 + +#![feature(asm, global_asm)] + +fn main() { + let mut foo = 0; + unsafe { + asm!("", options(nomem, readonly)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + asm!("", options(pure, nomem, noreturn)); + //~^ ERROR the `pure` and `noreturn` options are mutually exclusive + //~^^ ERROR asm with the `pure` option must have at least one output + asm!("{}", in(reg) foo, options(pure, nomem)); + //~^ ERROR asm with the `pure` option must have at least one output + asm!("{}", out(reg) foo, options(noreturn)); + //~^ ERROR asm outputs are not allowed with the `noreturn` option + } + + unsafe { + asm!("", clobber_abi("foo")); + //~^ ERROR invalid ABI for `clobber_abi` + asm!("{}", out(reg) foo, clobber_abi("C")); + //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs + asm!("", out("x0") foo, clobber_abi("C")); + } +} + +global_asm!("", options(nomem)); +//~^ ERROR expected one of +global_asm!("", options(readonly)); +//~^ ERROR expected one of +global_asm!("", options(noreturn)); +//~^ ERROR expected one of +global_asm!("", options(pure)); +//~^ ERROR expected one of +global_asm!("", options(nostack)); +//~^ ERROR expected one of +global_asm!("", options(preserves_flags)); +//~^ ERROR expected one of diff --git a/src/test/ui/asm/aarch64/bad-options.stderr b/src/test/ui/asm/aarch64/bad-options.stderr new file mode 100644 index 0000000000000..21bcc4a9c7bad --- /dev/null +++ b/src/test/ui/asm/aarch64/bad-options.stderr @@ -0,0 +1,84 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/bad-options.rs:8:18 + | +LL | asm!("", options(nomem, readonly)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with the `pure` option must have at least one output + --> $DIR/bad-options.rs:13:33 + | +LL | asm!("{}", in(reg) foo, options(pure, nomem)); + | ^^^^^^^^^^^^^^^^^^^^ + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/bad-options.rs:15:20 + | +LL | asm!("{}", out(reg) foo, options(noreturn)); + | ^^^^^^^^^^^^ + +error: asm with `clobber_abi` must specify explicit registers for outputs + --> $DIR/bad-options.rs:22:20 + | +LL | asm!("{}", out(reg) foo, clobber_abi("C")); + | ^^^^^^^^^^^^ ---------------- clobber_abi + | | + | generic outputs + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/bad-options.rs:28:25 + | +LL | global_asm!("", options(nomem)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` + --> $DIR/bad-options.rs:30:25 + | +LL | global_asm!("", options(readonly)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` + --> $DIR/bad-options.rs:32:25 + | +LL | global_asm!("", options(noreturn)); + | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `pure` + --> $DIR/bad-options.rs:34:25 + | +LL | global_asm!("", options(pure)); + | ^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` + --> $DIR/bad-options.rs:36:25 + | +LL | global_asm!("", options(nostack)); + | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` + --> $DIR/bad-options.rs:38:25 + | +LL | global_asm!("", options(preserves_flags)); + | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: invalid ABI for `clobber_abi` + --> $DIR/bad-options.rs:20:18 + | +LL | asm!("", clobber_abi("foo")); + | ^^^^^^^^^^^^^^^^^^ + | + = note: the following ABIs are supported on this target: `C`, `system`, `efiapi` + +error: aborting due to 13 previous errors + diff --git a/src/test/ui/asm/aarch64/bad-reg.rs b/src/test/ui/asm/aarch64/bad-reg.rs new file mode 100644 index 0000000000000..22d0499a1cc1d --- /dev/null +++ b/src/test/ui/asm/aarch64/bad-reg.rs @@ -0,0 +1,59 @@ +// only-aarch64 +// compile-flags: -C target-feature=+fp + +#![feature(asm)] + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + // Bad register/register class + + asm!("{}", in(foo) foo); + //~^ ERROR invalid register class `foo`: unknown register class + asm!("", in("foo") foo); + //~^ ERROR invalid register `foo`: unknown register + asm!("{:z}", in(reg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:r}", in(vreg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:r}", in(vreg_low16) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:a}", const 0); + //~^ ERROR asm template modifiers are not allowed for `const` arguments + asm!("{:a}", sym main); + //~^ ERROR asm template modifiers are not allowed for `sym` arguments + asm!("", in("x29") foo); + //~^ ERROR invalid register `x29`: the frame pointer cannot be used as an operand + asm!("", in("sp") foo); + //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand + asm!("", in("xzr") foo); + //~^ ERROR invalid register `xzr`: the zero register cannot be used as an operand + asm!("", in("x18") foo); + //~^ ERROR invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm + asm!("", in("x19") foo); + //~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm + + asm!("", in("p0") foo); + //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + asm!("", out("p0") _); + asm!("{}", in(preg) foo); + //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + asm!("{}", out(preg) _); + //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output + + // Explicit register conflicts + // (except in/lateout which don't conflict) + + asm!("", in("x0") foo, in("w0") bar); + //~^ ERROR register `x0` conflicts with register `x0` + asm!("", in("x0") foo, out("x0") bar); + //~^ ERROR register `x0` conflicts with register `x0` + asm!("", in("w0") foo, lateout("w0") bar); + asm!("", in("v0") foo, in("q0") bar); + //~^ ERROR register `v0` conflicts with register `v0` + asm!("", in("v0") foo, out("q0") bar); + //~^ ERROR register `v0` conflicts with register `v0` + asm!("", in("v0") foo, lateout("q0") bar); + } +} diff --git a/src/test/ui/asm/aarch64/bad-reg.stderr b/src/test/ui/asm/aarch64/bad-reg.stderr new file mode 100644 index 0000000000000..091e6077ef404 --- /dev/null +++ b/src/test/ui/asm/aarch64/bad-reg.stderr @@ -0,0 +1,152 @@ +error: invalid register class `foo`: unknown register class + --> $DIR/bad-reg.rs:12:20 + | +LL | asm!("{}", in(foo) foo); + | ^^^^^^^^^^^ + +error: invalid register `foo`: unknown register + --> $DIR/bad-reg.rs:14:18 + | +LL | asm!("", in("foo") foo); + | ^^^^^^^^^^^^^ + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:16:15 + | +LL | asm!("{:z}", in(reg) foo); + | ^^^^ ----------- argument + | | + | template modifier + | + = note: the `reg` register class supports the following template modifiers: `w`, `x` + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:18:15 + | +LL | asm!("{:r}", in(vreg) foo); + | ^^^^ ------------ argument + | | + | template modifier + | + = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:20:15 + | +LL | asm!("{:r}", in(vreg_low16) foo); + | ^^^^ ------------------ argument + | | + | template modifier + | + = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v` + +error: asm template modifiers are not allowed for `const` arguments + --> $DIR/bad-reg.rs:22:15 + | +LL | asm!("{:a}", const 0); + | ^^^^ ------- argument + | | + | template modifier + +error: asm template modifiers are not allowed for `sym` arguments + --> $DIR/bad-reg.rs:24:15 + | +LL | asm!("{:a}", sym main); + | ^^^^ -------- argument + | | + | template modifier + +error: invalid register `x29`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:26:18 + | +LL | asm!("", in("x29") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:28:18 + | +LL | asm!("", in("sp") foo); + | ^^^^^^^^^^^^ + +error: invalid register `xzr`: the zero register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", in("xzr") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", in("x18") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:34:18 + | +LL | asm!("", in("x19") foo); + | ^^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:37:18 + | +LL | asm!("", in("p0") foo); + | ^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:40:20 + | +LL | asm!("{}", in(preg) foo); + | ^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:42:20 + | +LL | asm!("{}", out(preg) _); + | ^^^^^^^^^^^ + +error: register `x0` conflicts with register `x0` + --> $DIR/bad-reg.rs:48:32 + | +LL | asm!("", in("x0") foo, in("w0") bar); + | ------------ ^^^^^^^^^^^^ register `x0` + | | + | register `x0` + +error: register `x0` conflicts with register `x0` + --> $DIR/bad-reg.rs:50:32 + | +LL | asm!("", in("x0") foo, out("x0") bar); + | ------------ ^^^^^^^^^^^^^ register `x0` + | | + | register `x0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:50:18 + | +LL | asm!("", in("x0") foo, out("x0") bar); + | ^^^^^^^^^^^^ + +error: register `v0` conflicts with register `v0` + --> $DIR/bad-reg.rs:53:32 + | +LL | asm!("", in("v0") foo, in("q0") bar); + | ------------ ^^^^^^^^^^^^ register `v0` + | | + | register `v0` + +error: register `v0` conflicts with register `v0` + --> $DIR/bad-reg.rs:55:32 + | +LL | asm!("", in("v0") foo, out("q0") bar); + | ------------ ^^^^^^^^^^^^^ register `v0` + | | + | register `v0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:55:18 + | +LL | asm!("", in("v0") foo, out("q0") bar); + | ^^^^^^^^^^^^ + +error: aborting due to 19 previous errors + diff --git a/src/test/ui/asm/aarch64/const.rs b/src/test/ui/asm/aarch64/const.rs new file mode 100644 index 0000000000000..906dcb0ebab98 --- /dev/null +++ b/src/test/ui/asm/aarch64/const.rs @@ -0,0 +1,42 @@ +// min-llvm-version: 10.0.1 +// only-aarch64 +// run-pass +// revisions: mirunsafeck thirunsafeck +// [thirunsafeck]compile-flags: -Z thir-unsafeck + +#![feature(asm, global_asm)] + +fn const_generic() -> usize { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const X); + a + } +} + +const fn constfn(x: usize) -> usize { + x +} + +fn main() { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const 5); + assert_eq!(a, 5); + + let b: usize; + asm!("mov {}, {}", out(reg) b, const constfn(5)); + assert_eq!(b, 5); + + let c: usize; + asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5)); + assert_eq!(c, 10); + } + + let d = const_generic::<5>(); + assert_eq!(d, 5); +} + +global_asm!("mov x0, {}", const 5); +global_asm!("mov x0, {}", const constfn(5)); +global_asm!("mov x0, {}", const constfn(5) + constfn(5)); diff --git a/src/test/ui/asm/aarch64/duplicate-options.fixed b/src/test/ui/asm/aarch64/duplicate-options.fixed new file mode 100644 index 0000000000000..d95c646e9f955 --- /dev/null +++ b/src/test/ui/asm/aarch64/duplicate-options.fixed @@ -0,0 +1,26 @@ +// only-aarch64 +// run-rustfix + +#![feature(asm, global_asm)] + +fn main() { + unsafe { + asm!("", options(nomem, )); + //~^ ERROR the `nomem` option was already provided + asm!("", options(preserves_flags, )); + //~^ ERROR the `preserves_flags` option was already provided + asm!("", options(nostack, preserves_flags), options()); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, ), options(), options()); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(preserves_flags, ), //~ ERROR the `noreturn` option was already provided + options( nostack), //~ ERROR the `nomem` option was already provided + options(), //~ ERROR the `noreturn` option was already provided + ); + } +} diff --git a/src/test/ui/asm/aarch64/duplicate-options.rs b/src/test/ui/asm/aarch64/duplicate-options.rs new file mode 100644 index 0000000000000..eec356463d4d7 --- /dev/null +++ b/src/test/ui/asm/aarch64/duplicate-options.rs @@ -0,0 +1,26 @@ +// only-aarch64 +// run-rustfix + +#![feature(asm, global_asm)] + +fn main() { + unsafe { + asm!("", options(nomem, nomem)); + //~^ ERROR the `nomem` option was already provided + asm!("", options(preserves_flags, preserves_flags)); + //~^ ERROR the `preserves_flags` option was already provided + asm!("", options(nostack, preserves_flags), options(nostack)); + //~^ ERROR the `nostack` option was already provided + asm!("", options(nostack, nostack), options(nostack), options(nostack)); + //~^ ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + //~| ERROR the `nostack` option was already provided + asm!( + "", + options(nomem, noreturn), + options(preserves_flags, noreturn), //~ ERROR the `noreturn` option was already provided + options(nomem, nostack), //~ ERROR the `nomem` option was already provided + options(noreturn), //~ ERROR the `noreturn` option was already provided + ); + } +} diff --git a/src/test/ui/asm/aarch64/duplicate-options.stderr b/src/test/ui/asm/aarch64/duplicate-options.stderr new file mode 100644 index 0000000000000..5063b0c1235f0 --- /dev/null +++ b/src/test/ui/asm/aarch64/duplicate-options.stderr @@ -0,0 +1,56 @@ +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:8:33 + | +LL | asm!("", options(nomem, nomem)); + | ^^^^^ this option was already provided + +error: the `preserves_flags` option was already provided + --> $DIR/duplicate-options.rs:10:43 + | +LL | asm!("", options(preserves_flags, preserves_flags)); + | ^^^^^^^^^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:12:61 + | +LL | asm!("", options(nostack, preserves_flags), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:35 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:53 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `nostack` option was already provided + --> $DIR/duplicate-options.rs:14:71 + | +LL | asm!("", options(nostack, nostack), options(nostack), options(nostack)); + | ^^^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:21:38 + | +LL | options(preserves_flags, noreturn), + | ^^^^^^^^ this option was already provided + +error: the `nomem` option was already provided + --> $DIR/duplicate-options.rs:22:21 + | +LL | options(nomem, nostack), + | ^^^^^ this option was already provided + +error: the `noreturn` option was already provided + --> $DIR/duplicate-options.rs:23:21 + | +LL | options(noreturn), + | ^^^^^^^^ this option was already provided + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/asm/aarch64/interpolated-idents.rs b/src/test/ui/asm/aarch64/interpolated-idents.rs new file mode 100644 index 0000000000000..1cdf0965667f6 --- /dev/null +++ b/src/test/ui/asm/aarch64/interpolated-idents.rs @@ -0,0 +1,24 @@ +// only-aarch64 + +#![feature(asm)] + +macro_rules! m { + ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident + $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident + $noreturn:ident $nostack:ident $options:ident) => { + unsafe { + asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + //~^ ERROR asm outputs are not allowed with the `noreturn` option + const x, sym x, + $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + //~| ERROR the `pure` and `noreturn` options are mutually exclusive + } + }; +} + +fn main() { + m!(in out lateout inout inlateout const sym + pure nomem readonly preserves_flags + noreturn nostack options); +} diff --git a/src/test/ui/asm/aarch64/interpolated-idents.stderr b/src/test/ui/asm/aarch64/interpolated-idents.stderr new file mode 100644 index 0000000000000..d1ab13af84e25 --- /dev/null +++ b/src/test/ui/asm/aarch64/interpolated-idents.stderr @@ -0,0 +1,51 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack options); + | |_________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/interpolated-idents.rs:13:13 + | +LL | $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / m!(in out lateout inout inlateout const sym +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack options); + | |_________________________________- in this macro invocation + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/interpolated-idents.rs:10:32 + | +LL | asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x, + | ^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^ +... +LL | m!(in out lateout inout inlateout const sym + | _____- + | |_____| + | |_____| + | |_____| + | | +LL | | pure nomem readonly preserves_flags +LL | | noreturn nostack options); + | | - + | |_________________________________| + | |_________________________________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) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/asm/aarch64/parse-error.rs b/src/test/ui/asm/aarch64/parse-error.rs new file mode 100644 index 0000000000000..faa5e37b781ec --- /dev/null +++ b/src/test/ui/asm/aarch64/parse-error.rs @@ -0,0 +1,135 @@ +// only-aarch64 + +#![feature(asm, global_asm)] + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + asm!(); + //~^ ERROR requires at least a template string argument + asm!(foo); + //~^ ERROR asm template must be a string literal + asm!("{}" foo); + //~^ ERROR expected token: `,` + asm!("{}", foo); + //~^ ERROR expected operand, clobber_abi, options, or additional template string + asm!("{}", in foo); + //~^ ERROR expected `(`, found `foo` + asm!("{}", in(reg foo)); + //~^ ERROR expected `)`, found `foo` + asm!("{}", in(reg)); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", inout(=) foo => bar); + //~^ ERROR expected register class or explicit register + asm!("{}", inout(reg) foo =>); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", in(reg) foo => bar); + //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + asm!("{}", sym foo + bar); + //~^ ERROR argument to `sym` must be a path expression + asm!("", options(foo)); + //~^ ERROR expected one of + asm!("", options(nomem foo)); + //~^ ERROR expected one of + asm!("", options(nomem, foo)); + //~^ ERROR expected one of + asm!("{}", options(), const foo); + //~^ ERROR arguments are not allowed after options + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", clobber_abi(foo)); + //~^ ERROR expected string literal + asm!("", clobber_abi("C" foo)); + //~^ ERROR expected `)`, found `foo` + asm!("", clobber_abi("C", foo)); + //~^ ERROR expected `)`, found `,` + asm!("{}", clobber_abi("C"), const foo); + //~^ ERROR arguments are not allowed after clobber_abi + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", options(), clobber_abi("C")); + //~^ ERROR clobber_abi is not allowed after options + asm!("{}", options(), clobber_abi("C"), const foo); + //~^ ERROR clobber_abi is not allowed after options + asm!("", clobber_abi("C"), clobber_abi("C")); + //~^ ERROR clobber_abi specified multiple times + asm!("{a}", a = const foo, a = const bar); + //~^ ERROR duplicate argument named `a` + //~^^ ERROR argument never used + //~^^^ ERROR attempt to use a non-constant value in a constant + //~^^^^ ERROR attempt to use a non-constant value in a constant + asm!("", a = in("x0") foo); + //~^ ERROR explicit register arguments cannot have names + asm!("{a}", in("x0") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{a}", in("x0") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("{1}", in("x0") foo, const bar); + //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments + //~^^ ERROR attempt to use a non-constant value in a constant + asm!("", options(), ""); + //~^ ERROR expected one of + asm!("{}", in(reg) foo, "{}", out(reg) foo); + //~^ ERROR expected one of + asm!(format!("{{{}}}", 0), in(reg) foo); + //~^ ERROR asm template must be a string literal + asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + //~^ ERROR asm template must be a string literal + asm!("{}", in(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inout(reg) _); + //~^ ERROR _ cannot be used for input operands + asm!("{}", inlateout(reg) _); + //~^ ERROR _ cannot be used for input operands + } +} + +const FOO: i32 = 1; +const BAR: i32 = 2; +global_asm!(); +//~^ ERROR requires at least a template string argument +global_asm!(FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{}" FOO); +//~^ ERROR expected token: `,` +global_asm!("{}", FOO); +//~^ ERROR expected operand, options, or additional template string +global_asm!("{}", const); +//~^ ERROR expected expression, found end of macro arguments +global_asm!("{}", const(reg) FOO); +//~^ ERROR expected one of +global_asm!("", options(FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem FOO)); +//~^ ERROR expected one of +global_asm!("", options(nomem, FOO)); +//~^ ERROR expected one of +global_asm!("{}", options(), const FOO); +//~^ ERROR arguments are not allowed after options +global_asm!("", clobber_abi(FOO)); +//~^ ERROR expected string literal +global_asm!("", clobber_abi("C" FOO)); +//~^ ERROR expected `)`, found `FOO` +global_asm!("", clobber_abi("C", FOO)); +//~^ ERROR expected `)`, found `,` +global_asm!("{}", clobber_abi("C"), const FOO); +//~^ ERROR arguments are not allowed after clobber_abi +//~^^ ERROR `clobber_abi` cannot be used with `global_asm!` +global_asm!("", options(), clobber_abi("C")); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("{}", options(), clobber_abi("C"), const FOO); +//~^ ERROR clobber_abi is not allowed after options +global_asm!("", clobber_abi("C"), clobber_abi("C")); +//~^ ERROR clobber_abi specified multiple times +global_asm!("{a}", a = const FOO, a = const BAR); +//~^ ERROR duplicate argument named `a` +//~^^ ERROR argument never used +global_asm!("", options(), ""); +//~^ ERROR expected one of +global_asm!("{}", const FOO, "{}", const FOO); +//~^ ERROR expected one of +global_asm!(format!("{{{}}}", 0), const FOO); +//~^ ERROR asm template must be a string literal +global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); +//~^ ERROR asm template must be a string literal diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr new file mode 100644 index 0000000000000..7b9fa90f70c25 --- /dev/null +++ b/src/test/ui/asm/aarch64/parse-error.stderr @@ -0,0 +1,462 @@ +error: requires at least a template string argument + --> $DIR/parse-error.rs:9:9 + | +LL | asm!(); + | ^^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:11:14 + | +LL | asm!(foo); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:13:19 + | +LL | asm!("{}" foo); + | ^^^ expected `,` + +error: expected operand, clobber_abi, options, or additional template string + --> $DIR/parse-error.rs:15:20 + | +LL | asm!("{}", foo); + | ^^^ expected operand, clobber_abi, options, or additional template string + +error: expected `(`, found `foo` + --> $DIR/parse-error.rs:17:23 + | +LL | asm!("{}", in foo); + | ^^^ expected `(` + +error: expected `)`, found `foo` + --> $DIR/parse-error.rs:19:27 + | +LL | asm!("{}", in(reg foo)); + | ^^^ expected `)` + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:21:27 + | +LL | asm!("{}", in(reg)); + | ^ expected expression + +error: expected register class or explicit register + --> $DIR/parse-error.rs:23:26 + | +LL | asm!("{}", inout(=) foo => bar); + | ^ + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:25:37 + | +LL | asm!("{}", inout(reg) foo =>); + | ^ expected expression + +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + --> $DIR/parse-error.rs:27:32 + | +LL | asm!("{}", in(reg) foo => bar); + | ^^ expected one of 7 possible tokens + +error: argument to `sym` must be a path expression + --> $DIR/parse-error.rs:29:24 + | +LL | asm!("{}", sym foo + bar); + | ^^^^^^^^^ + +error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:31:26 + | +LL | asm!("", options(foo)); + | ^^^ expected one of 9 possible tokens + +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:33:32 + | +LL | asm!("", options(nomem foo)); + | ^^^ expected one of `)` or `,` + +error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:35:33 + | +LL | asm!("", options(nomem, foo)); + | ^^^ expected one of 9 possible tokens + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:37:31 + | +LL | asm!("{}", options(), const foo); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: expected string literal + --> $DIR/parse-error.rs:40:30 + | +LL | asm!("", clobber_abi(foo)); + | ^^^ not a string literal + +error: expected `)`, found `foo` + --> $DIR/parse-error.rs:42:34 + | +LL | asm!("", clobber_abi("C" foo)); + | ^^^ expected `)` + +error: expected `)`, found `,` + --> $DIR/parse-error.rs:44:33 + | +LL | asm!("", clobber_abi("C", foo)); + | ^ expected `)` + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:46:38 + | +LL | asm!("{}", clobber_abi("C"), const foo); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:49:29 + | +LL | asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:51:31 + | +LL | asm!("{}", options(), clobber_abi("C"), const foo); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi specified multiple times + --> $DIR/parse-error.rs:53:36 + | +LL | asm!("", clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | clobber_abi previously specified here + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:55:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:55:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: explicit register arguments cannot have names + --> $DIR/parse-error.rs:60:18 + | +LL | asm!("", a = in("x0") foo); + | ^^^^^^^^^^^^^^^^ + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:62:35 + | +LL | asm!("{a}", in("x0") foo, a = const bar); + | ------------ ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:65:35 + | +LL | asm!("{a}", in("x0") foo, a = const bar); + | ------------ ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: positional arguments cannot follow named arguments or explicit register arguments + --> $DIR/parse-error.rs:68:35 + | +LL | asm!("{1}", in("x0") foo, const bar); + | ------------ ^^^^^^^^^ positional argument + | | + | explicit register argument + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""` + --> $DIR/parse-error.rs:71:29 + | +LL | asm!("", options(), ""); + | ^^ expected one of 9 possible tokens + +error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"` + --> $DIR/parse-error.rs:73:33 + | +LL | asm!("{}", in(reg) foo, "{}", out(reg) foo); + | ^^^^ expected one of 9 possible tokens + +error: asm template must be a string literal + --> $DIR/parse-error.rs:75:14 + | +LL | asm!(format!("{{{}}}", 0), in(reg) foo); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:77:21 + | +LL | asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:79:28 + | +LL | asm!("{}", in(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:81:31 + | +LL | asm!("{}", inout(reg) _); + | ^ + +error: _ cannot be used for input operands + --> $DIR/parse-error.rs:83:35 + | +LL | asm!("{}", inlateout(reg) _); + | ^ + +error: requires at least a template string argument + --> $DIR/parse-error.rs:90:1 + | +LL | global_asm!(); + | ^^^^^^^^^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:92:13 + | +LL | global_asm!(FOO); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:94:18 + | +LL | global_asm!("{}" FOO); + | ^^^ expected `,` + +error: expected operand, options, or additional template string + --> $DIR/parse-error.rs:96:19 + | +LL | global_asm!("{}", FOO); + | ^^^ expected operand, options, or additional template string + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:98:24 + | +LL | global_asm!("{}", const); + | ^ expected expression + +error: expected one of `,`, `.`, `?`, or an operator, found `FOO` + --> $DIR/parse-error.rs:100:30 + | +LL | global_asm!("{}", const(reg) FOO); + | ^^^ expected one of `,`, `.`, `?`, or an operator + +error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` + --> $DIR/parse-error.rs:102:25 + | +LL | global_asm!("", options(FOO)); + | ^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:104:25 + | +LL | global_asm!("", options(nomem FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` + --> $DIR/parse-error.rs:106:25 + | +LL | global_asm!("", options(nomem, FOO)); + | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:108:30 + | +LL | global_asm!("{}", options(), const FOO); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: expected string literal + --> $DIR/parse-error.rs:110:29 + | +LL | global_asm!("", clobber_abi(FOO)); + | ^^^ not a string literal + +error: expected `)`, found `FOO` + --> $DIR/parse-error.rs:112:33 + | +LL | global_asm!("", clobber_abi("C" FOO)); + | ^^^ expected `)` + +error: expected `)`, found `,` + --> $DIR/parse-error.rs:114:32 + | +LL | global_asm!("", clobber_abi("C", FOO)); + | ^ expected `)` + +error: arguments are not allowed after clobber_abi + --> $DIR/parse-error.rs:116:37 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ---------------- ^^^^^^^^^ argument + | | + | clobber_abi + +error: `clobber_abi` cannot be used with `global_asm!` + --> $DIR/parse-error.rs:116:19 + | +LL | global_asm!("{}", clobber_abi("C"), const FOO); + | ^^^^^^^^^^^^^^^^ + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:119:28 + | +LL | global_asm!("", options(), clobber_abi("C")); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi is not allowed after options + --> $DIR/parse-error.rs:121:30 + | +LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); + | --------- ^^^^^^^^^^^^^^^^ + | | + | options + +error: clobber_abi specified multiple times + --> $DIR/parse-error.rs:123:35 + | +LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); + | ---------------- ^^^^^^^^^^^^^^^^ + | | + | clobber_abi previously specified here + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:125:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:125:35 + | +LL | global_asm!("{a}", a = const FOO, a = const BAR); + | ^^^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` + +error: expected one of `clobber_abi`, `const`, or `options`, found `""` + --> $DIR/parse-error.rs:128:28 + | +LL | global_asm!("", options(), ""); + | ^^ expected one of `clobber_abi`, `const`, or `options` + +error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"` + --> $DIR/parse-error.rs:130:30 + | +LL | global_asm!("{}", const FOO, "{}", const FOO); + | ^^^^ expected one of `clobber_abi`, `const`, or `options` + +error: asm template must be a string literal + --> $DIR/parse-error.rs:132:13 + | +LL | global_asm!(format!("{{{}}}", 0), const FOO); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: asm template must be a string literal + --> $DIR/parse-error.rs:134:20 + | +LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:37:37 + | +LL | let mut foo = 0; + | ---------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", options(), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:46:44 + | +LL | let mut foo = 0; + | ---------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{}", clobber_abi("C"), const foo); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:55:31 + | +LL | let mut foo = 0; + | ---------- help: consider using `const` instead of `let`: `const foo` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:55:46 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:62:45 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("x0") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:65:45 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{a}", in("x0") foo, a = const bar); + | ^^^ non-constant value + +error[E0435]: attempt to use a non-constant value in a constant + --> $DIR/parse-error.rs:68:41 + | +LL | let mut bar = 0; + | ---------- help: consider using `const` instead of `let`: `const bar` +... +LL | asm!("{1}", in("x0") foo, const bar); + | ^^^ non-constant value + +error: aborting due to 66 previous errors + +For more information about this error, try `rustc --explain E0435`. diff --git a/src/test/ui/asm/aarch64/srcloc.rs b/src/test/ui/asm/aarch64/srcloc.rs new file mode 100644 index 0000000000000..58feb52653740 --- /dev/null +++ b/src/test/ui/asm/aarch64/srcloc.rs @@ -0,0 +1,121 @@ +// min-llvm-version: 10.0.1 +// only-aarch64 +// build-fail +// compile-flags: -Ccodegen-units=1 +#![feature(asm)] + +// Checks that inline asm errors are mapped to the correct line in the source code. + +fn main() { + unsafe { + asm!("invalid_instruction"); + //~^ ERROR: unrecognized instruction mnemonic + + asm!(" + invalid_instruction + "); + //~^^ ERROR: unrecognized instruction mnemonic + + asm!(r#" + invalid_instruction + "#); + //~^^ ERROR: unrecognized instruction mnemonic + + asm!(" + mov x0, x0 + invalid_instruction + mov x0, x0 + "); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!(r#" + mov x0, x0 + invalid_instruction + mov x0, x0 + "#); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!(concat!("invalid", "_", "instruction")); + //~^ ERROR: unrecognized instruction mnemonic + + asm!( + "invalid_instruction", + ); + //~^^ ERROR: unrecognized instruction mnemonic + + asm!( + "mov x0, x0", + "invalid_instruction", + "mov x0, x0", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + "mov x0, x0\n", + "invalid_instruction", + "mov x0, x0", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + "mov x0, x0", + concat!("invalid", "_", "instruction"), + "mov x0, x0", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!("mov x0", ", ", "x0"), + concat!("invalid", "_", "instruction"), + concat!("mov x0", ", ", "x0"), + ); + //~^^^ ERROR: unrecognized instruction mnemonic + + // Make sure template strings get separated + asm!( + "invalid_instruction1", + "invalid_instruction2", + ); + //~^^^ ERROR: unrecognized instruction mnemonic + //~^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + ); + //~^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", + ), + ); + //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^ ERROR: unrecognized instruction mnemonic + + asm!( + concat!( + "invalid", "_", "instruction1", "\n", + "invalid", "_", "instruction2", "\n", + ), + concat!( + "invalid", "_", "instruction3", "\n", + "invalid", "_", "instruction4", "\n", + ), + ); + //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^ ERROR: unrecognized instruction mnemonic + //~^^^^^^^^ ERROR: unrecognized instruction mnemonic + } +} diff --git a/src/test/ui/asm/aarch64/srcloc.stderr b/src/test/ui/asm/aarch64/srcloc.stderr new file mode 100644 index 0000000000000..96dab1bce0b75 --- /dev/null +++ b/src/test/ui/asm/aarch64/srcloc.stderr @@ -0,0 +1,278 @@ +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:11:15 + | +LL | asm!("invalid_instruction"); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:15:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:20:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:26:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:33:13 + | +LL | invalid_instruction + | ^ + | +note: instantiated into assembly here + --> :3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:38:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:42:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:48:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:55:14 + | +LL | "invalid_instruction", + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:62:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:69:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:76:14 + | +LL | "invalid_instruction1", + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:77:14 + | +LL | "invalid_instruction2", + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:83:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:83:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:92:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:92:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :3:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:107:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:107:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :4:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | concat!( + | ^ + | +note: instantiated into assembly here + --> :5:1 + | +LL | invalid_instruction4 + | ^ + +error: aborting due to 23 previous errors + diff --git a/src/test/ui/asm/aarch64/sym.rs b/src/test/ui/asm/aarch64/sym.rs new file mode 100644 index 0000000000000..db732e96b80b6 --- /dev/null +++ b/src/test/ui/asm/aarch64/sym.rs @@ -0,0 +1,80 @@ +// min-llvm-version: 10.0.1 +// only-aarch64 +// only-linux +// run-pass + +#![feature(asm, thread_local)] + +extern "C" fn f1() -> i32 { + 111 +} + +// The compiler will generate a shim to hide the caller location parameter. +#[track_caller] +fn f2() -> i32 { + 222 +} + +macro_rules! call { + ($func:path) => { + unsafe { + let result: i32; + asm!("bl {}", sym $func, + out("w0") result, + out("x20") _, out("x21") _, out("x22") _, + out("x23") _, out("x24") _, out("x25") _, + out("x26") _, out("x27") _, out("x28") _, + ); + result + } + } +} + +macro_rules! static_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + asm!( + // ADRP gives the address of a 4KB page from a PC-relative address + "adrp {out}, {sym}", + // We then add the remaining lower 12 bits + "add {out}, {out}, #:lo12:{sym}", + out = out(reg) result, + sym = sym $s); + result + } + } +} +macro_rules! static_tls_addr { + ($s:expr) => { + unsafe { + let result: *const u32; + asm!( + // Load the thread pointer register + "mrs {out}, TPIDR_EL0", + // Add the top 12 bits of the symbol's offset + "add {out}, {out}, :tprel_hi12:{sym}", + // And the bottom 12 bits + "add {out}, {out}, :tprel_lo12:{sym}", + out = out(reg) result, + sym = sym $s + ); + result + } + } +} + +static S1: u32 = 111; +#[thread_local] +static S2: u32 = 222; + +fn main() { + assert_eq!(call!(f1), 111); + assert_eq!(call!(f2), 222); + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + std::thread::spawn(|| { + assert_eq!(static_addr!(S1), &S1 as *const u32); + assert_eq!(static_tls_addr!(S2), &S2 as *const u32); + }).join().unwrap(); +} diff --git a/src/test/ui/asm/aarch64/type-check-2.rs b/src/test/ui/asm/aarch64/type-check-2.rs new file mode 100644 index 0000000000000..cf25dcb930c79 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-2.rs @@ -0,0 +1,84 @@ +// only-aarch64 + +#![feature(asm, repr_simd, never_type)] + +#[repr(simd)] +#[derive(Clone, Copy)] +struct SimdType(f32, f32, f32, f32); + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + let x: u64; + asm!("{}", in(reg) x); + //~^ ERROR use of possibly-uninitialized variable: `x` + let mut y: u64; + asm!("{}", inout(reg) y); + //~^ ERROR use of possibly-uninitialized variable: `y` + let _ = y; + + // Outputs require mutable places + + let v: Vec = vec![0, 1, 2]; + asm!("{}", in(reg) v[0]); + asm!("{}", out(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + asm!("{}", inout(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + + // Sym operands must point to a function or static + + const C: i32 = 0; + static S: i32 = 0; + asm!("{}", sym S); + asm!("{}", sym main); + asm!("{}", sym C); + //~^ ERROR asm `sym` operand must point to a fn or static + asm!("{}", sym x); + //~^ ERROR asm `sym` operand must point to a fn or static + + // Register operands must be Copy + + asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + //~^ ERROR arguments for inline assembly must be copyable + + // Register operands must be integers, floats, SIMD vectors, pointers or + // function pointers. + + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + asm!("{:v}", in(vreg) SimdType(0.0, 0.0, 0.0, 0.0)); + asm!("{}", in(reg) 0 as *const u8); + asm!("{}", in(reg) 0 as *mut u8); + asm!("{}", in(reg) main as fn()); + asm!("{}", in(reg) |x: i32| x); + //~^ ERROR cannot use value of type + asm!("{}", in(reg) vec![0]); + //~^ ERROR cannot use value of type `Vec` for inline assembly + asm!("{}", in(reg) (1, 2, 3)); + //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly + asm!("{}", in(reg) [1, 2, 3]); + //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly + + // Register inputs (but not outputs) allow references and function types + + let mut f = main; + let mut r = &mut 0; + asm!("{}", in(reg) f); + asm!("{}", inout(reg) f); + //~^ ERROR cannot use value of type `fn() {main}` for inline assembly + asm!("{}", in(reg) r); + asm!("{}", inout(reg) r); + //~^ ERROR cannot use value of type `&mut i32` for inline assembly + let _ = (f, r); + + // Type checks ignore never type + + let u: ! = unreachable!(); + asm!("{}", in(reg) u); + } +} diff --git a/src/test/ui/asm/aarch64/type-check-2.stderr b/src/test/ui/asm/aarch64/type-check-2.stderr new file mode 100644 index 0000000000000..e8209064d2d54 --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-2.stderr @@ -0,0 +1,103 @@ +error: arguments for inline assembly must be copyable + --> $DIR/type-check-2.rs:46:31 + | +LL | asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `SimdNonCopy` does not implement the Copy trait + +error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly + --> $DIR/type-check-2.rs:58:28 + | +LL | asm!("{}", in(reg) |x: i32| x); + | ^^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `Vec` for inline assembly + --> $DIR/type-check-2.rs:60:28 + | +LL | asm!("{}", in(reg) vec![0]); + | ^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use value of type `(i32, i32, i32)` for inline assembly + --> $DIR/type-check-2.rs:62:28 + | +LL | asm!("{}", in(reg) (1, 2, 3)); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[i32; 3]` for inline assembly + --> $DIR/type-check-2.rs:64:28 + | +LL | asm!("{}", in(reg) [1, 2, 3]); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `fn() {main}` for inline assembly + --> $DIR/type-check-2.rs:72:31 + | +LL | asm!("{}", inout(reg) f); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `&mut i32` for inline assembly + --> $DIR/type-check-2.rs:75:31 + | +LL | asm!("{}", inout(reg) r); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: asm `sym` operand must point to a fn or static + --> $DIR/type-check-2.rs:39:24 + | +LL | asm!("{}", sym C); + | ^ + +error: asm `sym` operand must point to a fn or static + --> $DIR/type-check-2.rs:41:24 + | +LL | asm!("{}", sym x); + | ^ + +error[E0381]: use of possibly-uninitialized variable: `x` + --> $DIR/type-check-2.rs:17:28 + | +LL | asm!("{}", in(reg) x); + | ^ use of possibly-uninitialized `x` + +error[E0381]: use of possibly-uninitialized variable: `y` + --> $DIR/type-check-2.rs:20:9 + | +LL | asm!("{}", inout(reg) y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2.rs:28:29 + | +LL | let v: Vec = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +LL | asm!("{}", in(reg) v[0]); +LL | asm!("{}", out(reg) v[0]); + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2.rs:30:31 + | +LL | let v: Vec = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +... +LL | asm!("{}", inout(reg) v[0]); + | ^ cannot borrow as mutable + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0381, E0596. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/asm/aarch64/type-check-3.rs b/src/test/ui/asm/aarch64/type-check-3.rs new file mode 100644 index 0000000000000..d0d5954ca4aef --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-3.rs @@ -0,0 +1,115 @@ +// only-aarch64 +// compile-flags: -C target-feature=+neon + +#![feature(asm, global_asm, repr_simd, stdsimd)] + +use std::arch::aarch64::float64x2_t; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct Simd256bit(f64, f64,f64, f64); + +fn main() { + let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) }; + let f64x4 = Simd256bit(0.0, 0.0, 0.0, 0.0); + + unsafe { + // Types must be listed in the register class. + + // Success cases + asm!("{:w}", in(reg) 0u8); + asm!("{:w}", in(reg) 0u16); + asm!("{:w}", in(reg) 0u32); + asm!("{:w}", in(reg) 0f32); + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + + asm!("{:b}", in(vreg) 0u8); + asm!("{:h}", in(vreg) 0u16); + asm!("{:s}", in(vreg) 0u32); + asm!("{:s}", in(vreg) 0f32); + asm!("{:d}", in(vreg) 0u64); + asm!("{:d}", in(vreg) 0f64); + asm!("{:q}", in(vreg) f64x2); + asm!("{:v}", in(vreg) f64x2); + + // Should be the same as vreg + asm!("{:q}", in(vreg_low16) f64x2); + + // Template modifiers of a different size to the argument are fine + asm!("{:w}", in(reg) 0u64); + asm!("{:x}", in(reg) 0u32); + asm!("{:b}", in(vreg) 0u64); + asm!("{:d}", in(vreg_low16) f64x2); + + + // Template modifier suggestions for sub-registers + + asm!("{}", in(reg) 0u8); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0u16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0i32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0f32); + //~^ WARN formatting may not be suitable for sub-register argument + + asm!("{}", in(vreg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(vreg) 0f32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(vreg) 0f64); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(vreg_low16) 0f64); + //~^ WARN formatting may not be suitable for sub-register argument + + asm!("{0} {0}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{0} {0:x}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + + // Invalid registers + + asm!("{}", in(reg) 0i128); + //~^ ERROR type `i128` cannot be used with this register class + asm!("{}", in(reg) f64x2); + //~^ ERROR type `float64x2_t` cannot be used with this register class + asm!("{}", in(vreg) f64x4); + //~^ ERROR type `Simd256bit` cannot be used with this register class + + // Split inout operands must have compatible types + + let mut val_i16: i16; + let mut val_f32: f32; + let mut val_u32: u32; + let mut val_u64: u64; + let mut val_ptr: *mut u8; + asm!("{:x}", inout(reg) 0u16 => val_i16); + asm!("{:x}", inout(reg) 0u32 => val_f32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:x}", inout(reg) 0u32 => val_ptr); + //~^ ERROR incompatible types for asm inout argument + asm!("{:x}", inout(reg) main => val_u32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:x}", inout(reg) 0u64 => val_ptr); + asm!("{:x}", inout(reg) main => val_u64); + } +} + +// Constants must be... constant + +static S: i32 = 1; +const fn const_foo(x: i32) -> i32 { + x +} +const fn const_bar(x: T) -> T { + x +} +global_asm!("{}", const S); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_foo(0)); +global_asm!("{}", const const_foo(S)); +//~^ ERROR constants cannot refer to statics +global_asm!("{}", const const_bar(0)); +global_asm!("{}", const const_bar(S)); +//~^ ERROR constants cannot refer to statics diff --git a/src/test/ui/asm/aarch64/type-check-3.stderr b/src/test/ui/asm/aarch64/type-check-3.stderr new file mode 100644 index 0000000000000..c31a62ae7912a --- /dev/null +++ b/src/test/ui/asm/aarch64/type-check-3.stderr @@ -0,0 +1,172 @@ +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:48:15 + | +LL | asm!("{}", in(reg) 0u8); + | ^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:50:15 + | +LL | asm!("{}", in(reg) 0u16); + | ^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:52:15 + | +LL | asm!("{}", in(reg) 0i32); + | ^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:54:15 + | +LL | asm!("{}", in(reg) 0f32); + | ^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:57:15 + | +LL | asm!("{}", in(vreg) 0i16); + | ^^ ---- for this argument + | + = help: use the `h` modifier to have the register formatted as `h0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:59:15 + | +LL | asm!("{}", in(vreg) 0f32); + | ^^ ---- for this argument + | + = help: use the `s` modifier to have the register formatted as `s0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:61:15 + | +LL | asm!("{}", in(vreg) 0f64); + | ^^ ---- for this argument + | + = help: use the `d` modifier to have the register formatted as `d0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:63:15 + | +LL | asm!("{}", in(vreg_low16) 0f64); + | ^^ ---- for this argument + | + = help: use the `d` modifier to have the register formatted as `d0` + = help: or use the `v` modifier to keep the default formatting of `v0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:66:15 + | +LL | asm!("{0} {0}", in(reg) 0i16); + | ^^^ ^^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:68:15 + | +LL | asm!("{0} {0:x}", in(reg) 0i16); + | ^^^ ---- for this argument + | + = help: use the `w` modifier to have the register formatted as `w0` + = help: or use the `x` modifier to keep the default formatting of `x0` + +error: type `i128` cannot be used with this register class + --> $DIR/type-check-3.rs:73:28 + | +LL | asm!("{}", in(reg) 0i128); + | ^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + +error: type `float64x2_t` cannot be used with this register class + --> $DIR/type-check-3.rs:75:28 + | +LL | asm!("{}", in(reg) f64x2); + | ^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + +error: type `Simd256bit` cannot be used with this register class + --> $DIR/type-check-3.rs:77:29 + | +LL | asm!("{}", in(vreg) f64x4); + | ^^^^^ + | + = note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:88:33 + | +LL | asm!("{:x}", inout(reg) 0u32 => val_f32); + | ^^^^ ^^^^^^^ type `f32` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:90:33 + | +LL | asm!("{:x}", inout(reg) 0u32 => val_ptr); + | ^^^^ ^^^^^^^ type `*mut u8` + | | + | type `u32` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:92:33 + | +LL | asm!("{:x}", inout(reg) main => val_u32); + | ^^^^ ^^^^^^^ type `u32` + | | + | type `fn()` + | + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-3.rs:108:25 + | +LL | global_asm!("{}", const S); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-3.rs:111:35 + | +LL | global_asm!("{}", const const_foo(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0013]: constants cannot refer to statics + --> $DIR/type-check-3.rs:114:35 + | +LL | global_asm!("{}", const const_bar(S)); + | ^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error: aborting due to 9 previous errors; 10 warnings emitted + +For more information about this error, try `rustc --explain E0013`. diff --git a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr new file mode 100644 index 0000000000000..3b1d922a7f757 --- /dev/null +++ b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr @@ -0,0 +1,187 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:15 + | +LL | asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:48:15 + | +LL | asm!("{}", in("x0") foo); + | ^^ ------------ explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:48:20 + | +LL | asm!("{}", in("x0") foo); + | ^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:52:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:58:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:60:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:60:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:63:14 + | +LL | global_asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:65:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:68:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:68:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:71:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:73:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: aborting due to 21 previous errors + diff --git a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr new file mode 100644 index 0000000000000..3b1d922a7f757 --- /dev/null +++ b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr @@ -0,0 +1,187 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:31:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:33:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:33:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:36:15 + | +LL | asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:38:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:38:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:41:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:41:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:48:15 + | +LL | asm!("{}", in("x0") foo); + | ^^ ------------ explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:48:20 + | +LL | asm!("{}", in("x0") foo); + | ^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:50:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:52:18 + | +LL | asm!("", in(reg) 0, in(reg) 1); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:58:14 + | +LL | global_asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:60:14 + | +LL | global_asm!("{1}", const FOO); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:60:20 + | +LL | global_asm!("{1}", const FOO); + | ^^^^^^^^^ argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` + +error: there is no argument named `a` + --> $DIR/bad-template.rs:63:14 + | +LL | global_asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:65:14 + | +LL | global_asm!("{}", a = const FOO); + | ^^ ------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:65:19 + | +LL | global_asm!("{}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:68:14 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:68:20 + | +LL | global_asm!("{1}", a = const FOO); + | ^^^^^^^^^^^^^ named argument never used + | + = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:71:16 + | +LL | global_asm!("{:foo}", const FOO); + | ^^^ + +error: multiple unused asm arguments + --> $DIR/bad-template.rs:73:17 + | +LL | global_asm!("", const FOO, const FOO); + | ^^^^^^^^^ ^^^^^^^^^ argument never used + | | + | argument never used + | + = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` + +error: aborting due to 21 previous errors + diff --git a/src/test/ui/asm/bad-template.rs b/src/test/ui/asm/bad-template.rs index 5aed2c62f0bdd..fca77e7aa71f3 100644 --- a/src/test/ui/asm/bad-template.rs +++ b/src/test/ui/asm/bad-template.rs @@ -1,8 +1,29 @@ -// only-x86_64 -// revisions: mirunsafeck thirunsafeck -// [thirunsafeck]compile-flags: -Z thir-unsafeck +// revisions: x86_64_mirunsafeck aarch64_mirunsafeck x86_64_thirunsafeck aarch64_thirunsafeck -#![feature(asm, global_asm)] +// [x86_64_thirunsafeck] compile-flags: -Z thir-unsafeck --target x86_64-unknown-linux-gnu +// [aarch64_thirunsafeck] compile-flags: -Z thir-unsafeck --target aarch64-unknown-linux-gnu +// [x86_64_mirunsafeck] compile-flags: --target x86_64-unknown-linux-gnu +// [aarch64_mirunsafeck] compile-flags: --target aarch64-unknown-linux-gnu + +// [x86_64_thirunsafeck] needs-llvm-components: x86 +// [x86_64_mirunsafeck] needs-llvm-components: x86 +// [aarch64_thirunsafeck] needs-llvm-components: aarch64 +// [aarch64_mirunsafeck] needs-llvm-components: aarch64 + +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! global_asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} fn main() { let mut foo = 0; @@ -20,8 +41,12 @@ fn main() { asm!("{1}", a = in(reg) foo); //~^ ERROR invalid reference to argument at index 1 //~^^ ERROR named argument never used + #[cfg(any(x86_64_thirunsafeck, x86_64_mirunsafeck))] asm!("{}", in("eax") foo); - //~^ ERROR invalid reference to argument at index 0 + //[x86_64_thirunsafeck,x86_64_mirunsafeck]~^ ERROR invalid reference to argument at index 0 + #[cfg(any(aarch64_thirunsafeck, aarch64_mirunsafeck))] + asm!("{}", in("x0") foo); + //[aarch64_thirunsafeck,aarch64_mirunsafeck]~^ ERROR invalid reference to argument at index 0 asm!("{:foo}", in(reg) foo); //~^ ERROR asm template modifier must be a single character asm!("", in(reg) 0, in(reg) 1); diff --git a/src/test/ui/asm/bad-template.mirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr similarity index 85% rename from src/test/ui/asm/bad-template.mirunsafeck.stderr rename to src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr index 13ef032ab1071..3b69186f1e18b 100644 --- a/src/test/ui/asm/bad-template.mirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr @@ -1,5 +1,5 @@ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:10:15 + --> $DIR/bad-template.rs:31:15 | LL | asm!("{}"); | ^^ from here @@ -7,7 +7,7 @@ LL | asm!("{}"); = note: no arguments were given error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:12:15 + --> $DIR/bad-template.rs:33:15 | LL | asm!("{1}", in(reg) foo); | ^^^ from here @@ -15,7 +15,7 @@ LL | asm!("{1}", in(reg) foo); = note: there is 1 argument error: argument never used - --> $DIR/bad-template.rs:12:21 + --> $DIR/bad-template.rs:33:21 | LL | asm!("{1}", in(reg) foo); | ^^^^^^^^^^^ argument never used @@ -23,13 +23,13 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:15:15 + --> $DIR/bad-template.rs:36:15 | LL | asm!("{a}"); | ^^^ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:17:15 + --> $DIR/bad-template.rs:38:15 | LL | asm!("{}", a = in(reg) foo); | ^^ --------------- named argument @@ -38,13 +38,13 @@ LL | asm!("{}", a = in(reg) foo); | = note: no positional arguments were given note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:17:20 + --> $DIR/bad-template.rs:38:20 | LL | asm!("{}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ error: named argument never used - --> $DIR/bad-template.rs:17:20 + --> $DIR/bad-template.rs:38:20 | LL | asm!("{}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ named argument never used @@ -52,7 +52,7 @@ LL | asm!("{}", a = in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:20:15 + --> $DIR/bad-template.rs:41:15 | LL | asm!("{1}", a = in(reg) foo); | ^^^ from here @@ -60,7 +60,7 @@ LL | asm!("{1}", a = in(reg) foo); = note: no positional arguments were given error: named argument never used - --> $DIR/bad-template.rs:20:21 + --> $DIR/bad-template.rs:41:21 | LL | asm!("{1}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ named argument never used @@ -68,7 +68,7 @@ LL | asm!("{1}", a = in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:23:15 + --> $DIR/bad-template.rs:45:15 | LL | asm!("{}", in("eax") foo); | ^^ ------------- explicit register argument @@ -77,19 +77,19 @@ LL | asm!("{}", in("eax") foo); | = note: no positional arguments were given note: explicit register arguments cannot be used in the asm template - --> $DIR/bad-template.rs:23:20 + --> $DIR/bad-template.rs:45:20 | LL | asm!("{}", in("eax") foo); | ^^^^^^^^^^^^^ error: asm template modifier must be a single character - --> $DIR/bad-template.rs:25:17 + --> $DIR/bad-template.rs:50:17 | LL | asm!("{:foo}", in(reg) foo); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:27:18 + --> $DIR/bad-template.rs:52:18 | LL | asm!("", in(reg) 0, in(reg) 1); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -99,7 +99,7 @@ LL | asm!("", in(reg) 0, in(reg) 1); = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:33:14 + --> $DIR/bad-template.rs:58:14 | LL | global_asm!("{}"); | ^^ from here @@ -107,7 +107,7 @@ LL | global_asm!("{}"); = note: no arguments were given error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:35:14 + --> $DIR/bad-template.rs:60:14 | LL | global_asm!("{1}", const FOO); | ^^^ from here @@ -115,7 +115,7 @@ LL | global_asm!("{1}", const FOO); = note: there is 1 argument error: argument never used - --> $DIR/bad-template.rs:35:20 + --> $DIR/bad-template.rs:60:20 | LL | global_asm!("{1}", const FOO); | ^^^^^^^^^ argument never used @@ -123,13 +123,13 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:38:14 + --> $DIR/bad-template.rs:63:14 | LL | global_asm!("{a}"); | ^^^ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:40:14 + --> $DIR/bad-template.rs:65:14 | LL | global_asm!("{}", a = const FOO); | ^^ ------------- named argument @@ -138,13 +138,13 @@ LL | global_asm!("{}", a = const FOO); | = note: no positional arguments were given note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:40:19 + --> $DIR/bad-template.rs:65:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ error: named argument never used - --> $DIR/bad-template.rs:40:19 + --> $DIR/bad-template.rs:65:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -152,7 +152,7 @@ LL | global_asm!("{}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:43:14 + --> $DIR/bad-template.rs:68:14 | LL | global_asm!("{1}", a = const FOO); | ^^^ from here @@ -160,7 +160,7 @@ LL | global_asm!("{1}", a = const FOO); = note: no positional arguments were given error: named argument never used - --> $DIR/bad-template.rs:43:20 + --> $DIR/bad-template.rs:68:20 | LL | global_asm!("{1}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -168,13 +168,13 @@ LL | global_asm!("{1}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: asm template modifier must be a single character - --> $DIR/bad-template.rs:46:16 + --> $DIR/bad-template.rs:71:16 | LL | global_asm!("{:foo}", const FOO); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:48:17 + --> $DIR/bad-template.rs:73:17 | LL | global_asm!("", const FOO, const FOO); | ^^^^^^^^^ ^^^^^^^^^ argument never used diff --git a/src/test/ui/asm/bad-template.thirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr similarity index 85% rename from src/test/ui/asm/bad-template.thirunsafeck.stderr rename to src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr index 13ef032ab1071..3b69186f1e18b 100644 --- a/src/test/ui/asm/bad-template.thirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr @@ -1,5 +1,5 @@ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:10:15 + --> $DIR/bad-template.rs:31:15 | LL | asm!("{}"); | ^^ from here @@ -7,7 +7,7 @@ LL | asm!("{}"); = note: no arguments were given error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:12:15 + --> $DIR/bad-template.rs:33:15 | LL | asm!("{1}", in(reg) foo); | ^^^ from here @@ -15,7 +15,7 @@ LL | asm!("{1}", in(reg) foo); = note: there is 1 argument error: argument never used - --> $DIR/bad-template.rs:12:21 + --> $DIR/bad-template.rs:33:21 | LL | asm!("{1}", in(reg) foo); | ^^^^^^^^^^^ argument never used @@ -23,13 +23,13 @@ LL | asm!("{1}", in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:15:15 + --> $DIR/bad-template.rs:36:15 | LL | asm!("{a}"); | ^^^ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:17:15 + --> $DIR/bad-template.rs:38:15 | LL | asm!("{}", a = in(reg) foo); | ^^ --------------- named argument @@ -38,13 +38,13 @@ LL | asm!("{}", a = in(reg) foo); | = note: no positional arguments were given note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:17:20 + --> $DIR/bad-template.rs:38:20 | LL | asm!("{}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ error: named argument never used - --> $DIR/bad-template.rs:17:20 + --> $DIR/bad-template.rs:38:20 | LL | asm!("{}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ named argument never used @@ -52,7 +52,7 @@ LL | asm!("{}", a = in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:20:15 + --> $DIR/bad-template.rs:41:15 | LL | asm!("{1}", a = in(reg) foo); | ^^^ from here @@ -60,7 +60,7 @@ LL | asm!("{1}", a = in(reg) foo); = note: no positional arguments were given error: named argument never used - --> $DIR/bad-template.rs:20:21 + --> $DIR/bad-template.rs:41:21 | LL | asm!("{1}", a = in(reg) foo); | ^^^^^^^^^^^^^^^ named argument never used @@ -68,7 +68,7 @@ LL | asm!("{1}", a = in(reg) foo); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:23:15 + --> $DIR/bad-template.rs:45:15 | LL | asm!("{}", in("eax") foo); | ^^ ------------- explicit register argument @@ -77,19 +77,19 @@ LL | asm!("{}", in("eax") foo); | = note: no positional arguments were given note: explicit register arguments cannot be used in the asm template - --> $DIR/bad-template.rs:23:20 + --> $DIR/bad-template.rs:45:20 | LL | asm!("{}", in("eax") foo); | ^^^^^^^^^^^^^ error: asm template modifier must be a single character - --> $DIR/bad-template.rs:25:17 + --> $DIR/bad-template.rs:50:17 | LL | asm!("{:foo}", in(reg) foo); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:27:18 + --> $DIR/bad-template.rs:52:18 | LL | asm!("", in(reg) 0, in(reg) 1); | ^^^^^^^^^ ^^^^^^^^^ argument never used @@ -99,7 +99,7 @@ LL | asm!("", in(reg) 0, in(reg) 1); = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"` error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:33:14 + --> $DIR/bad-template.rs:58:14 | LL | global_asm!("{}"); | ^^ from here @@ -107,7 +107,7 @@ LL | global_asm!("{}"); = note: no arguments were given error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:35:14 + --> $DIR/bad-template.rs:60:14 | LL | global_asm!("{1}", const FOO); | ^^^ from here @@ -115,7 +115,7 @@ LL | global_asm!("{1}", const FOO); = note: there is 1 argument error: argument never used - --> $DIR/bad-template.rs:35:20 + --> $DIR/bad-template.rs:60:20 | LL | global_asm!("{1}", const FOO); | ^^^^^^^^^ argument never used @@ -123,13 +123,13 @@ LL | global_asm!("{1}", const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"` error: there is no argument named `a` - --> $DIR/bad-template.rs:38:14 + --> $DIR/bad-template.rs:63:14 | LL | global_asm!("{a}"); | ^^^ error: invalid reference to argument at index 0 - --> $DIR/bad-template.rs:40:14 + --> $DIR/bad-template.rs:65:14 | LL | global_asm!("{}", a = const FOO); | ^^ ------------- named argument @@ -138,13 +138,13 @@ LL | global_asm!("{}", a = const FOO); | = note: no positional arguments were given note: named arguments cannot be referenced by position - --> $DIR/bad-template.rs:40:19 + --> $DIR/bad-template.rs:65:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ error: named argument never used - --> $DIR/bad-template.rs:40:19 + --> $DIR/bad-template.rs:65:19 | LL | global_asm!("{}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -152,7 +152,7 @@ LL | global_asm!("{}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: invalid reference to argument at index 1 - --> $DIR/bad-template.rs:43:14 + --> $DIR/bad-template.rs:68:14 | LL | global_asm!("{1}", a = const FOO); | ^^^ from here @@ -160,7 +160,7 @@ LL | global_asm!("{1}", a = const FOO); = note: no positional arguments were given error: named argument never used - --> $DIR/bad-template.rs:43:20 + --> $DIR/bad-template.rs:68:20 | LL | global_asm!("{1}", a = const FOO); | ^^^^^^^^^^^^^ named argument never used @@ -168,13 +168,13 @@ LL | global_asm!("{1}", a = const FOO); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"` error: asm template modifier must be a single character - --> $DIR/bad-template.rs:46:16 + --> $DIR/bad-template.rs:71:16 | LL | global_asm!("{:foo}", const FOO); | ^^^ error: multiple unused asm arguments - --> $DIR/bad-template.rs:48:17 + --> $DIR/bad-template.rs:73:17 | LL | global_asm!("", const FOO, const FOO); | ^^^^^^^^^ ^^^^^^^^^ argument never used diff --git a/src/test/ui/asm/issue-72570.rs b/src/test/ui/asm/issue-72570.rs index 678534657cb31..960f7427e3405 100644 --- a/src/test/ui/asm/issue-72570.rs +++ b/src/test/ui/asm/issue-72570.rs @@ -1,5 +1,5 @@ // compile-flags: -Zsave-analysis -// only-x86_64 +// needs-asm-support // Also test for #72960 #![feature(asm)] diff --git a/src/test/ui/asm/issue-87802.rs b/src/test/ui/asm/issue-87802.rs index b1fc13b6a7e8c..5b6453c42c6eb 100644 --- a/src/test/ui/asm/issue-87802.rs +++ b/src/test/ui/asm/issue-87802.rs @@ -1,4 +1,7 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 // Make sure rustc doesn't ICE on asm! when output type is !. #![feature(asm)] diff --git a/src/test/ui/asm/issue-87802.stderr b/src/test/ui/asm/issue-87802.stderr index 1eb72b68a7f04..de3e28fdd1228 100644 --- a/src/test/ui/asm/issue-87802.stderr +++ b/src/test/ui/asm/issue-87802.stderr @@ -1,5 +1,5 @@ error: cannot use value of type `!` for inline assembly - --> $DIR/issue-87802.rs:9:36 + --> $DIR/issue-87802.rs:12:36 | LL | asm!("/* {0} */", out(reg) x); | ^ diff --git a/src/test/ui/asm/issue-89305.rs b/src/test/ui/asm/issue-89305.rs new file mode 100644 index 0000000000000..bdcf3f305ebb1 --- /dev/null +++ b/src/test/ui/asm/issue-89305.rs @@ -0,0 +1,14 @@ +// Regression test for #89305, where a variable was erroneously reported +// as both unused and possibly-uninitialized. + +// check-pass + +#![feature(asm)] +#![warn(unused)] + +fn main() { + unsafe { + let x: () = asm!("nop"); + //~^ WARNING: unused variable: `x` + } +} diff --git a/src/test/ui/asm/issue-89305.stderr b/src/test/ui/asm/issue-89305.stderr new file mode 100644 index 0000000000000..9cc127b44d008 --- /dev/null +++ b/src/test/ui/asm/issue-89305.stderr @@ -0,0 +1,15 @@ +warning: unused variable: `x` + --> $DIR/issue-89305.rs:11:13 + | +LL | let x: () = asm!("nop"); + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | +note: the lint level is defined here + --> $DIR/issue-89305.rs:7:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: 1 warning emitted + diff --git a/src/test/ui/asm/naked-functions-ffi.rs b/src/test/ui/asm/naked-functions-ffi.rs index 5b2a8ed3034a6..f6725605b924b 100644 --- a/src/test/ui/asm/naked-functions-ffi.rs +++ b/src/test/ui/asm/naked-functions-ffi.rs @@ -1,5 +1,5 @@ // check-pass -// only-x86_64 +// needs-asm-support #![feature(asm)] #![feature(naked_functions)] #![crate_type = "lib"] diff --git a/src/test/ui/asm/naked-functions-unused.aarch64.stderr b/src/test/ui/asm/naked-functions-unused.aarch64.stderr new file mode 100644 index 0000000000000..a898ab19a7341 --- /dev/null +++ b/src/test/ui/asm/naked-functions-unused.aarch64.stderr @@ -0,0 +1,69 @@ +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:15:32 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/naked-functions-unused.rs:4:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:15:42 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:24:38 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:24:48 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:30:41 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:30:51 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:38:40 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:38:50 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:44:43 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:44:53 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/naked-functions-unused.rs b/src/test/ui/asm/naked-functions-unused.rs index e1f2362bb6fd0..4c5c2ac1c197e 100644 --- a/src/test/ui/asm/naked-functions-unused.rs +++ b/src/test/ui/asm/naked-functions-unused.rs @@ -1,16 +1,18 @@ -// only-x86_64 +// revisions: x86_64 aarch64 +//[x86_64] only-x86_64 +//[aarch64] only-aarch64 #![deny(unused)] #![feature(asm)] #![feature(naked_functions)] #![crate_type = "lib"] pub trait Trait { - extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize; - extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize; + extern "C" fn trait_associated(a: usize, b: usize) -> usize; + extern "C" fn trait_method(&self, a: usize, b: usize) -> usize; } pub mod normal { - pub extern "sysv64" fn function(a: usize, b: usize) -> usize { + pub extern "C" fn function(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } @@ -19,13 +21,13 @@ pub mod normal { pub struct Normal; impl Normal { - pub extern "sysv64" fn associated(a: usize, b: usize) -> usize { + pub extern "C" fn associated(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } } - pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize { + pub extern "C" fn method(&self, a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } @@ -33,13 +35,13 @@ pub mod normal { } impl super::Trait for Normal { - extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize { + extern "C" fn trait_associated(a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } } - extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize { + extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { //~^ ERROR unused variable: `a` //~| ERROR unused variable: `b` unsafe { asm!("", options(noreturn)); } @@ -49,7 +51,7 @@ pub mod normal { pub mod naked { #[naked] - pub extern "sysv64" fn function(a: usize, b: usize) -> usize { + pub extern "C" fn function(a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } @@ -57,24 +59,24 @@ pub mod naked { impl Naked { #[naked] - pub extern "sysv64" fn associated(a: usize, b: usize) -> usize { + pub extern "C" fn associated(a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } #[naked] - pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize { + pub extern "C" fn method(&self, a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } } impl super::Trait for Naked { #[naked] - extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize { + extern "C" fn trait_associated(a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } #[naked] - extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize { + extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { unsafe { asm!("", options(noreturn)); } } } diff --git a/src/test/ui/asm/naked-functions-unused.stderr b/src/test/ui/asm/naked-functions-unused.stderr deleted file mode 100644 index 840353366b670..0000000000000 --- a/src/test/ui/asm/naked-functions-unused.stderr +++ /dev/null @@ -1,69 +0,0 @@ -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:13:37 - | -LL | pub extern "sysv64" fn function(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - | -note: the lint level is defined here - --> $DIR/naked-functions-unused.rs:2:9 - | -LL | #![deny(unused)] - | ^^^^^^ - = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:13:47 - | -LL | pub extern "sysv64" fn function(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:22:43 - | -LL | pub extern "sysv64" fn associated(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:22:53 - | -LL | pub extern "sysv64" fn associated(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:28:46 - | -LL | pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:28:56 - | -LL | pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:36:45 - | -LL | extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:36:55 - | -LL | extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: unused variable: `a` - --> $DIR/naked-functions-unused.rs:42:48 - | -LL | extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_a` - -error: unused variable: `b` - --> $DIR/naked-functions-unused.rs:42:58 - | -LL | extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize { - | ^ help: if this is intentional, prefix it with an underscore: `_b` - -error: aborting due to 10 previous errors - diff --git a/src/test/ui/asm/naked-functions-unused.x86_64.stderr b/src/test/ui/asm/naked-functions-unused.x86_64.stderr new file mode 100644 index 0000000000000..a898ab19a7341 --- /dev/null +++ b/src/test/ui/asm/naked-functions-unused.x86_64.stderr @@ -0,0 +1,69 @@ +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:15:32 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/naked-functions-unused.rs:4:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:15:42 + | +LL | pub extern "C" fn function(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:24:38 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:24:48 + | +LL | pub extern "C" fn associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:30:41 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:30:51 + | +LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:38:40 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:38:50 + | +LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: unused variable: `a` + --> $DIR/naked-functions-unused.rs:44:43 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_a` + +error: unused variable: `b` + --> $DIR/naked-functions-unused.rs:44:53 + | +LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize { + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs index 72918a1411755..803311d423505 100644 --- a/src/test/ui/asm/naked-functions.rs +++ b/src/test/ui/asm/naked-functions.rs @@ -1,4 +1,8 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 + #![feature(asm)] #![feature(llvm_asm)] #![feature(naked_functions)] diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr index 3b54757cfe818..46ceef032427c 100644 --- a/src/test/ui/asm/naked-functions.stderr +++ b/src/test/ui/asm/naked-functions.stderr @@ -1,35 +1,35 @@ error: asm with the `pure` option must have at least one output - --> $DIR/naked-functions.rs:127:14 + --> $DIR/naked-functions.rs:131:14 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:14:5 + --> $DIR/naked-functions.rs:18:5 | LL | mut a: u32, | ^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:16:5 + --> $DIR/naked-functions.rs:20:5 | LL | &b: &i32, | ^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:18:6 + --> $DIR/naked-functions.rs:22:6 | LL | (None | Some(_)): Option>, | ^^^^^^^^^^^^^^ error: patterns not allowed in naked function parameters - --> $DIR/naked-functions.rs:20:5 + --> $DIR/naked-functions.rs:24:5 | LL | P { x, y }: P, | ^^^^^^^^^^ error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:30:5 + --> $DIR/naked-functions.rs:34:5 | LL | a + 1 | ^ @@ -37,7 +37,7 @@ LL | a + 1 = help: follow the calling convention in asm block to use parameters warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:27:1 + --> $DIR/naked-functions.rs:31:1 | LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 { LL | | @@ -53,7 +53,7 @@ LL | | } = note: for more information, see issue #32408 error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:36:31 + --> $DIR/naked-functions.rs:40:31 | LL | asm!("/* {0} */", in(reg) a, options(noreturn)); | ^ @@ -61,7 +61,7 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn)); = help: follow the calling convention in asm block to use parameters warning: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:36:23 + --> $DIR/naked-functions.rs:40:23 | LL | asm!("/* {0} */", in(reg) a, options(noreturn)); | ^^^^^^^^^ @@ -70,7 +70,7 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn)); = note: for more information, see issue #32408 warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:43:1 + --> $DIR/naked-functions.rs:47:1 | LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { LL | | @@ -84,7 +84,7 @@ LL | | } = note: for more information, see issue #32408 warning: only `const` and `sym` operands are supported in naked functions - --> $DIR/naked-functions.rs:63:10 + --> $DIR/naked-functions.rs:67:10 | LL | in(reg) a, | ^^^^^^^^^ @@ -102,7 +102,7 @@ LL | out(reg) e, = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:60:5 + --> $DIR/naked-functions.rs:64:5 | LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */", LL | | @@ -117,7 +117,7 @@ LL | | ); = note: for more information, see issue #32408 warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:50:1 + --> $DIR/naked-functions.rs:54:1 | LL | / pub unsafe extern "C" fn unsupported_operands() { LL | | @@ -141,7 +141,7 @@ LL | | } = note: for more information, see issue #32408 warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:76:1 + --> $DIR/naked-functions.rs:80:1 | LL | / pub extern "C" fn missing_assembly() { LL | | @@ -153,7 +153,7 @@ LL | | } = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:85:5 + --> $DIR/naked-functions.rs:89:5 | LL | asm!(""); | ^^^^^^^^^ @@ -162,7 +162,7 @@ LL | asm!(""); = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:88:5 + --> $DIR/naked-functions.rs:92:5 | LL | asm!(""); | ^^^^^^^^^ @@ -171,7 +171,7 @@ LL | asm!(""); = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:91:5 + --> $DIR/naked-functions.rs:95:5 | LL | asm!(""); | ^^^^^^^^^ @@ -180,7 +180,7 @@ LL | asm!(""); = note: for more information, see issue #32408 warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:82:1 + --> $DIR/naked-functions.rs:86:1 | LL | / pub extern "C" fn too_many_asm_blocks() { LL | | @@ -202,7 +202,7 @@ LL | | } = note: for more information, see issue #32408 error: referencing function parameters is not allowed in naked functions - --> $DIR/naked-functions.rs:102:11 + --> $DIR/naked-functions.rs:106:11 | LL | *&y | ^ @@ -210,7 +210,7 @@ LL | *&y = help: follow the calling convention in asm block to use parameters warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:99:5 + --> $DIR/naked-functions.rs:103:5 | LL | / pub extern "C" fn inner(y: usize) -> usize { LL | | @@ -225,7 +225,7 @@ LL | | } = note: for more information, see issue #32408 warning: the LLVM-style inline assembly is unsupported in naked functions - --> $DIR/naked-functions.rs:112:5 + --> $DIR/naked-functions.rs:116:5 | LL | llvm_asm!(""); | ^^^^^^^^^^^^^^ @@ -236,7 +236,7 @@ LL | llvm_asm!(""); = note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info) warning: naked functions must contain a single asm block - --> $DIR/naked-functions.rs:109:1 + --> $DIR/naked-functions.rs:113:1 | LL | / unsafe extern "C" fn llvm() -> ! { LL | | @@ -252,7 +252,7 @@ LL | | } = note: for more information, see issue #32408 warning: asm options unsupported in naked functions: `nomem`, `preserves_flags` - --> $DIR/naked-functions.rs:120:5 + --> $DIR/naked-functions.rs:124:5 | LL | asm!("", options(nomem, preserves_flags, noreturn)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -261,7 +261,7 @@ LL | asm!("", options(nomem, preserves_flags, noreturn)); = note: for more information, see issue #32408 warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly` - --> $DIR/naked-functions.rs:127:5 + --> $DIR/naked-functions.rs:131:5 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -270,7 +270,7 @@ LL | asm!("", options(readonly, nostack), options(pure)); = note: for more information, see issue #32408 warning: asm in naked functions must use `noreturn` option - --> $DIR/naked-functions.rs:127:5 + --> $DIR/naked-functions.rs:131:5 | LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | asm!("", options(readonly, nostack), options(pure)); = note: for more information, see issue #32408 warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:136:15 + --> $DIR/naked-functions.rs:140:15 | LL | pub unsafe fn default_abi() { | ^^^^^^^^^^^ @@ -287,13 +287,13 @@ LL | pub unsafe fn default_abi() { = note: `#[warn(undefined_naked_function_abi)]` on by default warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:142:29 + --> $DIR/naked-functions.rs:146:29 | LL | pub unsafe extern "Rust" fn rust_abi() { | ^^^^^^^^ warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:176:1 + --> $DIR/naked-functions.rs:180:1 | LL | #[inline] | ^^^^^^^^^ @@ -302,7 +302,7 @@ LL | #[inline] = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:184:1 + --> $DIR/naked-functions.rs:188:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ @@ -311,7 +311,7 @@ LL | #[inline(always)] = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:192:1 + --> $DIR/naked-functions.rs:196:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ @@ -320,7 +320,7 @@ LL | #[inline(never)] = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:200:1 + --> $DIR/naked-functions.rs:204:1 | LL | #[inline] | ^^^^^^^^^ @@ -329,7 +329,7 @@ LL | #[inline] = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:203:1 + --> $DIR/naked-functions.rs:207:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ @@ -338,7 +338,7 @@ LL | #[inline(always)] = note: for more information, see issue #32408 warning: naked functions cannot be inlined - --> $DIR/naked-functions.rs:206:1 + --> $DIR/naked-functions.rs:210:1 | LL | #[inline(never)] | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/asm/named-asm-labels.rs b/src/test/ui/asm/named-asm-labels.rs index 9f487bd8061fc..82c47945a7b30 100644 --- a/src/test/ui/asm/named-asm-labels.rs +++ b/src/test/ui/asm/named-asm-labels.rs @@ -1,4 +1,7 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 // Tests that the use of named labels in the `asm!` macro are linted against // except for in `#[naked]` fns. @@ -99,9 +102,6 @@ fn main() { asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); //~ ERROR avoid using named labels // Non-label colons - should pass - // (most of these are stolen from other places) - asm!("{:l}", in(reg) 0i64); - asm!("{:e}", in(reg) 0f32); asm!("mov rax, qword ptr fs:[0]"); // Comments diff --git a/src/test/ui/asm/named-asm-labels.stderr b/src/test/ui/asm/named-asm-labels.stderr index 396f0a1942428..75c848cdc572d 100644 --- a/src/test/ui/asm/named-asm-labels.stderr +++ b/src/test/ui/asm/named-asm-labels.stderr @@ -1,5 +1,5 @@ error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:19:15 + --> $DIR/named-asm-labels.rs:22:15 | LL | asm!("bar: nop"); | ^^^ @@ -9,7 +9,7 @@ LL | asm!("bar: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:22:15 + --> $DIR/named-asm-labels.rs:25:15 | LL | asm!("abcd:"); | ^^^^ @@ -18,7 +18,7 @@ LL | asm!("abcd:"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:25:15 + --> $DIR/named-asm-labels.rs:28:15 | LL | asm!("foo: bar1: nop"); | ^^^ ^^^^ @@ -27,7 +27,7 @@ LL | asm!("foo: bar1: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:29:15 + --> $DIR/named-asm-labels.rs:32:15 | LL | asm!("foo1: nop", "nop"); | ^^^^ @@ -36,7 +36,7 @@ LL | asm!("foo1: nop", "nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:30:15 + --> $DIR/named-asm-labels.rs:33:15 | LL | asm!("foo2: foo3: nop", "nop"); | ^^^^ ^^^^ @@ -45,7 +45,7 @@ LL | asm!("foo2: foo3: nop", "nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:32:22 + --> $DIR/named-asm-labels.rs:35:22 | LL | asm!("nop", "foo4: nop"); | ^^^^ @@ -54,7 +54,7 @@ LL | asm!("nop", "foo4: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:33:15 + --> $DIR/named-asm-labels.rs:36:15 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -63,7 +63,7 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:33:28 + --> $DIR/named-asm-labels.rs:36:28 | LL | asm!("foo5: nop", "foo6: nop"); | ^^^^ @@ -72,7 +72,7 @@ LL | asm!("foo5: nop", "foo6: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:38:15 + --> $DIR/named-asm-labels.rs:41:15 | LL | asm!("foo7: nop; foo8: nop"); | ^^^^ ^^^^ @@ -81,7 +81,7 @@ LL | asm!("foo7: nop; foo8: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:40:15 + --> $DIR/named-asm-labels.rs:43:15 | LL | asm!("foo9: nop; nop"); | ^^^^ @@ -90,7 +90,7 @@ LL | asm!("foo9: nop; nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:41:20 + --> $DIR/named-asm-labels.rs:44:20 | LL | asm!("nop; foo10: nop"); | ^^^^^ @@ -99,7 +99,7 @@ LL | asm!("nop; foo10: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:44:15 + --> $DIR/named-asm-labels.rs:47:15 | LL | asm!("bar2: nop\n bar3: nop"); | ^^^^ ^^^^ @@ -108,7 +108,7 @@ LL | asm!("bar2: nop\n bar3: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:46:15 + --> $DIR/named-asm-labels.rs:49:15 | LL | asm!("bar4: nop\n nop"); | ^^^^ @@ -117,7 +117,7 @@ LL | asm!("bar4: nop\n nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:47:21 + --> $DIR/named-asm-labels.rs:50:21 | LL | asm!("nop\n bar5: nop"); | ^^^^ @@ -126,7 +126,7 @@ LL | asm!("nop\n bar5: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:48:21 + --> $DIR/named-asm-labels.rs:51:21 | LL | asm!("nop\n bar6: bar7: nop"); | ^^^^ ^^^^ @@ -135,7 +135,7 @@ LL | asm!("nop\n bar6: bar7: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:54:13 + --> $DIR/named-asm-labels.rs:57:13 | LL | blah2: nop | ^^^^^ @@ -146,7 +146,7 @@ LL | blah3: nop = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:63:19 + --> $DIR/named-asm-labels.rs:66:19 | LL | nop ; blah4: nop | ^^^^^ @@ -155,7 +155,7 @@ LL | nop ; blah4: nop = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:77:15 + --> $DIR/named-asm-labels.rs:80:15 | LL | asm!("blah1: 2bar: nop"); | ^^^^^ @@ -164,7 +164,7 @@ LL | asm!("blah1: 2bar: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:80:15 + --> $DIR/named-asm-labels.rs:83:15 | LL | asm!("def: def: nop"); | ^^^ @@ -173,7 +173,7 @@ LL | asm!("def: def: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:81:15 + --> $DIR/named-asm-labels.rs:84:15 | LL | asm!("def: nop\ndef: nop"); | ^^^ @@ -182,7 +182,7 @@ LL | asm!("def: nop\ndef: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:82:15 + --> $DIR/named-asm-labels.rs:85:15 | LL | asm!("def: nop; def: nop"); | ^^^ @@ -191,7 +191,7 @@ LL | asm!("def: nop; def: nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:90:15 + --> $DIR/named-asm-labels.rs:93:15 | LL | asm!("fooo\u{003A} nop"); | ^^^^^^^^^^^^^^^^ @@ -200,7 +200,7 @@ LL | asm!("fooo\u{003A} nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:91:15 + --> $DIR/named-asm-labels.rs:94:15 | LL | asm!("foooo\x3A nop"); | ^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | asm!("foooo\x3A nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:94:15 + --> $DIR/named-asm-labels.rs:97:15 | LL | asm!("fooooo:\u{000A} nop"); | ^^^^^^ @@ -218,7 +218,7 @@ LL | asm!("fooooo:\u{000A} nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:95:15 + --> $DIR/named-asm-labels.rs:98:15 | LL | asm!("foooooo:\x0A nop"); | ^^^^^^^ @@ -227,7 +227,7 @@ LL | asm!("foooooo:\x0A nop"); = note: see the asm section of the unstable book for more information error: avoid using named labels in inline assembly - --> $DIR/named-asm-labels.rs:99:14 + --> $DIR/named-asm-labels.rs:102:14 | LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/asm/noreturn.rs b/src/test/ui/asm/noreturn.rs index 5e1ee93bfb073..cb92ff0ad1d6d 100644 --- a/src/test/ui/asm/noreturn.rs +++ b/src/test/ui/asm/noreturn.rs @@ -1,4 +1,4 @@ -// only-x86_64 +// needs-asm-support // check-pass #![feature(asm, never_type)] diff --git a/src/test/ui/asm/rustfix-asm.fixed b/src/test/ui/asm/rustfix-asm.fixed index 9251afd3f059f..1d5d2038aa89c 100644 --- a/src/test/ui/asm/rustfix-asm.fixed +++ b/src/test/ui/asm/rustfix-asm.fixed @@ -1,5 +1,5 @@ // run-rustfix -// only-x86_64 +// needs-asm-support #![feature(asm, llvm_asm)] #![allow(deprecated)] // llvm_asm! diff --git a/src/test/ui/asm/rustfix-asm.rs b/src/test/ui/asm/rustfix-asm.rs index 1e3bfd077081c..12be0e666ee14 100644 --- a/src/test/ui/asm/rustfix-asm.rs +++ b/src/test/ui/asm/rustfix-asm.rs @@ -1,5 +1,5 @@ // run-rustfix -// only-x86_64 +// needs-asm-support #![feature(asm, llvm_asm)] #![allow(deprecated)] // llvm_asm! diff --git a/src/test/ui/asm/type-check-1.rs b/src/test/ui/asm/type-check-1.rs index 5e38fb70a4adf..bbbe798d1557b 100644 --- a/src/test/ui/asm/type-check-1.rs +++ b/src/test/ui/asm/type-check-1.rs @@ -1,4 +1,7 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 #![feature(asm, global_asm)] @@ -49,6 +52,8 @@ fn main() { //~^ ERROR mismatched types asm!("{}", const 0 as *mut u8); //~^ ERROR mismatched types + asm!("{}", const &0); + //~^ ERROR mismatched types } } diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr index 5edbcf4a2a7c9..c9080a3c0309a 100644 --- a/src/test/ui/asm/type-check-1.stderr +++ b/src/test/ui/asm/type-check-1.stderr @@ -1,5 +1,5 @@ error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/type-check-1.rs:34:26 + --> $DIR/type-check-1.rs:37:26 | LL | let x = 0; | ----- help: consider using `const` instead of `let`: `const x` @@ -8,7 +8,7 @@ LL | asm!("{}", const x); | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/type-check-1.rs:37:36 + --> $DIR/type-check-1.rs:40:36 | LL | let x = 0; | ----- help: consider using `const` instead of `let`: `const x` @@ -17,7 +17,7 @@ LL | asm!("{}", const const_foo(x)); | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/type-check-1.rs:40:36 + --> $DIR/type-check-1.rs:43:36 | LL | let x = 0; | ----- help: consider using `const` instead of `let`: `const x` @@ -26,13 +26,13 @@ LL | asm!("{}", const const_bar(x)); | ^ non-constant value error[E0308]: mismatched types - --> $DIR/type-check-1.rs:48:26 + --> $DIR/type-check-1.rs:51:26 | LL | asm!("{}", const 0f32); | ^^^^ expected integer, found `f32` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:50:26 + --> $DIR/type-check-1.rs:53:26 | LL | asm!("{}", const 0 as *mut u8); | ^^^^^^^^^^^^ expected integer, found *-ptr @@ -40,20 +40,32 @@ LL | asm!("{}", const 0 as *mut u8); = note: expected type `{integer}` found raw pointer `*mut u8` +error[E0308]: mismatched types + --> $DIR/type-check-1.rs:55:26 + | +LL | asm!("{}", const &0); + | ^^ expected integer, found `&{integer}` + | +help: consider removing the borrow + | +LL - asm!("{}", const &0); +LL + asm!("{}", const 0); + | + error: invalid asm output - --> $DIR/type-check-1.rs:10:29 + --> $DIR/type-check-1.rs:13:29 | LL | asm!("{}", out(reg) 1 + 2); | ^^^^^ cannot assign to this expression error: invalid asm output - --> $DIR/type-check-1.rs:12:31 + --> $DIR/type-check-1.rs:15:31 | LL | asm!("{}", inout(reg) 1 + 2); | ^^^^^ cannot assign to this expression error[E0277]: the size for values of type `[u64]` cannot be known at compilation time - --> $DIR/type-check-1.rs:18:28 + --> $DIR/type-check-1.rs:21:28 | LL | asm!("{}", in(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time @@ -62,7 +74,7 @@ LL | asm!("{}", in(reg) v[..]); = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time - --> $DIR/type-check-1.rs:20:29 + --> $DIR/type-check-1.rs:23:29 | LL | asm!("{}", out(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time @@ -71,7 +83,7 @@ LL | asm!("{}", out(reg) v[..]); = note: all inline asm arguments must have a statically known size error[E0277]: the size for values of type `[u64]` cannot be known at compilation time - --> $DIR/type-check-1.rs:22:31 + --> $DIR/type-check-1.rs:25:31 | LL | asm!("{}", inout(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time @@ -80,13 +92,13 @@ LL | asm!("{}", inout(reg) v[..]); = note: all inline asm arguments must have a statically known size error[E0308]: mismatched types - --> $DIR/type-check-1.rs:60:25 + --> $DIR/type-check-1.rs:65:25 | LL | global_asm!("{}", const 0f32); | ^^^^ expected integer, found `f32` error[E0308]: mismatched types - --> $DIR/type-check-1.rs:62:25 + --> $DIR/type-check-1.rs:67:25 | LL | global_asm!("{}", const 0 as *mut u8); | ^^^^^^^^^^^^ expected integer, found *-ptr @@ -94,7 +106,7 @@ LL | global_asm!("{}", const 0 as *mut u8); = note: expected type `{integer}` found raw pointer `*mut u8` -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors Some errors have detailed explanations: E0277, E0308, E0435. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/asm/type-check-4.rs b/src/test/ui/asm/type-check-4.rs index 2be627c11657b..c982666200985 100644 --- a/src/test/ui/asm/type-check-4.rs +++ b/src/test/ui/asm/type-check-4.rs @@ -1,4 +1,7 @@ -// only-x86_64 +// needs-asm-support +// ignore-nvptx64 +// ignore-spirv +// ignore-wasm32 #![feature(asm)] diff --git a/src/test/ui/asm/type-check-4.stderr b/src/test/ui/asm/type-check-4.stderr index 8035bbefc1aa1..db2bf0a69f7fc 100644 --- a/src/test/ui/asm/type-check-4.stderr +++ b/src/test/ui/asm/type-check-4.stderr @@ -1,5 +1,5 @@ error[E0506]: cannot assign to `a` because it is borrowed - --> $DIR/type-check-4.rs:11:9 + --> $DIR/type-check-4.rs:14:9 | LL | let p = &a; | -- borrow of `a` occurs here @@ -10,7 +10,7 @@ LL | println!("{}", p); | - borrow later used here error[E0503]: cannot use `a` because it was mutably borrowed - --> $DIR/type-check-4.rs:19:28 + --> $DIR/type-check-4.rs:22:28 | LL | let p = &mut a; | ------ borrow of `a` occurs here diff --git a/src/test/ui/asm/bad-options.rs b/src/test/ui/asm/x86_64/bad-options.rs similarity index 100% rename from src/test/ui/asm/bad-options.rs rename to src/test/ui/asm/x86_64/bad-options.rs diff --git a/src/test/ui/asm/bad-options.stderr b/src/test/ui/asm/x86_64/bad-options.stderr similarity index 100% rename from src/test/ui/asm/bad-options.stderr rename to src/test/ui/asm/x86_64/bad-options.stderr diff --git a/src/test/ui/asm/bad-reg.rs b/src/test/ui/asm/x86_64/bad-reg.rs similarity index 100% rename from src/test/ui/asm/bad-reg.rs rename to src/test/ui/asm/x86_64/bad-reg.rs diff --git a/src/test/ui/asm/bad-reg.stderr b/src/test/ui/asm/x86_64/bad-reg.stderr similarity index 100% rename from src/test/ui/asm/bad-reg.stderr rename to src/test/ui/asm/x86_64/bad-reg.stderr diff --git a/src/test/ui/asm/const.rs b/src/test/ui/asm/x86_64/const.rs similarity index 100% rename from src/test/ui/asm/const.rs rename to src/test/ui/asm/x86_64/const.rs diff --git a/src/test/ui/asm/duplicate-options.fixed b/src/test/ui/asm/x86_64/duplicate-options.fixed similarity index 100% rename from src/test/ui/asm/duplicate-options.fixed rename to src/test/ui/asm/x86_64/duplicate-options.fixed diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/x86_64/duplicate-options.rs similarity index 100% rename from src/test/ui/asm/duplicate-options.rs rename to src/test/ui/asm/x86_64/duplicate-options.rs diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/x86_64/duplicate-options.stderr similarity index 100% rename from src/test/ui/asm/duplicate-options.stderr rename to src/test/ui/asm/x86_64/duplicate-options.stderr diff --git a/src/test/ui/asm/interpolated-idents.rs b/src/test/ui/asm/x86_64/interpolated-idents.rs similarity index 100% rename from src/test/ui/asm/interpolated-idents.rs rename to src/test/ui/asm/x86_64/interpolated-idents.rs diff --git a/src/test/ui/asm/interpolated-idents.stderr b/src/test/ui/asm/x86_64/interpolated-idents.stderr similarity index 100% rename from src/test/ui/asm/interpolated-idents.stderr rename to src/test/ui/asm/x86_64/interpolated-idents.stderr diff --git a/src/test/ui/asm/issue-82869.rs b/src/test/ui/asm/x86_64/issue-82869.rs similarity index 100% rename from src/test/ui/asm/issue-82869.rs rename to src/test/ui/asm/x86_64/issue-82869.rs diff --git a/src/test/ui/asm/issue-82869.stderr b/src/test/ui/asm/x86_64/issue-82869.stderr similarity index 100% rename from src/test/ui/asm/issue-82869.stderr rename to src/test/ui/asm/x86_64/issue-82869.stderr diff --git a/src/test/ui/asm/parse-error.rs b/src/test/ui/asm/x86_64/parse-error.rs similarity index 100% rename from src/test/ui/asm/parse-error.rs rename to src/test/ui/asm/x86_64/parse-error.rs diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr similarity index 100% rename from src/test/ui/asm/parse-error.stderr rename to src/test/ui/asm/x86_64/parse-error.stderr diff --git a/src/test/ui/asm/srcloc.rs b/src/test/ui/asm/x86_64/srcloc.rs similarity index 100% rename from src/test/ui/asm/srcloc.rs rename to src/test/ui/asm/x86_64/srcloc.rs diff --git a/src/test/ui/asm/srcloc.stderr b/src/test/ui/asm/x86_64/srcloc.stderr similarity index 100% rename from src/test/ui/asm/srcloc.stderr rename to src/test/ui/asm/x86_64/srcloc.stderr diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/x86_64/sym.rs similarity index 100% rename from src/test/ui/asm/sym.rs rename to src/test/ui/asm/x86_64/sym.rs diff --git a/src/test/ui/asm/type-check-2.rs b/src/test/ui/asm/x86_64/type-check-2.rs similarity index 93% rename from src/test/ui/asm/type-check-2.rs rename to src/test/ui/asm/x86_64/type-check-2.rs index c70a8802814f7..2311f86d340f4 100644 --- a/src/test/ui/asm/type-check-2.rs +++ b/src/test/ui/asm/x86_64/type-check-2.rs @@ -26,10 +26,6 @@ fn main() { asm!("{}", inout(reg) v[0]); //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable - // This currently causes an ICE: https://github.com/rust-lang/rust/issues/81857 - // asm!("{}", const &0); - // ERROR asm `const` arguments must be integer or floating-point values - // Sym operands must point to a function or static const C: i32 = 0; diff --git a/src/test/ui/asm/type-check-2.stderr b/src/test/ui/asm/x86_64/type-check-2.stderr similarity index 93% rename from src/test/ui/asm/type-check-2.stderr rename to src/test/ui/asm/x86_64/type-check-2.stderr index 1354a9dd849b3..b82a0b8e2ba26 100644 --- a/src/test/ui/asm/type-check-2.stderr +++ b/src/test/ui/asm/x86_64/type-check-2.stderr @@ -1,13 +1,13 @@ error: arguments for inline assembly must be copyable - --> $DIR/type-check-2.rs:46:32 + --> $DIR/type-check-2.rs:42:32 | LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `SimdNonCopy` does not implement the Copy trait -error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly - --> $DIR/type-check-2.rs:58:28 +error: cannot use value of type `[closure@$DIR/type-check-2.rs:54:28: 54:38]` for inline assembly + --> $DIR/type-check-2.rs:54:28 | LL | asm!("{}", in(reg) |x: i32| x); | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | asm!("{}", in(reg) |x: i32| x); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `Vec` for inline assembly - --> $DIR/type-check-2.rs:60:28 + --> $DIR/type-check-2.rs:56:28 | LL | asm!("{}", in(reg) vec![0]); | ^^^^^^^ @@ -24,7 +24,7 @@ LL | asm!("{}", in(reg) vec![0]); = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot use value of type `(i32, i32, i32)` for inline assembly - --> $DIR/type-check-2.rs:62:28 + --> $DIR/type-check-2.rs:58:28 | LL | asm!("{}", in(reg) (1, 2, 3)); | ^^^^^^^^^ @@ -32,7 +32,7 @@ LL | asm!("{}", in(reg) (1, 2, 3)); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `[i32; 3]` for inline assembly - --> $DIR/type-check-2.rs:64:28 + --> $DIR/type-check-2.rs:60:28 | LL | asm!("{}", in(reg) [1, 2, 3]); | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL | asm!("{}", in(reg) [1, 2, 3]); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `fn() {main}` for inline assembly - --> $DIR/type-check-2.rs:72:31 + --> $DIR/type-check-2.rs:68:31 | LL | asm!("{}", inout(reg) f); | ^ @@ -48,7 +48,7 @@ LL | asm!("{}", inout(reg) f); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: cannot use value of type `&mut i32` for inline assembly - --> $DIR/type-check-2.rs:75:31 + --> $DIR/type-check-2.rs:71:31 | LL | asm!("{}", inout(reg) r); | ^ @@ -56,13 +56,13 @@ LL | asm!("{}", inout(reg) r); = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:39:24 + --> $DIR/type-check-2.rs:35:24 | LL | asm!("{}", sym C); | ^ error: asm `sym` operand must point to a fn or static - --> $DIR/type-check-2.rs:41:24 + --> $DIR/type-check-2.rs:37:24 | LL | asm!("{}", sym x); | ^ diff --git a/src/test/ui/asm/type-check-3.rs b/src/test/ui/asm/x86_64/type-check-3.rs similarity index 100% rename from src/test/ui/asm/type-check-3.rs rename to src/test/ui/asm/x86_64/type-check-3.rs diff --git a/src/test/ui/asm/type-check-3.stderr b/src/test/ui/asm/x86_64/type-check-3.stderr similarity index 100% rename from src/test/ui/asm/type-check-3.stderr rename to src/test/ui/asm/x86_64/type-check-3.stderr diff --git a/src/test/ui/assignment-operator-unimplemented.stderr b/src/test/ui/assignment-operator-unimplemented.stderr index 5304b09de5efe..73c9f86e00220 100644 --- a/src/test/ui/assignment-operator-unimplemented.stderr +++ b/src/test/ui/assignment-operator-unimplemented.stderr @@ -6,7 +6,22 @@ LL | a += *b; | | | cannot use `+=` on type `Foo` | - = note: an implementation of `std::ops::AddAssign` might be missing for `Foo` +note: an implementation of `AddAssign<_>` might be missing for `Foo` + --> $DIR/assignment-operator-unimplemented.rs:1:1 + | +LL | struct Foo; + | ^^^^^^^^^^^ must implement `AddAssign<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait AddAssign { +LL | | /// Performs the `+=` operation. +LL | | /// +LL | | /// # Example +... | +LL | | fn add_assign(&mut self, rhs: Rhs); +LL | | } + | |_^ error: aborting due to previous error diff --git a/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr b/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr index d4c12b8e061cc..60cf9a533cd72 100644 --- a/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr +++ b/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr @@ -16,12 +16,12 @@ LL | const ID: i32 = 3; | ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated constant for candidate #1 | -LL | const X: i32 = Foo::ID; - | ~~~~~ +LL | const X: i32 = ::ID; + | ~~~~~~~~~~~~~~ help: disambiguate the associated constant for candidate #2 | -LL | const X: i32 = Bar::ID; - | ~~~~~ +LL | const X: i32 = ::ID; + | ~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing-self.rs b/src/test/ui/associated-type-bounds/supertrait-referencing-self.rs similarity index 100% rename from src/test/ui/associated-type-bounds/super-trait-referencing-self.rs rename to src/test/ui/associated-type-bounds/supertrait-referencing-self.rs diff --git a/src/test/ui/associated-type-bounds/super-trait-referencing.rs b/src/test/ui/associated-type-bounds/supertrait-referencing.rs similarity index 100% rename from src/test/ui/associated-type-bounds/super-trait-referencing.rs rename to src/test/ui/associated-type-bounds/supertrait-referencing.rs diff --git a/src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs b/src/test/ui/associated-type-bounds/supertrait-where-referencing-self.rs similarity index 100% rename from src/test/ui/associated-type-bounds/super-trait-where-referencing-self.rs rename to src/test/ui/associated-type-bounds/supertrait-where-referencing-self.rs diff --git a/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs b/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs index ad5c6aed97c2c..d854dce382fc4 100644 --- a/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs +++ b/src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs @@ -1,5 +1,5 @@ // check-pass -// compile-flags:-Cincremental=tmp/traits-assoc-type-macros +// incremental // This test case makes sure that we can compile with incremental compilation // enabled when there are macros, traits, inheritance and associated types involved. diff --git a/src/test/ui/associated-types/associated-types-doubleendediterator-object.rs b/src/test/ui/associated-types/associated-types-doubleendediterator-object.rs index 96ba2ee3b62b8..05498ba63e994 100644 --- a/src/test/ui/associated-types/associated-types-doubleendediterator-object.rs +++ b/src/test/ui/associated-types/associated-types-doubleendediterator-object.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn pairwise_sub(mut t: Box>) -> isize { let mut result = 0; diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr index 558f394ef8644..f532c96ed2cc7 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.nll.stderr @@ -5,8 +5,6 @@ LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here LL | bar(foo, x) | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr index db82c9fd43794..c417cdd543e4d 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.nll.stderr @@ -6,8 +6,6 @@ LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { ... LL | bar(foo, x) | ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr index e3bd0c2276e48..de254b7a1636c 100644 --- a/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr +++ b/src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr @@ -6,6 +6,11 @@ LL | foo(()); | = note: expected reference `&'a ()` found reference `&()` +note: the lifetime requirement is introduced here + --> $DIR/higher-ranked-projection.rs:15:33 + | +LL | where for<'a> &'a T: Mirror + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr index 079989f2331af..fe9b4d630b910 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr @@ -9,7 +9,7 @@ LL | | type U = str; LL | | } | |_^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`hr_associated_type_bound_2`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hr_associated_type_bound_2`) note: required because of the requirements on the impl of `for<'b> X<'b>` for `u32` --> $DIR/hr-associated-type-bound-2.rs:11:6 | @@ -24,7 +24,7 @@ error[E0275]: overflow evaluating the requirement `for<'b> u32: X<'b>` LL | type U = str; | ^^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`hr_associated_type_bound_2`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`hr_associated_type_bound_2`) note: required because of the requirements on the impl of `for<'b> X<'b>` for `u32` --> $DIR/hr-associated-type-bound-2.rs:11:6 | diff --git a/src/test/ui/associated-types/impl-wf-cycle-1.stderr b/src/test/ui/associated-types/impl-wf-cycle-1.stderr index 1d8d2b0149d21..73167d0831104 100644 --- a/src/test/ui/associated-types/impl-wf-cycle-1.stderr +++ b/src/test/ui/associated-types/impl-wf-cycle-1.stderr @@ -15,7 +15,7 @@ note: required because of the requirements on the impl of `Grault` for `(T,)` | LL | impl Grault for (T,) | ^^^^^^ ^^^^ - = note: 1 redundant requirements hidden + = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Grault` for `(T,)` error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` @@ -29,7 +29,7 @@ note: required because of the requirements on the impl of `Grault` for `(T,)` | LL | impl Grault for (T,) | ^^^^^^ ^^^^ - = note: 1 redundant requirements hidden + = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Grault` for `(T,)` error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` @@ -43,7 +43,7 @@ note: required because of the requirements on the impl of `Grault` for `(T,)` | LL | impl Grault for (T,) | ^^^^^^ ^^^^ - = note: 1 redundant requirements hidden + = note: 1 redundant requirement hidden = note: required because of the requirements on the impl of `Grault` for `(T,)` error: aborting due to 3 previous errors diff --git a/src/test/ui/associated-types/issue-22560.stderr b/src/test/ui/associated-types/issue-22560.stderr index d2193cc4a4895..c5c70f226fdf6 100644 --- a/src/test/ui/associated-types/issue-22560.stderr +++ b/src/test/ui/associated-types/issue-22560.stderr @@ -32,7 +32,7 @@ LL | type Test = dyn Add + Sub; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified diff --git a/src/test/ui/associated-types/missing-associated-types.stderr b/src/test/ui/associated-types/missing-associated-types.stderr index 340d4e2418e0f..8c52736b02c4c 100644 --- a/src/test/ui/associated-types/missing-associated-types.stderr +++ b/src/test/ui/associated-types/missing-associated-types.stderr @@ -6,7 +6,7 @@ LL | type Foo = dyn Add + Sub + X + Y; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + X + Y {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub + X + Y {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `Add`), `Output` (from trait `Mul`), `Output` (from trait `Sub`) must be specified @@ -35,7 +35,7 @@ LL | type Bar = dyn Add + Sub + X + Z; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + X + Z {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub + X + Z {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `A` (from trait `Z`), `B` (from trait `Z`), `Output` (from trait `Add`), `Output` (from trait `Div`), `Output` (from trait `Div`), `Output` (from trait `Mul`), `Output` (from trait `Sub`) must be specified @@ -71,7 +71,7 @@ LL | type Baz = dyn Add + Sub + Y; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + Y {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub + Y {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified @@ -99,7 +99,7 @@ LL | type Bat = dyn Add + Sub + Fine; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Add + Sub + Fine {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub + Fine {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified diff --git a/src/test/ui/async-await/issue-61452.stderr b/src/test/ui/async-await/issue-61452.stderr index f2dec87baf08b..2d3bb48e03be8 100644 --- a/src/test/ui/async-await/issue-61452.stderr +++ b/src/test/ui/async-await/issue-61452.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable LL | pub async fn f(x: Option) { | - help: consider changing this to be mutable: `mut x` LL | x.take(); - | ^ cannot borrow as mutable + | ^^^^^^^^ cannot borrow as mutable error[E0384]: cannot assign twice to immutable variable `x` --> $DIR/issue-61452.rs:9:5 diff --git a/src/test/ui/async-await/issue-72442.rs b/src/test/ui/async-await/issue-72442.rs index 61c8c8c1594d3..2280154c7157c 100644 --- a/src/test/ui/async-await/issue-72442.rs +++ b/src/test/ui/async-await/issue-72442.rs @@ -1,5 +1,5 @@ // edition:2018 -// compile-flags:-Cincremental=tmp/issue-72442 +// incremental use std::fs::File; use std::future::Future; diff --git a/src/test/ui/async-await/issues/issue-61187.stderr b/src/test/ui/async-await/issues/issue-61187.stderr index 4d361c824dd6d..163053471b52d 100644 --- a/src/test/ui/async-await/issues/issue-61187.stderr +++ b/src/test/ui/async-await/issues/issue-61187.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `data` as mutable, as it is not declared as mutable LL | async fn response(data: Vec) { | ---- help: consider changing this to be mutable: `mut data` LL | data.reverse(); - | ^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-62097.nll.stderr b/src/test/ui/async-await/issues/issue-62097.nll.stderr index e71bcf5822808..786f621326049 100644 --- a/src/test/ui/async-await/issues/issue-62097.nll.stderr +++ b/src/test/ui/async-await/issues/issue-62097.nll.stderr @@ -20,9 +20,15 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-62097.rs:13:9 | LL | pub async fn run_dummy_fn(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | foo(|| self.bar()).await; - | ^^^^^^^^^^^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/async-await/issues/issue-64964.rs b/src/test/ui/async-await/issues/issue-64964.rs index 5313d1715c483..6d6eff4864ee3 100644 --- a/src/test/ui/async-await/issues/issue-64964.rs +++ b/src/test/ui/async-await/issues/issue-64964.rs @@ -1,5 +1,6 @@ // check-pass -// compile-flags: -Z query-dep-graph -C incremental=tmp/issue-64964 +// incremental +// compile-flags: -Z query-dep-graph // edition:2018 // Regression test for ICE related to `await`ing in a method + incr. comp. (#64964) diff --git a/src/test/ui/attributes/extented-attribute-macro-error.rs b/src/test/ui/attributes/extented-attribute-macro-error.rs new file mode 100644 index 0000000000000..f5f75f9f4dac5 --- /dev/null +++ b/src/test/ui/attributes/extented-attribute-macro-error.rs @@ -0,0 +1,8 @@ +// normalize-stderr-test: "couldn't read.*" -> "couldn't read the file" + +#![feature(extended_key_value_attributes)] +#![doc = include_str!("../not_existing_file.md")] +struct Documented {} +//~^^ ERROR couldn't read + +fn main() {} diff --git a/src/test/ui/attributes/extented-attribute-macro-error.stderr b/src/test/ui/attributes/extented-attribute-macro-error.stderr new file mode 100644 index 0000000000000..e4deeacd0ff60 --- /dev/null +++ b/src/test/ui/attributes/extented-attribute-macro-error.stderr @@ -0,0 +1,10 @@ +error: couldn't read the file + --> $DIR/extented-attribute-macro-error.rs:4:10 + | +LL | #![doc = include_str!("../not_existing_file.md")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/attributes/register-attr-tool-fail.stderr b/src/test/ui/attributes/register-attr-tool-fail.stderr index 77acfcd87cf75..8f6977cb55f25 100644 --- a/src/test/ui/attributes/register-attr-tool-fail.stderr +++ b/src/test/ui/attributes/register-attr-tool-fail.stderr @@ -30,13 +30,13 @@ error: malformed `register_attr` attribute input --> $DIR/register-attr-tool-fail.rs:4:1 | LL | #![register_attr] - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_attr(attr1, attr2, ...)]` + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_attr(attr1, attr2, ...)]` error: malformed `register_tool` attribute input --> $DIR/register-attr-tool-fail.rs:5:1 | LL | #![register_tool] - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_tool(tool1, tool2, ...)]` + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_tool(tool1, tool2, ...)]` error: aborting due to 6 previous errors diff --git a/src/test/ui/auto-traits/auto-trait-validation.fixed b/src/test/ui/auto-traits/auto-trait-validation.fixed new file mode 100644 index 0000000000000..da878ac6222bb --- /dev/null +++ b/src/test/ui/auto-traits/auto-trait-validation.fixed @@ -0,0 +1,13 @@ +#![feature(auto_traits)] + +// run-rustfix + +auto trait Generic {} +//~^ auto traits cannot have generic parameters [E0567] +auto trait Bound {} +//~^ auto traits cannot have super traits or lifetime bounds [E0568] +auto trait LifetimeBound {} +//~^ auto traits cannot have super traits or lifetime bounds [E0568] +auto trait MyTrait { } +//~^ auto traits cannot have associated items [E0380] +fn main() {} diff --git a/src/test/ui/auto-traits/auto-trait-validation.rs b/src/test/ui/auto-traits/auto-trait-validation.rs index a997b044c8ff8..d43055e270bd5 100644 --- a/src/test/ui/auto-traits/auto-trait-validation.rs +++ b/src/test/ui/auto-traits/auto-trait-validation.rs @@ -1,9 +1,13 @@ #![feature(auto_traits)] +// run-rustfix + auto trait Generic {} //~^ auto traits cannot have generic parameters [E0567] auto trait Bound : Copy {} -//~^ auto traits cannot have super traits [E0568] +//~^ auto traits cannot have super traits or lifetime bounds [E0568] +auto trait LifetimeBound : 'static {} +//~^ auto traits cannot have super traits or lifetime bounds [E0568] auto trait MyTrait { fn foo() {} } -//~^ auto traits cannot have methods or associated items [E0380] +//~^ auto traits cannot have associated items [E0380] fn main() {} diff --git a/src/test/ui/auto-traits/auto-trait-validation.stderr b/src/test/ui/auto-traits/auto-trait-validation.stderr index 4040e66c6af77..2c380e5b09a6e 100644 --- a/src/test/ui/auto-traits/auto-trait-validation.stderr +++ b/src/test/ui/auto-traits/auto-trait-validation.stderr @@ -1,28 +1,37 @@ error[E0567]: auto traits cannot have generic parameters - --> $DIR/auto-trait-validation.rs:3:19 + --> $DIR/auto-trait-validation.rs:5:19 | LL | auto trait Generic {} | -------^^^ help: remove the parameters | | | auto trait cannot have generic parameters -error[E0568]: auto traits cannot have super traits - --> $DIR/auto-trait-validation.rs:5:20 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/auto-trait-validation.rs:7:17 | LL | auto trait Bound : Copy {} - | ----- ^^^^ help: remove the super traits + | -----^^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have super traits + | auto trait cannot have super traits or lifetime bounds -error[E0380]: auto traits cannot have methods or associated items - --> $DIR/auto-trait-validation.rs:7:25 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/auto-trait-validation.rs:9:25 | -LL | auto trait MyTrait { fn foo() {} } - | ------- ^^^ +LL | auto trait LifetimeBound : 'static {} + | -------------^^^^^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have items + | auto trait cannot have super traits or lifetime bounds + +error[E0380]: auto traits cannot have associated items + --> $DIR/auto-trait-validation.rs:11:25 + | +LL | auto trait MyTrait { fn foo() {} } + | ------- ---^^^----- + | | | + | | help: remove these associated items + | auto trait cannot have associated items -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0380, E0567, E0568. For more information about an error, try `rustc --explain E0380`. diff --git a/src/test/ui/auto-traits/issue-23080-2.stderr b/src/test/ui/auto-traits/issue-23080-2.stderr index efeceafdd2a7d..267a712f62fa0 100644 --- a/src/test/ui/auto-traits/issue-23080-2.stderr +++ b/src/test/ui/auto-traits/issue-23080-2.stderr @@ -1,10 +1,10 @@ -error[E0380]: auto traits cannot have methods or associated items +error[E0380]: auto traits cannot have associated items --> $DIR/issue-23080-2.rs:5:10 | LL | unsafe auto trait Trait { - | ----- auto trait cannot have items + | ----- auto trait cannot have associated items LL | type Output; - | ^^^^^^ + | -----^^^^^^- help: remove these associated items error: aborting due to previous error diff --git a/src/test/ui/auto-traits/issue-23080.stderr b/src/test/ui/auto-traits/issue-23080.stderr index 73ecb1c362e17..c1b16b2f403d7 100644 --- a/src/test/ui/auto-traits/issue-23080.stderr +++ b/src/test/ui/auto-traits/issue-23080.stderr @@ -1,10 +1,13 @@ -error[E0380]: auto traits cannot have methods or associated items +error[E0380]: auto traits cannot have associated items --> $DIR/issue-23080.rs:5:8 | -LL | unsafe auto trait Trait { - | ----- auto trait cannot have items -LL | fn method(&self) { - | ^^^^^^ +LL | unsafe auto trait Trait { + | ----- auto trait cannot have associated items +LL | fn method(&self) { + | _____- ^^^^^^ +LL | | println!("Hello"); +LL | | } + | |_____- help: remove these associated items error: aborting due to previous error diff --git a/src/test/ui/auto-traits/issue-84075.rs b/src/test/ui/auto-traits/issue-84075.rs new file mode 100644 index 0000000000000..a6afe24ea4c8b --- /dev/null +++ b/src/test/ui/auto-traits/issue-84075.rs @@ -0,0 +1,16 @@ +// Regression test for issue #84075. + +#![feature(auto_traits)] + +auto trait Magic where Self: Copy {} //~ ERROR E0568 +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); + println!("{:?} {:?}", a, b); +} diff --git a/src/test/ui/auto-traits/issue-84075.stderr b/src/test/ui/auto-traits/issue-84075.stderr new file mode 100644 index 0000000000000..02dca598ec250 --- /dev/null +++ b/src/test/ui/auto-traits/issue-84075.stderr @@ -0,0 +1,11 @@ +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/issue-84075.rs:5:18 + | +LL | auto trait Magic where Self: Copy {} + | ----- ^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds + | | + | auto trait cannot have super traits or lifetime bounds + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0568`. diff --git a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs index 6cceaf821f6bf..98359ef51b764 100644 --- a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs +++ b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.rs @@ -2,6 +2,7 @@ #![feature(negative_impls)] auto trait Magic : Sized where Option : Magic {} //~ ERROR E0568 +//~^ ERROR E0568 impl Magic for T {} fn copy(x: T) -> (T, T) { (x, x) } diff --git a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr index 63b3300f6dbf4..4827916fa5c53 100644 --- a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr +++ b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits-2.stderr @@ -1,11 +1,19 @@ -error[E0568]: auto traits cannot have super traits - --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:20 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:17 | LL | auto trait Magic : Sized where Option : Magic {} - | ----- ^^^^^ help: remove the super traits + | -----^^^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have super traits + | auto trait cannot have super traits or lifetime bounds -error: aborting due to previous error +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/typeck-auto-trait-no-supertraits-2.rs:4:26 + | +LL | auto trait Magic : Sized where Option : Magic {} + | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the super traits or lifetime bounds + | | + | auto trait cannot have super traits or lifetime bounds + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0568`. diff --git a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr index 796638fc54dce..d7716f4b61f04 100644 --- a/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr +++ b/src/test/ui/auto-traits/typeck-auto-trait-no-supertraits.stderr @@ -1,10 +1,10 @@ -error[E0568]: auto traits cannot have super traits - --> $DIR/typeck-auto-trait-no-supertraits.rs:28:19 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/typeck-auto-trait-no-supertraits.rs:28:17 | LL | auto trait Magic: Copy {} - | ----- ^^^^ help: remove the super traits + | -----^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have super traits + | auto trait cannot have super traits or lifetime bounds error: aborting due to previous error diff --git a/src/test/ui/autoderef-full-lval.rs b/src/test/ui/autoderef-full-lval.rs index f07a2c107ba45..0fadc5c98277e 100644 --- a/src/test/ui/autoderef-full-lval.rs +++ b/src/test/ui/autoderef-full-lval.rs @@ -1,23 +1,23 @@ -#![feature(box_syntax)] - struct Clam { x: Box, y: Box, } + + struct Fish { a: Box, } fn main() { - let a: Clam = Clam{x: box 1, y: box 2}; - let b: Clam = Clam{x: box 10, y: box 20}; + let a: Clam = Clam{ x: Box::new(1), y: Box::new(2) }; + let b: Clam = Clam{ x: Box::new(10), y: Box::new(20) }; let z: isize = a.x + b.y; //~^ ERROR cannot add `Box` to `Box` println!("{}", z); assert_eq!(z, 21); - let forty: Fish = Fish{a: box 40}; - let two: Fish = Fish{a: box 2}; + let forty: Fish = Fish{ a: Box::new(40) }; + let two: Fish = Fish{ a: Box::new(2) }; let answer: isize = forty.a + two.a; //~^ ERROR cannot add `Box` to `Box` println!("{}", answer); diff --git a/src/test/ui/autoref-autoderef/autoderef-method-on-trait.rs b/src/test/ui/autoref-autoderef/autoderef-method-on-trait.rs index fadb0784e7525..af747cc76e9a0 100644 --- a/src/test/ui/autoref-autoderef/autoderef-method-on-trait.rs +++ b/src/test/ui/autoref-autoderef/autoderef-method-on-trait.rs @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self: Box) -> usize; @@ -11,6 +10,6 @@ impl double for usize { } pub fn main() { - let x: Box<_> = box (box 3usize as Box); + let x: Box<_> = Box::new(Box::new(3usize) as Box); assert_eq!(x.double(), 6); } diff --git a/src/test/ui/autoref-autoderef/autoderef-method-priority.rs b/src/test/ui/autoref-autoderef/autoderef-method-priority.rs index a218f85eba2c6..88a5140dc752b 100644 --- a/src/test/ui/autoref-autoderef/autoderef-method-priority.rs +++ b/src/test/ui/autoref-autoderef/autoderef-method-priority.rs @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self) -> usize; @@ -15,6 +14,6 @@ impl double for Box { } pub fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); assert_eq!(x.double(), 6); } diff --git a/src/test/ui/autoref-autoderef/autoderef-method-twice-but-not-thrice.rs b/src/test/ui/autoref-autoderef/autoderef-method-twice-but-not-thrice.rs index 9fda3b2c09999..3657e61d42534 100644 --- a/src/test/ui/autoref-autoderef/autoderef-method-twice-but-not-thrice.rs +++ b/src/test/ui/autoref-autoderef/autoderef-method-twice-but-not-thrice.rs @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self: Box) -> usize; @@ -11,6 +10,6 @@ impl double for Box { } pub fn main() { - let x: Box>>>> = box box box box box 3; + let x: Box>>>> = Box::new(Box::new(Box::new(Box::new(Box::new(3))))); assert_eq!(x.double(), 6); } diff --git a/src/test/ui/autoref-autoderef/autoderef-method-twice.rs b/src/test/ui/autoref-autoderef/autoderef-method-twice.rs index f53dc8d1032bf..ed86b31b8bbed 100644 --- a/src/test/ui/autoref-autoderef/autoderef-method-twice.rs +++ b/src/test/ui/autoref-autoderef/autoderef-method-twice.rs @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self: Box) -> usize; @@ -11,6 +10,6 @@ impl double for usize { } pub fn main() { - let x: Box> = box box 3; + let x: Box> = Box::new(Box::new(3)); assert_eq!(x.double(), 6); } diff --git a/src/test/ui/autoref-autoderef/autoderef-method.rs b/src/test/ui/autoref-autoderef/autoderef-method.rs index 262050fa47bec..5b7965e9553fe 100644 --- a/src/test/ui/autoref-autoderef/autoderef-method.rs +++ b/src/test/ui/autoref-autoderef/autoderef-method.rs @@ -1,6 +1,5 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait double { fn double(self: Box) -> usize; @@ -11,6 +10,6 @@ impl double for usize { } pub fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); assert_eq!(x.double(), 6); } diff --git a/src/test/ui/autoref-autoderef/autoref-intermediate-types-issue-3585.rs b/src/test/ui/autoref-autoderef/autoref-intermediate-types-issue-3585.rs index 70ef7ce87ede8..3bdc248ff0f7f 100644 --- a/src/test/ui/autoref-autoderef/autoref-intermediate-types-issue-3585.rs +++ b/src/test/ui/autoref-autoderef/autoref-intermediate-types-issue-3585.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] trait Foo { fn foo(&self) -> String; @@ -18,6 +17,6 @@ impl Foo for usize { } pub fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); assert_eq!(x.foo(), "box 3".to_string()); } diff --git a/src/test/ui/autoref-autoderef/issue-38940.stderr b/src/test/ui/autoref-autoderef/issue-38940.stderr index 0671cede73bbe..a560334314cea 100644 --- a/src/test/ui/autoref-autoderef/issue-38940.stderr +++ b/src/test/ui/autoref-autoderef/issue-38940.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `J` LL | let x: &Bottom = &t; | ^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`issue_38940`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`issue_38940`) error[E0308]: mismatched types --> $DIR/issue-38940.rs:43:22 diff --git a/src/test/ui/binding/expr-match-generic-unique1.rs b/src/test/ui/binding/expr-match-generic-unique1.rs index 5a5f75eea3679..c5f38d815593a 100644 --- a/src/test/ui/binding/expr-match-generic-unique1.rs +++ b/src/test/ui/binding/expr-match-generic-unique1.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn test_generic(expected: Box, eq: F) where F: FnOnce(Box, Box) -> bool { let actual: Box = match true { @@ -13,7 +12,7 @@ fn test_box() { fn compare_box(b1: Box, b2: Box) -> bool { return *b1 == *b2; } - test_generic::(box true, compare_box); + test_generic::(Box::new(true), compare_box); } pub fn main() { test_box(); } diff --git a/src/test/ui/binding/expr-match-generic-unique2.rs b/src/test/ui/binding/expr-match-generic-unique2.rs index 1d236135cdbd7..8977ca68efa67 100644 --- a/src/test/ui/binding/expr-match-generic-unique2.rs +++ b/src/test/ui/binding/expr-match-generic-unique2.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn test_generic(expected: T, eq: F) where F: FnOnce(T, T) -> bool { let actual: T = match true { @@ -11,7 +10,7 @@ fn test_generic(expected: T, eq: F) where F: FnOnce(T, T) -> bool { fn test_vec() { fn compare_box(v1: Box, v2: Box) -> bool { return v1 == v2; } - test_generic::, _>(box 1, compare_box); + test_generic::, _>(Box::new(1), compare_box); } pub fn main() { test_vec(); } diff --git a/src/test/ui/binding/expr-match-unique.rs b/src/test/ui/binding/expr-match-unique.rs index a999541207d14..eec9e1f8b4ae1 100644 --- a/src/test/ui/binding/expr-match-unique.rs +++ b/src/test/ui/binding/expr-match-unique.rs @@ -1,9 +1,8 @@ // run-pass -#![feature(box_syntax)] // Tests for match as expressions resulting in boxed types fn test_box() { - let res: Box<_> = match true { true => { box 100 }, _ => panic!() }; + let res: Box<_> = match true { true => { Box::new(100) }, _ => panic!() }; assert_eq!(*res, 100); } diff --git a/src/test/ui/binding/func-arg-incomplete-pattern.rs b/src/test/ui/binding/func-arg-incomplete-pattern.rs index 98dd51811de5b..eb94ee48f9249 100644 --- a/src/test/ui/binding/func-arg-incomplete-pattern.rs +++ b/src/test/ui/binding/func-arg-incomplete-pattern.rs @@ -3,8 +3,6 @@ // Test that we do not leak when the arg pattern must drop part of the // argument (in this case, the `y` field). -#![feature(box_syntax)] - struct Foo { x: Box, y: Box, @@ -16,9 +14,9 @@ fn foo(Foo {x, ..}: Foo) -> *const usize { } pub fn main() { - let obj: Box<_> = box 1; + let obj: Box<_> = Box::new(1); let objptr: *const usize = &*obj; - let f = Foo {x: obj, y: box 2}; + let f = Foo { x: obj, y: Box::new(2) }; let xptr = foo(f); assert_eq!(objptr, xptr); } diff --git a/src/test/ui/binding/func-arg-ref-pattern.rs b/src/test/ui/binding/func-arg-ref-pattern.rs index f46eeb7a020d8..2d75c12140bf3 100644 --- a/src/test/ui/binding/func-arg-ref-pattern.rs +++ b/src/test/ui/binding/func-arg-ref-pattern.rs @@ -5,7 +5,6 @@ // pattern. #![feature(box_patterns)] -#![feature(box_syntax)] fn getaddr(box ref x: Box) -> *const usize { let addr: *const usize = &*x; @@ -17,11 +16,11 @@ fn checkval(box ref x: Box) -> usize { } pub fn main() { - let obj: Box<_> = box 1; + let obj: Box<_> = Box::new(1); let objptr: *const usize = &*obj; let xptr = getaddr(obj); assert_eq!(objptr, xptr); - let obj = box 22; + let obj = Box::new(22); assert_eq!(checkval(obj), 22); } diff --git a/src/test/ui/binding/let-assignability.rs b/src/test/ui/binding/let-assignability.rs index 5bb375d285d38..b85f4a96a6d50 100644 --- a/src/test/ui/binding/let-assignability.rs +++ b/src/test/ui/binding/let-assignability.rs @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] fn f() { - let a: Box<_> = box 1; + let a: Box<_> = Box::new(1); let b: &isize = &*a; println!("{}", b); } diff --git a/src/test/ui/binding/match-implicit-copy-unique.rs b/src/test/ui/binding/match-implicit-copy-unique.rs index a7e8109b46ca7..74ffe2ecdb3a5 100644 --- a/src/test/ui/binding/match-implicit-copy-unique.rs +++ b/src/test/ui/binding/match-implicit-copy-unique.rs @@ -1,16 +1,15 @@ // run-pass #![allow(non_shorthand_field_patterns)] -#![feature(box_syntax)] struct Pair { a: Box, b: Box } pub fn main() { - let mut x: Box<_> = box Pair {a: box 10, b: box 20}; + let mut x: Box<_> = Box::new(Pair { a: Box::new(10), b: Box::new(20) }); let x_internal = &mut *x; match *x_internal { Pair {a: ref mut a, b: ref mut _b} => { assert_eq!(**a, 10); - *a = box 30; + *a = Box::new(30); assert_eq!(**a, 30); } } diff --git a/src/test/ui/binding/match-unique-bind.rs b/src/test/ui/binding/match-unique-bind.rs index f5361b118bed8..507478983f681 100644 --- a/src/test/ui/binding/match-unique-bind.rs +++ b/src/test/ui/binding/match-unique-bind.rs @@ -1,9 +1,8 @@ // run-pass #![feature(box_patterns)] -#![feature(box_syntax)] pub fn main() { - match box 100 { + match Box::new(100) { box x => { println!("{}", x); assert_eq!(x, 100); diff --git a/src/test/ui/binding/match-value-binding-in-guard-3291.rs b/src/test/ui/binding/match-value-binding-in-guard-3291.rs index 4b209b20a18aa..0d750da79e71c 100644 --- a/src/test/ui/binding/match-value-binding-in-guard-3291.rs +++ b/src/test/ui/binding/match-value-binding-in-guard-3291.rs @@ -1,8 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn foo(x: Option>, b: bool) -> isize { match x { None => { 1 } @@ -12,8 +10,8 @@ fn foo(x: Option>, b: bool) -> isize { } pub fn main() { - foo(Some(box 22), true); - foo(Some(box 22), false); + foo(Some(Box::new(22)), true); + foo(Some(Box::new(22)), false); foo(None, true); foo(None, false); } diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr index 7721f8827db87..2cd6d1abfdcdb 100644 --- a/src/test/ui/binop/binop-move-semantics.stderr +++ b/src/test/ui/binop/binop-move-semantics.stderr @@ -30,7 +30,7 @@ LL | x | - value moved here LL | + LL | x.clone(); - | ^ value borrowed here after move + | ^^^^^^^^^ value borrowed here after move | help: consider further restricting this bound | diff --git a/src/test/ui/binop/issue-28837.stderr b/src/test/ui/binop/issue-28837.stderr index 07f67bc3de79d..10f243bab1586 100644 --- a/src/test/ui/binop/issue-28837.stderr +++ b/src/test/ui/binop/issue-28837.stderr @@ -6,7 +6,22 @@ LL | a + a; | | | A | - = note: an implementation of `std::ops::Add` might be missing for `A` +note: an implementation of `Add<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Add<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Add { +LL | | /// The resulting type after applying the `+` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn add(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot subtract `A` from `A` --> $DIR/issue-28837.rs:8:7 @@ -16,7 +31,22 @@ LL | a - a; | | | A | - = note: an implementation of `std::ops::Sub` might be missing for `A` +note: an implementation of `Sub<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Sub<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Sub { +LL | | /// The resulting type after applying the `-` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn sub(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot multiply `A` by `A` --> $DIR/issue-28837.rs:10:7 @@ -26,7 +56,22 @@ LL | a * a; | | | A | - = note: an implementation of `std::ops::Mul` might be missing for `A` +note: an implementation of `Mul<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Mul<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Mul { +LL | | /// The resulting type after applying the `*` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn mul(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot divide `A` by `A` --> $DIR/issue-28837.rs:12:7 @@ -36,7 +81,22 @@ LL | a / a; | | | A | - = note: an implementation of `std::ops::Div` might be missing for `A` +note: an implementation of `Div<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Div<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Div { +LL | | /// The resulting type after applying the `/` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn div(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot mod `A` by `A` --> $DIR/issue-28837.rs:14:7 @@ -46,7 +106,22 @@ LL | a % a; | | | A | - = note: an implementation of `std::ops::Rem` might be missing for `A` +note: an implementation of `Rem<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Rem<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Rem { +LL | | /// The resulting type after applying the `%` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn rem(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: no implementation for `A & A` --> $DIR/issue-28837.rs:16:7 @@ -56,7 +131,22 @@ LL | a & a; | | | A | - = note: an implementation of `std::ops::BitAnd` might be missing for `A` +note: an implementation of `BitAnd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `BitAnd<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait BitAnd { +LL | | /// The resulting type after applying the `&` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn bitand(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: no implementation for `A | A` --> $DIR/issue-28837.rs:18:7 @@ -66,7 +156,22 @@ LL | a | a; | | | A | - = note: an implementation of `std::ops::BitOr` might be missing for `A` +note: an implementation of `BitOr<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `BitOr<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait BitOr { +LL | | /// The resulting type after applying the `|` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn bitor(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: no implementation for `A << A` --> $DIR/issue-28837.rs:20:7 @@ -76,7 +181,22 @@ LL | a << a; | | | A | - = note: an implementation of `std::ops::Shl` might be missing for `A` +note: an implementation of `Shl<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Shl<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait Shl { +LL | | /// The resulting type after applying the `<<` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn shl(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: no implementation for `A >> A` --> $DIR/issue-28837.rs:22:7 @@ -86,7 +206,22 @@ LL | a >> a; | | | A | - = note: an implementation of `std::ops::Shr` might be missing for `A` +note: an implementation of `Shr<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `Shr<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait Shr { +LL | | /// The resulting type after applying the `>>` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn shr(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: binary operation `==` cannot be applied to type `A` --> $DIR/issue-28837.rs:24:7 @@ -96,7 +231,15 @@ LL | a == a; | | | A | - = note: an implementation of `std::cmp::PartialEq` might be missing for `A` +note: an implementation of `PartialEq<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialEq<_>` +help: consider annotating `A` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `A` --> $DIR/issue-28837.rs:26:7 @@ -106,7 +249,15 @@ LL | a != a; | | | A | - = note: an implementation of `std::cmp::PartialEq` might be missing for `A` +note: an implementation of `PartialEq<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialEq<_>` +help: consider annotating `A` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `<` cannot be applied to type `A` --> $DIR/issue-28837.rs:28:7 @@ -116,7 +267,15 @@ LL | a < a; | | | A | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` +note: an implementation of `PartialOrd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialOrd<_>` +help: consider annotating `A` with `#[derive(PartialOrd)]` + | +LL | #[derive(PartialOrd)] + | error[E0369]: binary operation `<=` cannot be applied to type `A` --> $DIR/issue-28837.rs:30:7 @@ -126,7 +285,15 @@ LL | a <= a; | | | A | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` +note: an implementation of `PartialOrd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialOrd<_>` +help: consider annotating `A` with `#[derive(PartialOrd)]` + | +LL | #[derive(PartialOrd)] + | error[E0369]: binary operation `>` cannot be applied to type `A` --> $DIR/issue-28837.rs:32:7 @@ -136,7 +303,15 @@ LL | a > a; | | | A | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` +note: an implementation of `PartialOrd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialOrd<_>` +help: consider annotating `A` with `#[derive(PartialOrd)]` + | +LL | #[derive(PartialOrd)] + | error[E0369]: binary operation `>=` cannot be applied to type `A` --> $DIR/issue-28837.rs:34:7 @@ -146,7 +321,15 @@ LL | a >= a; | | | A | - = note: an implementation of `std::cmp::PartialOrd` might be missing for `A` +note: an implementation of `PartialOrd<_>` might be missing for `A` + --> $DIR/issue-28837.rs:1:1 + | +LL | struct A; + | ^^^^^^^^^ must implement `PartialOrd<_>` +help: consider annotating `A` with `#[derive(PartialOrd)]` + | +LL | #[derive(PartialOrd)] + | error: aborting due to 15 previous errors diff --git a/src/test/ui/borrowck/borrow-tuple-fields.rs b/src/test/ui/borrowck/borrow-tuple-fields.rs index 3e24a1b29c920..c628fa49ede43 100644 --- a/src/test/ui/borrowck/borrow-tuple-fields.rs +++ b/src/test/ui/borrowck/borrow-tuple-fields.rs @@ -1,13 +1,13 @@ -#![feature(box_syntax)] +struct Foo(Box, isize); + +struct Bar(isize, isize); -struct Foo(Box, isize); -struct Bar(isize, isize); fn main() { - let x: (Box<_>, _) = (box 1, 2); + let x: (Box<_>, _) = (Box::new(1), 2); let r = &x.0; let y = x; //~ ERROR cannot move out of `x` because it is borrowed @@ -23,7 +23,7 @@ fn main() { let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time a.use_ref(); - let x = Foo(box 1, 2); + let x = Foo(Box::new(1), 2); let r = &x.0; let y = x; //~ ERROR cannot move out of `x` because it is borrowed r.use_ref(); diff --git a/src/test/ui/borrowck/borrow-tuple-fields.stderr b/src/test/ui/borrowck/borrow-tuple-fields.stderr index 503ea49d74ee0..ad628abcbfc2e 100644 --- a/src/test/ui/borrowck/borrow-tuple-fields.stderr +++ b/src/test/ui/borrowck/borrow-tuple-fields.stderr @@ -7,7 +7,7 @@ LL | let y = x; | ^ move out of `x` occurs here LL | LL | r.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable --> $DIR/borrow-tuple-fields.rs:18:13 @@ -17,7 +17,7 @@ LL | let a = &x.0; LL | let b = &mut x.0; | ^^^^^^^^ mutable borrow occurs here LL | a.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0499]: cannot borrow `x.0` as mutable more than once at a time --> $DIR/borrow-tuple-fields.rs:23:13 @@ -27,7 +27,7 @@ LL | let a = &mut x.0; LL | let b = &mut x.0; | ^^^^^^^^ second mutable borrow occurs here LL | a.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/borrow-tuple-fields.rs:28:13 @@ -37,7 +37,7 @@ LL | let r = &x.0; LL | let y = x; | ^ move out of `x` occurs here LL | r.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0502]: cannot borrow `x.0` as mutable because it is also borrowed as immutable --> $DIR/borrow-tuple-fields.rs:33:13 @@ -47,7 +47,7 @@ LL | let a = &x.0; LL | let b = &mut x.0; | ^^^^^^^^ mutable borrow occurs here LL | a.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0499]: cannot borrow `x.0` as mutable more than once at a time --> $DIR/borrow-tuple-fields.rs:38:13 @@ -57,7 +57,7 @@ LL | let a = &mut x.0; LL | let b = &mut x.0; | ^^^^^^^^ second mutable borrow occurs here LL | a.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to 6 previous errors diff --git a/src/test/ui/borrowck/borrowck-argument.stderr b/src/test/ui/borrowck/borrowck-argument.stderr index cf15833140927..d4d646e390c31 100644 --- a/src/test/ui/borrowck/borrowck-argument.stderr +++ b/src/test/ui/borrowck/borrowck-argument.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable LL | fn func(arg: S) { | --- help: consider changing this to be mutable: `mut arg` LL | arg.mutate(); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:15:9 @@ -12,7 +12,7 @@ error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable LL | fn method(&self, arg: S) { | --- help: consider changing this to be mutable: `mut arg` LL | arg.mutate(); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:21:9 @@ -20,13 +20,13 @@ error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable LL | fn default(&self, arg: S) { | --- help: consider changing this to be mutable: `mut arg` LL | arg.mutate(); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable --> $DIR/borrowck-argument.rs:32:17 | LL | (|arg: S| { arg.mutate() })(s); - | --- ^^^ cannot borrow as mutable + | --- ^^^^^^^^^^^^ cannot borrow as mutable | | | help: consider changing this to be mutable: `mut arg` diff --git a/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr b/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr index 3ed76c13f6a7b..186ecddd6d61d 100644 --- a/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr +++ b/src/test/ui/borrowck/borrowck-auto-mut-ref-to-immut-var.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable LL | let x = Foo { x: 3 }; | - help: consider changing this to be mutable: `mut x` LL | x.printme(); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-bad-nested-calls-free.rs b/src/test/ui/borrowck/borrowck-bad-nested-calls-free.rs index 3abc56153b78a..b0bb9a0351b49 100644 --- a/src/test/ui/borrowck/borrowck-bad-nested-calls-free.rs +++ b/src/test/ui/borrowck/borrowck-bad-nested-calls-free.rs @@ -1,10 +1,10 @@ // Test that we detect nested calls that could free pointers evaluated // for earlier arguments. -#![feature(box_syntax)] + fn rewrite(v: &mut Box) -> usize { - *v = box 22; + *v = Box::new(22); **v } @@ -13,7 +13,7 @@ fn add(v: &usize, w: usize) -> usize { } fn implicit() { - let mut a: Box<_> = box 1; + let mut a: Box<_> = Box::new(1); // Note the danger here: // @@ -26,7 +26,7 @@ fn implicit() { } fn explicit() { - let mut a: Box<_> = box 1; + let mut a: Box<_> = Box::new(1); add( &*a, rewrite(&mut a)); //~ ERROR cannot borrow diff --git a/src/test/ui/borrowck/borrowck-bad-nested-calls-move.rs b/src/test/ui/borrowck/borrowck-bad-nested-calls-move.rs index fd8df78a5d5a1..b2afb6391c1ad 100644 --- a/src/test/ui/borrowck/borrowck-bad-nested-calls-move.rs +++ b/src/test/ui/borrowck/borrowck-bad-nested-calls-move.rs @@ -1,10 +1,10 @@ // Test that we detect nested calls that could free pointers evaluated // for earlier arguments. -#![feature(box_syntax)] + fn rewrite(v: &mut Box) -> usize { - *v = box 22; + *v = Box::new(22); **v } @@ -13,7 +13,7 @@ fn add(v: &usize, w: Box) -> usize { } fn implicit() { - let mut a: Box<_> = box 1; + let mut a: Box<_> = Box::new(1); // Note the danger here: // @@ -26,7 +26,7 @@ fn implicit() { } fn explicit() { - let mut a: Box<_> = box 1; + let mut a: Box<_> = Box::new(1); add( &*a, a); //~ ERROR cannot move diff --git a/src/test/ui/borrowck/borrowck-borrow-from-expr-block.rs b/src/test/ui/borrowck/borrowck-borrow-from-expr-block.rs index 15c6e8bf210fc..24efadc305511 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-expr-block.rs +++ b/src/test/ui/borrowck/borrowck-borrow-from-expr-block.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn borrow(x: &isize, f: F) where F: FnOnce(&isize) { f(x) @@ -14,5 +13,5 @@ fn test1(x: &Box) { } pub fn main() { - test1(&box 22); + test1(&Box::new(22)); } diff --git a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs b/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs index bc820ee9f9141..6b5544a8a396b 100644 --- a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs +++ b/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - struct A; impl A { @@ -7,8 +5,10 @@ impl A { } } + + pub fn main() { - let a: Box<_> = box A; + let a: Box<_> = Box::new(A); a.foo(); //~^ ERROR cannot borrow `*a` as mutable, as `a` is not declared as mutable [E0596] } diff --git a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr b/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr index 7d7e305a31f31..237071e16fc66 100644 --- a/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr @@ -1,10 +1,10 @@ error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable --> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5 | -LL | let a: Box<_> = box A; +LL | let a: Box<_> = Box::new(A); | - help: consider changing this to be mutable: `mut a` LL | a.foo(); - | ^ cannot borrow as mutable + | ^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr b/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr index fa0ae318e72cd..42b6c34cd2f37 100644 --- a/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-mut-object-twice.stderr @@ -2,11 +2,11 @@ error[E0499]: cannot borrow `*x` as mutable more than once at a time --> $DIR/borrowck-borrow-mut-object-twice.rs:13:5 | LL | let y = x.f1(); - | - first mutable borrow occurs here + | ------ first mutable borrow occurs here LL | x.f2(); - | ^ second mutable borrow occurs here + | ^^^^^^ second mutable borrow occurs here LL | y.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr index 426d5bc4726f5..fdf6568d8397d 100644 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr @@ -58,7 +58,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:72:5 | LL | x.set(0, 0); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -66,7 +66,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:76:5 | LL | x.set(0, 0); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -74,7 +74,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:84:5 | LL | x.y_mut() - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -82,7 +82,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:88:5 | LL | x.y_mut() - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -90,7 +90,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:92:6 | LL | *x.y_mut() = 3; - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -98,7 +98,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:96:6 | LL | *x.y_mut() = 3; - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` @@ -106,7 +106,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:100:6 | LL | *x.y_mut() = 3; - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs index a78c66f47cd14..1d05845fc6b20 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs @@ -1,8 +1,8 @@ -//buggy.rs +use std::collections::HashMap; + + -#![feature(box_syntax)] -use std::collections::HashMap; fn main() { let tmp: Box<_>; @@ -10,6 +10,6 @@ fn main() { buggy_map.insert(42, &*Box::new(1)); //~ ERROR temporary value dropped while borrowed // but it is ok if we use a temporary - tmp = box 2; + tmp = Box::new(2); buggy_map.insert(43, &*tmp); } diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr index c91a4377b4c67..01379ed851200 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.stderr @@ -7,7 +7,7 @@ LL | buggy_map.insert(42, &*Box::new(1)); | creates a temporary which is freed while still in use ... LL | buggy_map.insert(43, &*tmp); - | --------- borrow later used here + | --------------------------- borrow later used here | = note: consider using a `let` binding to create a longer lived value diff --git a/src/test/ui/borrowck/borrowck-box-sensitivity.rs b/src/test/ui/borrowck/borrowck-box-sensitivity.rs index e5591f500380b..e880f876f91a9 100644 --- a/src/test/ui/borrowck/borrowck-box-sensitivity.rs +++ b/src/test/ui/borrowck/borrowck-box-sensitivity.rs @@ -3,8 +3,6 @@ // run-pass -#![feature(box_syntax)] - struct A { x: Box, y: isize, @@ -26,97 +24,97 @@ struct D { } fn copy_after_move() { - let a: Box<_> = box A { x: box 0, y: 1 }; + let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = a.x; let _y = a.y; } fn move_after_move() { - let a: Box<_> = box B { x: box 0, y: box 1 }; + let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) }); let _x = a.x; let _y = a.y; } fn borrow_after_move() { - let a: Box<_> = box A { x: box 0, y: 1 }; + let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = a.x; let _y = &a.y; } fn move_after_borrow() { - let a: Box<_> = box B { x: box 0, y: box 1 }; + let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) }); let _x = &a.x; let _y = a.y; use_imm(_x); } fn copy_after_mut_borrow() { - let mut a: Box<_> = box A { x: box 0, y: 1 }; + let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = &mut a.x; let _y = a.y; use_mut(_x); } fn move_after_mut_borrow() { - let mut a: Box<_> = box B { x: box 0, y: box 1 }; + let mut a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) }); let _x = &mut a.x; let _y = a.y; use_mut(_x); } fn borrow_after_mut_borrow() { - let mut a: Box<_> = box A { x: box 0, y: 1 }; + let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = &mut a.x; let _y = &a.y; use_mut(_x); } fn mut_borrow_after_borrow() { - let mut a: Box<_> = box A { x: box 0, y: 1 }; + let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 }); let _x = &a.x; let _y = &mut a.y; use_imm(_x); } fn copy_after_move_nested() { - let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = a.x.x; let _y = a.y; } fn move_after_move_nested() { - let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; + let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) }); let _x = a.x.x; let _y = a.y; } fn borrow_after_move_nested() { - let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = a.x.x; let _y = &a.y; } fn move_after_borrow_nested() { - let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; + let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) }); let _x = &a.x.x; let _y = a.y; use_imm(_x); } fn copy_after_mut_borrow_nested() { - let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = &mut a.x.x; let _y = a.y; use_mut(_x); } fn move_after_mut_borrow_nested() { - let mut a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 }; + let mut a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) }); let _x = &mut a.x.x; let _y = a.y; use_mut(_x); } fn borrow_after_mut_borrow_nested() { - let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = &mut a.x.x; let _y = &a.y; use_mut(_x); } fn mut_borrow_after_borrow_nested() { - let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 }; + let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 }); let _x = &a.x.x; let _y = &mut a.y; use_imm(_x); diff --git a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs index 2dc405ffcd4c0..a8225f2faf166 100644 --- a/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs +++ b/src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs @@ -1,8 +1,6 @@ // Tests that two closures cannot simultaneously have mutable // and immutable access to the variable. Issue #6801. -#![feature(box_syntax)] - fn get(x: &isize) -> isize { *x } @@ -11,6 +9,8 @@ fn set(x: &mut isize) { *x = 4; } + + fn a() { let mut x = 3; let c1 = || x = 4; @@ -52,7 +52,7 @@ fn e() { } fn f() { - let mut x: Box<_> = box 3; + let mut x: Box<_> = Box::new(3); let c1 = || get(&*x); *x = 5; //~^ ERROR cannot assign to `*x` because it is borrowed @@ -64,7 +64,7 @@ fn g() { f: Box } - let mut x: Box<_> = box Foo { f: box 3 }; + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); let c1 = || get(&*x.f); *x.f = 5; //~^ ERROR cannot assign to `*x.f` because it is borrowed @@ -76,7 +76,7 @@ fn h() { f: Box } - let mut x: Box<_> = box Foo { f: box 3 }; + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); let c1 = || get(&*x.f); let c2 = || *x.f = 5; //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.rs b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.rs index 2a1757231db85..63a75cdff42de 100644 --- a/src/test/ui/borrowck/borrowck-closures-two-mut-fail.rs +++ b/src/test/ui/borrowck/borrowck-closures-two-mut-fail.rs @@ -2,7 +2,7 @@ // access to the variable, whether that mutable access be used // for direct assignment or for taking mutable ref. Issue #6801. -#![feature(box_syntax)] + @@ -48,7 +48,7 @@ fn g() { f: Box } - let mut x: Box<_> = box Foo { f: box 3 }; + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); let c1 = to_fn_mut(|| set(&mut *x.f)); let c2 = to_fn_mut(|| set(&mut *x.f)); //~^ ERROR cannot borrow `x` as mutable more than once diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.rs b/src/test/ui/borrowck/borrowck-closures-two-mut.rs index 5fe51654f3b79..cdff8f9e890c6 100644 --- a/src/test/ui/borrowck/borrowck-closures-two-mut.rs +++ b/src/test/ui/borrowck/borrowck-closures-two-mut.rs @@ -2,7 +2,7 @@ // access to the variable, whether that mutable access be used // for direct assignment or for taking mutable ref. Issue #6801. -#![feature(box_syntax)] + fn to_fn_mut(f: F) -> F { f } @@ -44,7 +44,7 @@ fn g() { f: Box } - let mut x: Box<_> = box Foo { f: box 3 }; + let mut x: Box<_> = Box::new(Foo { f: Box::new(3) }); let c1 = to_fn_mut(|| set(&mut *x.f)); let c2 = to_fn_mut(|| set(&mut *x.f)); //~^ ERROR cannot borrow `x` as mutable more than once diff --git a/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr b/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr index b8bbb31a3550f..0c5fd39b71871 100644 --- a/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr +++ b/src/test/ui/borrowck/borrowck-closures-unique-imm.stderr @@ -6,7 +6,7 @@ LL | let p = &this.x; LL | &mut this.x; | ^^^^^^^^^^^ mutable borrow occurs here LL | p.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-closures-use-after-free.rs b/src/test/ui/borrowck/borrowck-closures-use-after-free.rs index e9f65c4ff7df4..be5f1f873df52 100644 --- a/src/test/ui/borrowck/borrowck-closures-use-after-free.rs +++ b/src/test/ui/borrowck/borrowck-closures-use-after-free.rs @@ -2,8 +2,6 @@ // cannot also be supplied a borrowed version of that // variable's contents. Issue #11192. -#![feature(box_syntax)] - struct Foo { x: isize } @@ -14,10 +12,12 @@ impl Drop for Foo { } } + + fn main() { - let mut ptr: Box<_> = box Foo { x: 0 }; + let mut ptr: Box<_> = Box::new(Foo { x: 0 }); let mut test = |foo: &Foo| { - ptr = box Foo { x: ptr.x + 1 }; + ptr = Box::new(Foo { x: ptr.x + 1 }); }; test(&*ptr); //~ ERROR cannot borrow `*ptr` } diff --git a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr index a6dbcf36077a7..30900a3b6d96e 100644 --- a/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr +++ b/src/test/ui/borrowck/borrowck-closures-use-after-free.stderr @@ -3,7 +3,7 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as m | LL | let mut test = |foo: &Foo| { | ----------- mutable borrow occurs here -LL | ptr = box Foo { x: ptr.x + 1 }; +LL | ptr = Box::new(Foo { x: ptr.x + 1 }); | --- first borrow occurs due to use of `ptr` in closure LL | }; LL | test(&*ptr); diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr index 4b9c5a2a98ff6..f909dbc4082d6 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr @@ -41,7 +41,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 + | ----- borrow of `f` occurs here LL | f.x; | ^^^ use of borrowed `f` LL | drop(x); @@ -51,7 +51,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 + | ----- borrow of `g` occurs here LL | g.0; | ^^^ use of borrowed `g` LL | drop(x); @@ -71,7 +71,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 + | ----- borrow of `e` occurs here LL | match e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `e` @@ -93,7 +93,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 + | ----- borrow of `*f` occurs here LL | f.x; | ^^^ use of borrowed `*f` LL | drop(x); @@ -103,7 +103,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 + | ----- borrow of `*g` occurs here LL | g.0; | ^^^ use of borrowed `*g` LL | drop(x); @@ -123,7 +123,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 + | ----- borrow of `*e` occurs here LL | match *e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `*e` diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity-rpass.rs b/src/test/ui/borrowck/borrowck-field-sensitivity-rpass.rs index cb1ba90de891e..dd6708582c1b4 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity-rpass.rs +++ b/src/test/ui/borrowck/borrowck-field-sensitivity-rpass.rs @@ -3,89 +3,87 @@ #![allow(unused_variables)] // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - struct A { a: isize, b: Box } struct B { a: Box, b: Box } fn move_after_copy() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.a); drop(x.b); } fn move_after_fu_copy() { - let x = A { a: 1, b: box 2 }; - let _y = A { b: box 3, .. x }; + let x = A { a: 1, b: Box::new(2) }; + let _y = A { b: Box::new(3), .. x }; drop(x.b); } fn fu_move_after_copy() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.a); let _y = A { a: 3, .. x }; } fn fu_move_after_fu_copy() { - let x = A { a: 1, b: box 2 }; - let _y = A { b: box 3, .. x }; + let x = A { a: 1, b: Box::new(2) }; + let _y = A { b: Box::new(3), .. x }; let _z = A { a: 4, .. x }; } fn copy_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); drop(x.a); } fn copy_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let y = A { a: 3, .. x }; drop(x.a); } fn fu_copy_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); - let _y = A { b: box 3, .. x }; + let _y = A { b: Box::new(3), .. x }; } fn fu_copy_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - let _z = A { b: box 3, .. x }; + let _z = A { b: Box::new(3), .. x }; } fn borrow_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); let p = &x.a; drop(*p); } fn borrow_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; let p = &x.a; drop(*p); } fn move_after_borrow() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let p = &x.a; drop(x.b); drop(*p); } fn fu_move_after_borrow() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let p = &x.a; let _y = A { a: 3, .. x }; drop(*p); } fn mut_borrow_after_mut_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; let q = &mut x.b; drop(*p); @@ -93,134 +91,134 @@ fn mut_borrow_after_mut_borrow() { } fn move_after_move() { - let x = B { a: box 1, b: box 2 }; + let x = B { a: Box::new(1), b: Box::new(2) }; drop(x.a); drop(x.b); } fn move_after_fu_move() { - let x = B { a: box 1, b: box 2 }; - let y = B { a: box 3, .. x }; + let x = B { a: Box::new(1), b: Box::new(2) }; + let y = B { a: Box::new(3), .. x }; drop(x.a); } fn fu_move_after_move() { - let x = B { a: box 1, b: box 2 }; + let x = B { a: Box::new(1), b: Box::new(2) }; drop(x.a); - let z = B { a: box 3, .. x }; + let z = B { a: Box::new(3), .. x }; drop(z.b); } fn fu_move_after_fu_move() { - let x = B { a: box 1, b: box 2 }; - let _y = B { b: box 3, .. x }; - let _z = B { a: box 4, .. x }; + let x = B { a: Box::new(1), b: Box::new(2) }; + let _y = B { b: Box::new(3), .. x }; + let _z = B { a: Box::new(4), .. x }; } fn copy_after_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; drop(*x.b); } fn copy_after_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; drop(*x.b); } fn copy_after_field_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x.b = box 3; + x.b = Box::new(3); drop(*x.b); } fn copy_after_field_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x.b = box 3; + x.b = Box::new(3); drop(*x.b); } fn borrow_after_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; let p = &x.b; drop(**p); } fn borrow_after_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; let p = &x.b; drop(**p); } fn borrow_after_field_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x.b = box 3; + x.b = Box::new(3); let p = &x.b; drop(**p); } fn borrow_after_field_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x.b = box 3; + x.b = Box::new(3); let p = &x.b; drop(**p); } fn move_after_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = x.b; - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; drop(x.b); } fn move_after_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x = A { a: 3, b: box 4 }; + x = A { a: 3, b: Box::new(4) }; drop(x.b); } fn move_after_field_assign_after_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; drop(x.b); - x.b = box 3; + x.b = Box::new(3); drop(x.b); } fn move_after_field_assign_after_fu_move() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; - x.b = box 3; + x.b = Box::new(3); drop(x.b); } fn copy_after_assign_after_uninit() { let mut x: A; - x = A { a: 1, b: box 2 }; + x = A { a: 1, b: Box::new(2) }; drop(x.a); } fn borrow_after_assign_after_uninit() { let mut x: A; - x = A { a: 1, b: box 2 }; + x = A { a: 1, b: Box::new(2) }; let p = &x.a; drop(*p); } fn move_after_assign_after_uninit() { let mut x: A; - x = A { a: 1, b: box 2 }; + x = A { a: 1, b: Box::new(2) }; drop(x.b); } diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.rs b/src/test/ui/borrowck/borrowck-field-sensitivity.rs index ab607c2acbd4b..50edfb6ba2db1 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.rs +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.rs @@ -1,49 +1,49 @@ -#![feature(box_syntax)] - struct A { a: isize, b: Box } + + fn deref_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); drop(*x.b); //~ ERROR use of moved value: `x.b` } fn deref_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let y = A { a: 3, .. x }; drop(*x.b); //~ ERROR use of moved value: `x.b` } fn borrow_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); let p = &x.b; //~ ERROR borrow of moved value: `x.b` drop(**p); } fn borrow_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; let p = &x.b; //~ ERROR borrow of moved value: `x.b` drop(**p); } fn move_after_borrow() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let p = &x.b; drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed drop(**p); } fn fu_move_after_borrow() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let p = &x.b; let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed drop(**p); } fn mut_borrow_after_mut_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; let q = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time drop(*p); @@ -51,25 +51,25 @@ fn mut_borrow_after_mut_borrow() { } fn move_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); drop(x.b); //~ ERROR use of moved value: `x.b` } fn move_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; drop(x.b); //~ ERROR use of moved value: `x.b` } fn fu_move_after_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; drop(x.b); let _z = A { a: 3, .. x }; //~ ERROR use of moved value: `x.b` } fn fu_move_after_fu_move() { - let x = A { a: 1, b: box 2 }; + let x = A { a: 1, b: Box::new(2) }; let _y = A { a: 3, .. x }; let _z = A { a: 4, .. x }; //~ ERROR use of moved value: `x.b` } @@ -91,7 +91,7 @@ fn borrow_after_field_assign_after_uninit() { fn move_after_field_assign_after_uninit() { let mut x: A; - x.b = box 1; //~ ERROR assign to part of possibly-uninitialized variable: `x` + x.b = Box::new(1); //~ ERROR assign to part of possibly-uninitialized variable: `x` drop(x.b); } diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr index f1601336fca9b..bb4d2f06016b9 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr @@ -123,7 +123,7 @@ LL | x.a = 1; error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/borrowck-field-sensitivity.rs:94:5 | -LL | x.b = box 1; +LL | x.b = Box::new(1); | ^^^ use of possibly-uninitialized `x` error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs b/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs index de75368578d9f..389b8a43c0551 100644 --- a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs +++ b/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs @@ -1,6 +1,6 @@ // Issue #16205. -#![feature(box_syntax)] + struct Foo { a: [Box; 3], @@ -13,12 +13,12 @@ fn main() { } let f = Foo { - a: [box 3, box 4, box 5], + a: [Box::new(3), Box::new(4), Box::new(5)], }; for &a in &f.a { //~ ERROR cannot move out } - let x: Option> = Some(box 1); + let x: Option> = Some(Box::new(1)); for &a in x.iter() { //~ ERROR cannot move out } } diff --git a/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr b/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr deleted file mode 100644 index 3468f29fb1a23..0000000000000 --- a/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-for-loop-head-linkage.rs:7:9 - | -LL | for &x in &vector { - | ------- - | | - | immutable borrow occurs here - | immutable borrow later used here -LL | let cap = vector.capacity(); -LL | vector.extend(repeat(0)); - | ^^^^^^ mutable borrow occurs here - -error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-for-loop-head-linkage.rs:8:9 - | -LL | for &x in &vector { - | ------- - | | - | immutable borrow occurs here - | immutable borrow later used here -... -LL | vector[1] = 5; - | ^^^^^^ mutable borrow occurs here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-insert-during-each.stderr b/src/test/ui/borrowck/borrowck-insert-during-each.stderr index a1ac45795fae2..99d08e905d5fd 100644 --- a/src/test/ui/borrowck/borrowck-insert-during-each.stderr +++ b/src/test/ui/borrowck/borrowck-insert-during-each.stderr @@ -16,15 +16,17 @@ LL | | }) error[E0500]: closure requires unique access to `f` but it is already borrowed --> $DIR/borrowck-insert-during-each.rs:18:9 | -LL | f.foo( - | - --- first borrow later used by call - | | - | borrow occurs here -LL | -LL | |a| { - | ^^^ closure construction occurs here -LL | f.n.insert(*a); - | --- second borrow occurs due to use of `f` in closure +LL | f.foo( + | - --- first borrow later used by call + | _____| + | | +LL | | +LL | | |a| { + | | ^^^ closure construction occurs here +LL | | f.n.insert(*a); + | | --- second borrow occurs due to use of `f` in closure +LL | | }) + | |__________- borrow occurs here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-issue-14498.rs b/src/test/ui/borrowck/borrowck-issue-14498.rs index e8c9019264fe7..003533a51844d 100644 --- a/src/test/ui/borrowck/borrowck-issue-14498.rs +++ b/src/test/ui/borrowck/borrowck-issue-14498.rs @@ -4,14 +4,14 @@ // Also includes tests of the errors reported when the Box in question // is immutable (#14270). -#![feature(box_syntax)] + struct A { a: isize } struct B<'a> { a: Box<&'a mut isize> } fn indirect_write_to_imm_box() { let mut x: isize = 1; - let y: Box<_> = box &mut x; + let y: Box<_> = Box::new(&mut x); let p = &y; ***p = 2; //~ ERROR cannot assign to `***p` drop(p); @@ -19,7 +19,7 @@ fn indirect_write_to_imm_box() { fn borrow_in_var_from_var() { let mut x: isize = 1; - let mut y: Box<_> = box &mut x; + let mut y: Box<_> = Box::new(&mut x); let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed @@ -29,7 +29,7 @@ fn borrow_in_var_from_var() { fn borrow_in_var_from_var_via_imm_box() { let mut x: isize = 1; - let y: Box<_> = box &mut x; + let y: Box<_> = Box::new(&mut x); let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed @@ -39,7 +39,7 @@ fn borrow_in_var_from_var_via_imm_box() { fn borrow_in_var_from_field() { let mut x = A { a: 1 }; - let mut y: Box<_> = box &mut x.a; + let mut y: Box<_> = Box::new(&mut x.a); let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed @@ -49,7 +49,7 @@ fn borrow_in_var_from_field() { fn borrow_in_var_from_field_via_imm_box() { let mut x = A { a: 1 }; - let y: Box<_> = box &mut x.a; + let y: Box<_> = Box::new(&mut x.a); let p = &y; let q = &***p; **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed @@ -59,7 +59,7 @@ fn borrow_in_var_from_field_via_imm_box() { fn borrow_in_field_from_var() { let mut x: isize = 1; - let mut y = B { a: box &mut x }; + let mut y = B { a: Box::new(&mut x) }; let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed @@ -69,7 +69,7 @@ fn borrow_in_field_from_var() { fn borrow_in_field_from_var_via_imm_box() { let mut x: isize = 1; - let y = B { a: box &mut x }; + let y = B { a: Box::new(&mut x) }; let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed @@ -79,7 +79,7 @@ fn borrow_in_field_from_var_via_imm_box() { fn borrow_in_field_from_field() { let mut x = A { a: 1 }; - let mut y = B { a: box &mut x.a }; + let mut y = B { a: Box::new(&mut x.a) }; let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed @@ -89,7 +89,7 @@ fn borrow_in_field_from_field() { fn borrow_in_field_from_field_via_imm_box() { let mut x = A { a: 1 }; - let y = B { a: box &mut x.a }; + let y = B { a: Box::new(&mut x.a) }; let p = &y.a; let q = &***p; **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed diff --git a/src/test/ui/borrowck/borrowck-issue-2657-1.rs b/src/test/ui/borrowck/borrowck-issue-2657-1.rs index c38293740edaa..0fb2267b982ea 100644 --- a/src/test/ui/borrowck/borrowck-issue-2657-1.rs +++ b/src/test/ui/borrowck/borrowck-issue-2657-1.rs @@ -1,9 +1,9 @@ -#![feature(box_syntax)] - +trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } +impl Fake for T { } fn main() { - let x: Option> = Some(box 1); + let x: Option> = Some(Box::new(1)); match x { Some(ref _y) => { let _a = x; //~ ERROR cannot move @@ -12,6 +12,3 @@ fn main() { _ => {} } } - -trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } -impl Fake for T { } diff --git a/src/test/ui/borrowck/borrowck-issue-2657-1.stderr b/src/test/ui/borrowck/borrowck-issue-2657-1.stderr index 4ea4eb8f00759..390bb9384f8ae 100644 --- a/src/test/ui/borrowck/borrowck-issue-2657-1.stderr +++ b/src/test/ui/borrowck/borrowck-issue-2657-1.stderr @@ -6,7 +6,7 @@ LL | Some(ref _y) => { LL | let _a = x; | ^ move out of `x` occurs here LL | _y.use_ref(); - | -- borrow later used here + | ------------ borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-issue-2657-2.rs b/src/test/ui/borrowck/borrowck-issue-2657-2.rs index cea5611048744..7dbac02154a6e 100644 --- a/src/test/ui/borrowck/borrowck-issue-2657-2.rs +++ b/src/test/ui/borrowck/borrowck-issue-2657-2.rs @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - fn main() { - let x: Option> = Some(box 1); + + let x: Option> = Some(Box::new(1)); + match x { Some(ref y) => { let _b = *y; //~ ERROR cannot move out diff --git a/src/test/ui/borrowck/borrowck-lend-flow-if.rs b/src/test/ui/borrowck/borrowck-lend-flow-if.rs index 1150346f752fa..19a0dd0c6b17b 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow-if.rs +++ b/src/test/ui/borrowck/borrowck-lend-flow-if.rs @@ -4,7 +4,7 @@ // either genuine or would require more advanced changes. The latter // cases are noted. -#![feature(box_syntax)] + fn borrow(_v: &isize) {} fn borrow_mut(_v: &mut isize) {} @@ -13,15 +13,15 @@ fn for_func(_f: F) where F: FnOnce() -> bool { panic!() } fn produce() -> T { panic!(); } fn inc(v: &mut Box) { - *v = box (**v + 1); + *v = Box::new(**v + 1); } fn pre_freeze_cond() { // In this instance, the freeze is conditional and starts before // the mut borrow. - let u = box 0; - let mut v: Box<_> = box 3; + let u = Box::new(0); + let mut v: Box<_> = Box::new(3); let mut _w = &u; if cond() { _w = &v; @@ -34,8 +34,8 @@ fn pre_freeze_else() { // In this instance, the freeze and mut borrow are on separate sides // of the if. - let u = box 0; - let mut v: Box<_> = box 3; + let u = Box::new(0); + let mut v: Box<_> = Box::new(3); let mut _w = &u; if cond() { _w = &v; diff --git a/src/test/ui/borrowck/borrowck-lend-flow-if.stderr b/src/test/ui/borrowck/borrowck-lend-flow-if.stderr index 68a82bdb57c55..e47efc0e0b346 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow-if.stderr +++ b/src/test/ui/borrowck/borrowck-lend-flow-if.stderr @@ -7,7 +7,7 @@ LL | } LL | borrow_mut(&mut *v); | ^^^^^^^ mutable borrow occurs here LL | _w.use_ref(); - | -- immutable borrow later used here + | ------------ immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-lend-flow-loop.rs b/src/test/ui/borrowck/borrowck-lend-flow-loop.rs index b650df91ca23c..548ffbd515e98 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow-loop.rs +++ b/src/test/ui/borrowck/borrowck-lend-flow-loop.rs @@ -1,18 +1,18 @@ -#![feature(box_syntax)] - fn borrow(_v: &isize) {} fn borrow_mut(_v: &mut isize) {} fn cond() -> bool { panic!() } fn produce() -> T { panic!(); } + fn inc(v: &mut Box) { - *v = box (**v + 1); + *v = Box::new(**v + 1); } + fn loop_overarching_alias_mut() { // In this instance, the borrow ends on the line before the loop - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let mut x = &mut v; **x += 1; loop { @@ -23,18 +23,18 @@ fn loop_overarching_alias_mut() { fn block_overarching_alias_mut() { // In this instance, the borrow encompasses the entire closure call. - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let mut x = &mut v; for _ in 0..3 { borrow(&*v); //~ ERROR cannot borrow } - *x = box 5; + *x = Box::new(5); } fn loop_aliased_mut() { // In this instance, the borrow ends right after each assignment to _x - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut _x = &w; loop { borrow_mut(&mut *v); // OK @@ -45,8 +45,8 @@ fn loop_aliased_mut() { fn while_aliased_mut() { // In this instance, the borrow ends right after each assignment to _x - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut _x = &w; while cond() { borrow_mut(&mut *v); // OK @@ -58,8 +58,8 @@ fn while_aliased_mut() { fn loop_aliased_mut_break() { // In this instance, the borrow ends right after each assignment to _x - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut _x = &w; loop { borrow_mut(&mut *v); @@ -72,8 +72,8 @@ fn loop_aliased_mut_break() { fn while_aliased_mut_break() { // In this instance, the borrow ends right after each assignment to _x - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut _x = &w; while cond() { borrow_mut(&mut *v); @@ -84,8 +84,8 @@ fn while_aliased_mut_break() { } fn while_aliased_mut_cond(cond: bool, cond2: bool) { - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut x = &mut w; while cond { **x += 1; diff --git a/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr b/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr index f02c357f48b4c..df7c86b85623e 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr +++ b/src/test/ui/borrowck/borrowck-lend-flow-loop.stderr @@ -7,7 +7,7 @@ LL | for _ in 0..3 { LL | borrow(&*v); | ^^^ immutable borrow occurs here LL | } -LL | *x = box 5; +LL | *x = Box::new(5); | -- mutable borrow later used here error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable diff --git a/src/test/ui/borrowck/borrowck-lend-flow.rs b/src/test/ui/borrowck/borrowck-lend-flow.rs index 0eb62ede5d65a..564c57044a37e 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow.rs +++ b/src/test/ui/borrowck/borrowck-lend-flow.rs @@ -4,7 +4,7 @@ // either genuine or would require more advanced changes. The latter // cases are noted. -#![feature(box_syntax)] + fn borrow(_v: &isize) {} fn borrow_mut(_v: &mut isize) {} @@ -13,13 +13,13 @@ fn for_func(_f: F) where F: FnOnce() -> bool { panic!() } fn produce() -> T { panic!(); } fn inc(v: &mut Box) { - *v = box (**v + 1); + *v = Box::new(**v + 1); } fn pre_freeze() { // In this instance, the freeze starts before the mut borrow. - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let _w = &v; borrow_mut(&mut *v); //~ ERROR cannot borrow _w.use_ref(); @@ -28,7 +28,7 @@ fn pre_freeze() { fn post_freeze() { // In this instance, the const alias starts after the borrow. - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); borrow_mut(&mut *v); let _w = &v; } diff --git a/src/test/ui/borrowck/borrowck-lend-flow.stderr b/src/test/ui/borrowck/borrowck-lend-flow.stderr index 07b11b3e72828..40c14f54cb881 100644 --- a/src/test/ui/borrowck/borrowck-lend-flow.stderr +++ b/src/test/ui/borrowck/borrowck-lend-flow.stderr @@ -6,7 +6,7 @@ LL | let _w = &v; LL | borrow_mut(&mut *v); | ^^^^^^^ mutable borrow occurs here LL | _w.use_ref(); - | -- immutable borrow later used here + | ------------ immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs index 9fa46563fdf80..e536d40409927 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs +++ b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - use std::thread; @@ -8,8 +6,10 @@ fn borrow(v: &isize, f: F) where F: FnOnce(&isize) { f(v); } + + fn box_imm() { - let v: Box<_> = box 3; + let v: Box<_> = Box::new(3); let w = &v; thread::spawn(move|| { //~^ ERROR cannot move out of `v` because it is borrowed @@ -19,7 +19,7 @@ fn box_imm() { } fn box_imm_explicit() { - let v: Box<_> = box 3; + let v: Box<_> = Box::new(3); let w = &v; thread::spawn(move|| { //~^ ERROR cannot move diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr index ac25502ad053c..3548da35b6139 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr +++ b/src/test/ui/borrowck/borrowck-loan-blocks-move-cc.stderr @@ -10,7 +10,7 @@ LL | println!("v={}", *v); | -- move occurs due to use in closure LL | }); LL | w.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0505]: cannot move out of `v` because it is borrowed --> $DIR/borrowck-loan-blocks-move-cc.rs:24:19 @@ -24,7 +24,7 @@ LL | println!("v={}", *v); | -- move occurs due to use in closure LL | }); LL | w.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move.rs b/src/test/ui/borrowck/borrowck-loan-blocks-move.rs index bde73219f70ed..f3f443721b5ec 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move.rs +++ b/src/test/ui/borrowck/borrowck-loan-blocks-move.rs @@ -1,12 +1,12 @@ -#![feature(box_syntax)] +fn take(_v: Box) { +} + -fn take(_v: Box) { -} fn box_imm() { - let v = box 3; + let v = Box::new(3); let w = &v; take(v); //~ ERROR cannot move out of `v` because it is borrowed w.use_ref(); diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr index 615660febbce2..b5c6b101f765c 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr +++ b/src/test/ui/borrowck/borrowck-loan-blocks-move.stderr @@ -6,7 +6,7 @@ LL | let w = &v; LL | take(v); | ^ move out of `v` occurs here LL | w.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs b/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs index da30bfa29bbf7..33d6af303102a 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs +++ b/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs @@ -1,14 +1,14 @@ -#![feature(box_syntax)] - fn borrow(v: &isize, f: F) where F: FnOnce(&isize) { f(v); } + + fn box_imm() { - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); borrow(&*v, |w| { //~ ERROR cannot borrow `v` as mutable - v = box 4; + v = Box::new(4); assert_eq!(*v, 3); assert_eq!(*w, 4); }) diff --git a/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr b/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr index 1d1522a15b1ed..fa5308c290390 100644 --- a/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr +++ b/src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr @@ -7,7 +7,7 @@ LL | borrow(&*v, | immutable borrow later used by call LL | |w| { | ^^^ mutable borrow occurs here -LL | v = box 4; +LL | v = Box::new(4); | - second borrow occurs due to use of `v` in closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs index 1baa94edfbe58..b8f1650fcdc59 100644 --- a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs +++ b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs @@ -1,5 +1,5 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + use std::ops::Add; @@ -12,12 +12,12 @@ impl Add for Foo { fn add(self, f: Foo) -> Foo { let Foo(box i) = self; let Foo(box j) = f; - Foo(box (i + j)) + Foo(Box::new(i + j)) } } fn main() { - let x = Foo(box 3); + let x = Foo(Box::new(3)); let _y = {x} + x.clone(); // the `{x}` forces a move to occur //~^ ERROR borrow of moved value: `x` } diff --git a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr index 095ae7f56b22e..0dd720ff6ce04 100644 --- a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr +++ b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr @@ -1,10 +1,10 @@ error[E0382]: borrow of moved value: `x` --> $DIR/borrowck-loan-in-overloaded-op.rs:21:20 | -LL | let x = Foo(box 3); +LL | let x = Foo(Box::new(3)); | - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait LL | let _y = {x} + x.clone(); // the `{x}` forces a move to occur - | - ^ value borrowed here after move + | - ^^^^^^^^^ value borrowed here after move | | | value moved here diff --git a/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr b/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr index aa874c34a22ed..1d8d04c9181c2 100644 --- a/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr +++ b/src/test/ui/borrowck/borrowck-loan-rcvr-overloaded-op.stderr @@ -17,7 +17,7 @@ LL | let q = &mut p; | ------ mutable borrow occurs here ... LL | p.times(3); - | ^ immutable borrow occurs here + | ^^^^^^^^^^ immutable borrow occurs here LL | LL | *q + 3; // OK to use the new alias `q` | -- mutable borrow later used here diff --git a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr index 489ec7d04ed1d..74cad575d276a 100644 --- a/src/test/ui/borrowck/borrowck-loan-rcvr.stderr +++ b/src/test/ui/borrowck/borrowck-loan-rcvr.stderr @@ -1,13 +1,15 @@ error[E0502]: cannot borrow `p` as mutable because it is also borrowed as immutable --> $DIR/borrowck-loan-rcvr.rs:23:14 | -LL | p.blockm(|| { - | - ------ ^^ mutable borrow occurs here - | | | - | | immutable borrow later used by call - | immutable borrow occurs here -LL | p.x = 10; - | --- second borrow occurs due to use of `p` in closure +LL | p.blockm(|| { + | - ------ ^^ mutable borrow occurs here + | | | + | _____| immutable borrow later used by call + | | +LL | | p.x = 10; + | | --- second borrow occurs due to use of `p` in closure +LL | | }) + | |______- immutable borrow occurs here error[E0502]: cannot borrow `p` as immutable because it is also borrowed as mutable --> $DIR/borrowck-loan-rcvr.rs:34:5 @@ -15,7 +17,7 @@ error[E0502]: cannot borrow `p` as immutable because it is also borrowed as muta LL | let l = &mut p; | ------ mutable borrow occurs here LL | p.impurem(); - | ^ immutable borrow occurs here + | ^^^^^^^^^^^ immutable borrow occurs here LL | LL | l.x += 1; | -------- mutable borrow later used here diff --git a/src/test/ui/borrowck/borrowck-macro-interaction-issue-6304.rs b/src/test/ui/borrowck/borrowck-macro-interaction-issue-6304.rs index 628e49f574cf2..4e969f6ed83d3 100644 --- a/src/test/ui/borrowck/borrowck-macro-interaction-issue-6304.rs +++ b/src/test/ui/borrowck/borrowck-macro-interaction-issue-6304.rs @@ -6,9 +6,7 @@ // Check that we do not ICE when compiling this // macro, which reuses the expression `$id` - #![feature(box_patterns)] -#![feature(box_syntax)] struct Foo { a: isize @@ -23,7 +21,7 @@ impl Foo { macro_rules! declare { ($id:expr, $rest:expr) => ({ self.check_id($id); - box Bar::Bar2($id, $rest) + Box::new(Bar::Bar2($id, $rest)) }) } match s { diff --git a/src/test/ui/borrowck/borrowck-move-by-capture-ok.rs b/src/test/ui/borrowck/borrowck-move-by-capture-ok.rs index 98e4b881893cb..e7a48ebf6ca9b 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture-ok.rs +++ b/src/test/ui/borrowck/borrowck-move-by-capture-ok.rs @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let bar: Box<_> = box 3; + let bar: Box<_> = Box::new(3); let h = || -> isize { *bar }; assert_eq!(h(), 3); } diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.rs b/src/test/ui/borrowck/borrowck-move-by-capture.rs index a825ed5e89acd..f26edef17f349 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.rs +++ b/src/test/ui/borrowck/borrowck-move-by-capture.rs @@ -1,10 +1,10 @@ -#![feature(box_syntax,unboxed_closures)] +#![feature(unboxed_closures)] fn to_fn_mut>(f: F) -> F { f } fn to_fn_once>(f: F) -> F { f } pub fn main() { - let bar: Box<_> = box 3; + let bar: Box<_> = Box::new(3); let _g = to_fn_mut(|| { let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of }); diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr index 05489cf18e7fc..257ec3fbb7fa2 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr @@ -1,7 +1,7 @@ error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure --> $DIR/borrowck-move-by-capture.rs:9:29 | -LL | let bar: Box<_> = box 3; +LL | let bar: Box<_> = Box::new(3); | --- captured outer variable LL | let _g = to_fn_mut(|| { | ________________________- diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.rs b/src/test/ui/borrowck/borrowck-move-error-with-note.rs index 7ef59f50c0332..ef38cbb63a5e3 100644 --- a/src/test/ui/borrowck/borrowck-move-error-with-note.rs +++ b/src/test/ui/borrowck/borrowck-move-error-with-note.rs @@ -1,14 +1,14 @@ -#![feature(box_syntax)] - enum Foo { Foo1(Box, Box), Foo2(Box), Foo3, } + + fn blah() { - let f = &Foo::Foo1(box 1, box 2); - match *f { //~ ERROR cannot move out of + let f = &Foo::Foo1(Box::new(1), Box::new(2)); + match *f { //~ ERROR cannot move out of Foo::Foo1(num1, num2) => (), Foo::Foo2(num) => (), @@ -42,8 +42,8 @@ struct A { fn free(_: T) {} fn blah2() { - let a = &A { a: box 1 }; - match a.a { //~ ERROR cannot move out of + let a = &A { a: Box::new(1) }; + match a.a { //~ ERROR cannot move out of n => { free(n) } diff --git a/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs b/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs index e058c80651679..71405f7a7329d 100644 --- a/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs +++ b/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs @@ -3,10 +3,10 @@ -#![feature(box_syntax)] + fn main() { - let a: Box> = box box 2; + let a: Box> = Box::new(Box::new(2)); let b = &a; let z = *a; //~ ERROR: cannot move out of `*a` because it is borrowed diff --git a/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr b/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr index e4840fba67299..b305e3c0a163a 100644 --- a/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr +++ b/src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.stderr @@ -7,7 +7,7 @@ LL | LL | let z = *a; | ^^ move out of `*a` occurs here LL | b.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs index 233d0a733e316..72e7b5a716273 100644 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs +++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs @@ -1,11 +1,11 @@ -#![feature(box_syntax)] - fn call_f isize>(f: F) -> isize { f() } + + fn main() { - let t: Box<_> = box 3; + let t: Box<_> = Box::new(3); call_f(move|| { *t + 1 }); call_f(move|| { *t + 1 }); //~ ERROR use of moved value diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr index 1ac4999e6e11d..edd597fe30bd2 100644 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr +++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `t` --> $DIR/borrowck-move-moved-value-into-closure.rs:11:12 | -LL | let t: Box<_> = box 3; +LL | let t: Box<_> = Box::new(3); | - move occurs because `t` has type `Box`, which does not implement the `Copy` trait LL | LL | call_f(move|| { *t + 1 }); diff --git a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr b/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr index 77f5b72e51c5d..d5ff0c501c4bd 100644 --- a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-move-mut-base-ptr.stderr @@ -7,7 +7,7 @@ LL | let t1 = t0; | ^^ move out of `t0` occurs here LL | *t1 = 22; LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr index 0a29d2bb1d54e..7974506507097 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of an `Rc` --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14 | LL | let _x = Rc::new(vec![1, 2]).into_iter(); - | ^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-subcomponent.rs b/src/test/ui/borrowck/borrowck-move-subcomponent.rs index 4185632c4e291..38abd19322215 100644 --- a/src/test/ui/borrowck/borrowck-move-subcomponent.rs +++ b/src/test/ui/borrowck/borrowck-move-subcomponent.rs @@ -1,7 +1,7 @@ // Tests that the borrow checker checks all components of a path when moving // out. -#![feature(box_syntax)] + struct S { x : Box @@ -10,7 +10,7 @@ struct S { fn f(_: T) {} fn main() { - let a : S = S { x : box 1 }; + let a : S = S { x : Box::new(1) }; let pb = &a; let S { x: ax } = a; //~ ERROR cannot move out f(pb); diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.rs b/src/test/ui/borrowck/borrowck-multiple-captures.rs index 9f09f8442c044..57b3819ac5113 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.rs +++ b/src/test/ui/borrowck/borrowck-multiple-captures.rs @@ -1,13 +1,13 @@ -#![feature(box_syntax)] - use std::thread; + fn borrow(_: &T) { } + fn different_vars_after_borrows() { - let x1: Box<_> = box 1; + let x1: Box<_> = Box::new(1); let p1 = &x1; - let x2: Box<_> = box 2; + let x2: Box<_> = Box::new(2); let p2 = &x2; thread::spawn(move|| { //~^ ERROR cannot move out of `x1` because it is borrowed @@ -20,9 +20,9 @@ fn different_vars_after_borrows() { } fn different_vars_after_moves() { - let x1: Box<_> = box 1; + let x1: Box<_> = Box::new(1); drop(x1); - let x2: Box<_> = box 2; + let x2: Box<_> = Box::new(2); drop(x2); thread::spawn(move|| { //~^ ERROR use of moved value: `x1` @@ -33,7 +33,7 @@ fn different_vars_after_moves() { } fn same_var_after_borrow() { - let x: Box<_> = box 1; + let x: Box<_> = Box::new(1); let p = &x; thread::spawn(move|| { //~^ ERROR cannot move out of `x` because it is borrowed @@ -44,7 +44,7 @@ fn same_var_after_borrow() { } fn same_var_after_move() { - let x: Box<_> = box 1; + let x: Box<_> = Box::new(1); drop(x); thread::spawn(move|| { //~^ ERROR use of moved value: `x` diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.stderr index e159878619a0b..86d2955e2364f 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.stderr +++ b/src/test/ui/borrowck/borrowck-multiple-captures.stderr @@ -30,7 +30,7 @@ LL | borrow(&*p2); error[E0382]: use of moved value: `x1` --> $DIR/borrowck-multiple-captures.rs:27:19 | -LL | let x1: Box<_> = box 1; +LL | let x1: Box<_> = Box::new(1); | -- move occurs because `x1` has type `Box`, which does not implement the `Copy` trait LL | drop(x1); | -- value moved here @@ -44,7 +44,7 @@ LL | drop(x1); error[E0382]: use of moved value: `x2` --> $DIR/borrowck-multiple-captures.rs:27:19 | -LL | let x2: Box<_> = box 2; +LL | let x2: Box<_> = Box::new(2); | -- move occurs because `x2` has type `Box`, which does not implement the `Copy` trait LL | drop(x2); | -- value moved here @@ -91,7 +91,7 @@ LL | drop(x); error[E0382]: use of moved value: `x` --> $DIR/borrowck-multiple-captures.rs:49:19 | -LL | let x: Box<_> = box 1; +LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | drop(x); | - value moved here diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr index a409077793902..15ac737606d66 100644 --- a/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr +++ b/src/test/ui/borrowck/borrowck-mut-borrow-linear-errors.stderr @@ -5,8 +5,9 @@ LL | 1 => { addr.push(&mut x); } | ^^^^^^ second mutable borrow occurs here LL | 2 => { addr.push(&mut x); } LL | _ => { addr.push(&mut x); } - | ---- ------ first mutable borrow occurs here - | | + | ----------------- + | | | + | | first mutable borrow occurs here | first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time @@ -15,8 +16,9 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time LL | 2 => { addr.push(&mut x); } | ^^^^^^ second mutable borrow occurs here LL | _ => { addr.push(&mut x); } - | ---- ------ first mutable borrow occurs here - | | + | ----------------- + | | | + | | first mutable borrow occurs here | first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr b/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr index f2baee09376e2..ef811b849052a 100644 --- a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.stderr @@ -7,7 +7,7 @@ LL | let mut t2 = &mut t0; | ^^^^^^^ mutable borrow occurs here LL | **t2 += 1; // Mutates `*t0` LL | p.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0499]: cannot borrow `t0` as mutable more than once at a time --> $DIR/borrowck-mut-borrow-of-mut-base-ptr.rs:19:18 @@ -18,7 +18,7 @@ LL | let mut t2 = &mut t0; | ^^^^^^^ second mutable borrow occurs here LL | **t2 += 1; // Mutates `*t0` but not through `*p` LL | p.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-mut-uniq.rs b/src/test/ui/borrowck/borrowck-mut-uniq.rs index 80b3484e0fb23..255b4995b640d 100644 --- a/src/test/ui/borrowck/borrowck-mut-uniq.rs +++ b/src/test/ui/borrowck/borrowck-mut-uniq.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] use std::mem::swap; @@ -20,7 +19,7 @@ fn iter_ints(x: &Ints, mut f: F) -> bool where F: FnMut(&isize) -> bool { } pub fn main() { - let mut ints: Box<_> = box Ints {sum: box 0, values: Vec::new()}; + let mut ints: Box<_> = Box::new(Ints {sum: Box::new(0), values: Vec::new()}); add_int(&mut *ints, 22); add_int(&mut *ints, 44); diff --git a/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs b/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs index 4c1ff98ce6ec2..f035049d82d8d 100644 --- a/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs +++ b/src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - struct Node_ { a: Box } @@ -8,8 +6,10 @@ enum Cycle { Node(Node_), Empty, } + fn main() { - let mut x: Box<_> = box Cycle::Node(Node_ {a: box Cycle::Empty}); + let mut x: Box<_> = Box::new(Cycle::Node(Node_ {a: Box::new(Cycle::Empty)})); + // Create a cycle! match *x { Cycle::Node(ref mut y) => { diff --git a/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr b/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr deleted file mode 100644 index 49c3f861ea993..0000000000000 --- a/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-object-lifetime.rs:20:13 - | -LL | let y = x.borrowed(); - | - immutable borrow occurs here -LL | let z = x.mut_borrowed(); - | ^ mutable borrow occurs here -LL | y.use_ref(); - | - immutable borrow later used here - -error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-object-lifetime.rs:26:13 - | -LL | let y = x.borrowed(); - | - immutable borrow occurs here -LL | let z = &mut x; - | ^^^^^^ mutable borrow occurs here -LL | y.use_ref(); - | - immutable borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/borrowck-object-lifetime.stderr b/src/test/ui/borrowck/borrowck-object-lifetime.stderr index cf94c74dec222..215ed760ae1eb 100644 --- a/src/test/ui/borrowck/borrowck-object-lifetime.stderr +++ b/src/test/ui/borrowck/borrowck-object-lifetime.stderr @@ -2,21 +2,21 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut --> $DIR/borrowck-object-lifetime.rs:20:13 | LL | let y = x.borrowed(); - | - immutable borrow occurs here + | ------------ immutable borrow occurs here LL | let z = x.mut_borrowed(); | ^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/borrowck-object-lifetime.rs:26:13 | LL | let y = x.borrowed(); - | - immutable borrow occurs here + | ------------ immutable borrow occurs here LL | let z = &mut x; | ^^^^^^ mutable borrow occurs here LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr index 978e1291722a3..087f2ac799eeb 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-autoderef.stderr @@ -6,7 +6,7 @@ LL | let p = &mut f[&s]; LL | let q = &f[&s]; | ^ immutable borrow occurs here LL | p.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/borrowck-overloaded-index-autoderef.rs:43:18 @@ -16,7 +16,7 @@ LL | let p = &mut f[&s]; LL | let q = &mut f[&s]; | ^ second mutable borrow occurs here LL | p.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error[E0499]: cannot borrow `f.foo` as mutable more than once at a time --> $DIR/borrowck-overloaded-index-autoderef.rs:53:18 @@ -26,7 +26,7 @@ LL | let p = &mut f.foo[&s]; LL | let q = &mut f.foo[&s]; | ^^^^^ second mutable borrow occurs here LL | p.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error[E0502]: cannot borrow `f.foo` as mutable because it is also borrowed as immutable --> $DIR/borrowck-overloaded-index-autoderef.rs:65:18 @@ -36,7 +36,7 @@ LL | let p = &f.foo[&s]; LL | let q = &mut f.foo[&s]; | ^^^^^ mutable borrow occurs here LL | p.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0506]: cannot assign to `f.foo` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:71:5 @@ -46,7 +46,7 @@ LL | let p = &f.foo[&s]; LL | f.foo = g; | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `*f` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:77:5 @@ -56,7 +56,7 @@ LL | let p = &f.foo[&s]; LL | *f = g; | ^^^^^^ assignment to borrowed `*f` occurs here LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `f.foo` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:83:5 @@ -66,7 +66,7 @@ LL | let p = &mut f.foo[&s]; LL | f.foo = g; | ^^^^^^^^^ assignment to borrowed `f.foo` occurs here LL | p.use_mut(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `*f` because it is borrowed --> $DIR/borrowck-overloaded-index-autoderef.rs:89:5 @@ -76,7 +76,7 @@ LL | let p = &mut f.foo[&s]; LL | *f = g; | ^^^^^^ assignment to borrowed `*f` occurs here LL | p.use_mut(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to 8 previous errors diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs index ddf6354c97341..344d75cc58f02 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - use std::ops::Index; struct MyVec { @@ -14,8 +12,10 @@ impl Index for MyVec { } } + + fn main() { - let v = MyVec::> { data: vec![box 1, box 2, box 3] }; + let v = MyVec::> { data: vec![Box::new(1), Box::new(2), Box::new(3)] }; let good = &v[0]; // Shouldn't fail here let bad = v[0]; //~^ ERROR cannot move out of index of `MyVec>` diff --git a/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr b/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr index db73d4c04acc8..d05996413dd41 100644 --- a/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr +++ b/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.stderr @@ -8,7 +8,7 @@ LL | let z = &x; | ^^ immutable borrow occurs here ... LL | y.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/borrowck-report-with-custom-diagnostic.rs:21:21 @@ -20,7 +20,7 @@ LL | let z = &mut x; | ^^^^^^ mutable borrow occurs here ... LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/borrowck-report-with-custom-diagnostic.rs:36:17 @@ -32,7 +32,7 @@ LL | let z = &mut x; | ^^^^^^ second mutable borrow occurs here ... LL | y.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr b/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr index 1c55953c91fb7..b39215b9aab5f 100644 --- a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.stderr @@ -7,7 +7,7 @@ LL | swap(&mut t0, &mut t1); | ^^^^^^^ mutable borrow occurs here LL | *t1 = 22; LL | p.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr b/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr index 61569b9cac106..4bd7d54cffeda 100644 --- a/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr +++ b/src/test/ui/borrowck/borrowck-union-borrow-nested.stderr @@ -6,7 +6,7 @@ LL | let ra = &mut u.s.a; LL | let b = u.c; | ^^^ use of borrowed `u.s.a` LL | ra.use_mut(); - | -- borrow later used here + | ------------ borrow later used here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-uniq-via-lend.rs b/src/test/ui/borrowck/borrowck-uniq-via-lend.rs index f62880788edb7..25d3e0b548646 100644 --- a/src/test/ui/borrowck/borrowck-uniq-via-lend.rs +++ b/src/test/ui/borrowck/borrowck-uniq-via-lend.rs @@ -1,17 +1,17 @@ -#![feature(box_syntax)] +fn borrow(_v: &isize) {} + -fn borrow(_v: &isize) {} fn local() { - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); borrow(&*v); } fn local_rec() { struct F { f: Box } - let mut v = F {f: box 3}; + let mut v = F {f: Box::new(3)}; borrow(&*v.f); } @@ -19,35 +19,35 @@ fn local_recs() { struct F { f: G } struct G { g: H } struct H { h: Box } - let mut v = F {f: G {g: H {h: box 3}}}; + let mut v = F {f: G {g: H {h: Box::new(3)}}}; borrow(&*v.f.g.h); } fn aliased_imm() { - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let w = &v; borrow(&*v); w.use_ref(); } fn aliased_mut() { - let mut v: Box<_> = box 3; + let mut v: Box<_> = Box::new(3); let w = &mut v; borrow(&*v); //~ ERROR cannot borrow `*v` w.use_mut(); } fn aliased_other() { - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let x = &mut w; borrow(&*v); x.use_mut(); } fn aliased_other_reassign() { - let mut v: Box<_> = box 3; - let mut w: Box<_> = box 4; + let mut v: Box<_> = Box::new(3); + let mut w: Box<_> = Box::new(4); let mut x = &mut w; x = &mut v; borrow(&*v); //~ ERROR cannot borrow `*v` diff --git a/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr b/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr index 923edc8edae7d..6dbe4c74b5842 100644 --- a/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr +++ b/src/test/ui/borrowck/borrowck-uniq-via-lend.stderr @@ -6,7 +6,7 @@ LL | let w = &mut v; LL | borrow(&*v); | ^^^ immutable borrow occurs here LL | w.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable --> $DIR/borrowck-uniq-via-lend.rs:53:12 @@ -16,7 +16,7 @@ LL | x = &mut v; LL | borrow(&*v); | ^^^ immutable borrow occurs here LL | x.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-use-mut-borrow-rpass.rs b/src/test/ui/borrowck/borrowck-use-mut-borrow-rpass.rs index bcd1d3ccd8acb..1cf763f66fd20 100644 --- a/src/test/ui/borrowck/borrowck-use-mut-borrow-rpass.rs +++ b/src/test/ui/borrowck/borrowck-use-mut-borrow-rpass.rs @@ -1,41 +1,39 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - struct A { a: isize, b: Box } fn field_copy_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.b; drop(x.a); **p = 3; } fn fu_field_copy_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.b; - let y = A { b: box 3, .. x }; + let y = A { b: Box::new(3), .. x }; drop(y); **p = 4; } fn field_deref_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; drop(*x.b); *p = 3; } fn field_move_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; drop(x.b); *p = 3; } fn fu_field_move_after_field_borrow() { - let mut x = A { a: 1, b: box 2 }; + let mut x = A { a: 1, b: Box::new(2) }; let p = &mut x.a; let y = A { a: 3, .. x }; drop(y); diff --git a/src/test/ui/borrowck/borrowck-use-mut-borrow.rs b/src/test/ui/borrowck/borrowck-use-mut-borrow.rs index 95b165d6ef22f..94f88395ff9e2 100644 --- a/src/test/ui/borrowck/borrowck-use-mut-borrow.rs +++ b/src/test/ui/borrowck/borrowck-use-mut-borrow.rs @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - #[derive(Copy, Clone)] struct A { a: isize, b: isize } struct B { a: isize, b: Box } + + fn var_copy_after_var_borrow() { let mut x: isize = 1; let p = &mut x; @@ -50,21 +50,21 @@ fn fu_field_copy_after_field_borrow() { } fn var_deref_after_var_borrow() { - let mut x: Box = box 1; + let mut x: Box = Box::new(1); let p = &mut x; drop(*x); //~ ERROR cannot use `*x` because it was mutably borrowed **p = 2; } fn field_deref_after_var_borrow() { - let mut x = B { a: 1, b: box 2 }; + let mut x = B { a: 1, b: Box::new(2) }; let p = &mut x; drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed p.a = 3; } fn field_deref_after_field_borrow() { - let mut x = B { a: 1, b: box 2 }; + let mut x = B { a: 1, b: Box::new(2) }; let p = &mut x.b; drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed **p = 3; diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr index 5141fcc1bb261..eb0f24b9b7a50 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-loan-from-mut.stderr @@ -5,8 +5,9 @@ LL | let vb: &mut [isize] = &mut v; | ------ first mutable borrow occurs here ... LL | v.push(tail[0] + tail[1]); - | ^ ------- first borrow later used here - | | + | ^^^^^^^-------^^^^^^^^^^^ + | | | + | | first borrow later used here | second mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs index 67b6c12ba803a..8a9296c597828 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs @@ -1,12 +1,12 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + fn a() { - let mut vec = [box 1, box 2, box 3]; + let mut vec = [Box::new(1), Box::new(2), Box::new(3)]; match vec { [box ref _a, _, _] => { //~^ NOTE borrow of `vec[_]` occurs here - vec[0] = box 4; //~ ERROR cannot assign + vec[0] = Box::new(4); //~ ERROR cannot assign //~^ NOTE assignment to borrowed `vec[_]` occurs here _a.use_ref(); //~^ NOTE borrow later used here @@ -15,12 +15,12 @@ fn a() { } fn b() { - let mut vec = vec![box 1, box 2, box 3]; + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; let vec: &mut [Box] = &mut vec; match vec { &mut [ref _b @ ..] => { //~^ borrow of `vec[_]` occurs here - vec[0] = box 4; //~ ERROR cannot assign + vec[0] = Box::new(4); //~ ERROR cannot assign //~^ NOTE assignment to borrowed `vec[_]` occurs here _b.use_ref(); //~^ NOTE borrow later used here @@ -29,7 +29,7 @@ fn b() { } fn c() { - let mut vec = vec![box 1, box 2, box 3]; + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; let vec: &mut [Box] = &mut vec; match vec { //~^ ERROR cannot move out @@ -50,7 +50,7 @@ fn c() { } fn d() { - let mut vec = vec![box 1, box 2, box 3]; + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; let vec: &mut [Box] = &mut vec; match vec { //~^ ERROR cannot move out @@ -69,7 +69,7 @@ fn d() { } fn e() { - let mut vec = vec![box 1, box 2, box 3]; + let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)]; let vec: &mut [Box] = &mut vec; match vec { //~^ ERROR cannot move out diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr index 36f8f5c9ad739..ddd89afe5bf91 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -4,11 +4,11 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed LL | [box ref _a, _, _] => { | ------ borrow of `vec[_]` occurs here LL | -LL | vec[0] = box 4; +LL | vec[0] = Box::new(4); | ^^^^^^ assignment to borrowed `vec[_]` occurs here LL | LL | _a.use_ref(); - | -- borrow later used here + | ------------ borrow later used here error[E0506]: cannot assign to `vec[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-nesting.rs:23:13 @@ -16,11 +16,11 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed LL | &mut [ref _b @ ..] => { | ----------- borrow of `vec[_]` occurs here LL | -LL | vec[0] = box 4; +LL | vec[0] = Box::new(4); | ^^^^^^ assignment to borrowed `vec[_]` occurs here LL | LL | _b.use_ref(); - | -- borrow later used here + | ------------ borrow later used here error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:34:11 diff --git a/src/test/ui/borrowck/fsu-moves-and-copies.rs b/src/test/ui/borrowck/fsu-moves-and-copies.rs index 6a0b4ed17b962..85e0a840a1961 100644 --- a/src/test/ui/borrowck/fsu-moves-and-copies.rs +++ b/src/test/ui/borrowck/fsu-moves-and-copies.rs @@ -5,7 +5,7 @@ // Issue 4691: Ensure that functional-struct-updates operates // correctly and moves rather than copy when appropriate. -#![feature(box_syntax, core)] +#![feature(core)] struct ncint { v: isize } fn ncint(v: isize) -> ncint { ncint { v: v } } @@ -17,7 +17,7 @@ impl NoFoo { struct MoveFoo { copied: isize, moved: Box, } impl MoveFoo { - fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: box y } } + fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: Box::new(y) } } } struct DropNoFoo { inner: NoFoo } @@ -53,8 +53,8 @@ fn test0() { // Case 2: Owned let f = DropMoveFoo::new(5, 6); - let b = DropMoveFoo { inner: MoveFoo { moved: box 7, ..f.inner }}; - let c = DropMoveFoo { inner: MoveFoo { moved: box 8, ..f.inner }}; + let b = DropMoveFoo { inner: MoveFoo { moved: Box::new(7), ..f.inner }}; + let c = DropMoveFoo { inner: MoveFoo { moved: Box::new(8), ..f.inner }}; assert_eq!(f.inner.copied, 5); assert_eq!(*f.inner.moved, 6); @@ -69,7 +69,7 @@ fn test1() { // copying move-by-default fields from `f`, so it moves: let f = MoveFoo::new(11, 12); - let b = MoveFoo {moved: box 13, ..f}; + let b = MoveFoo {moved: Box::new(13), ..f}; let c = MoveFoo {copied: 14, ..f}; assert_eq!(b.copied, 11); assert_eq!(*b.moved, 13); diff --git a/src/test/ui/borrowck/index-mut-help-with-impl.stderr b/src/test/ui/borrowck/index-mut-help-with-impl.stderr index 89391f4099a21..69dca7e7b565c 100644 --- a/src/test/ui/borrowck/index-mut-help-with-impl.stderr +++ b/src/test/ui/borrowck/index-mut-help-with-impl.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/index-mut-help-with-impl.rs:9:5 | LL | Index::index(&v, 1..2).make_ascii_uppercase(); - | ^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/index-mut-help.stderr b/src/test/ui/borrowck/index-mut-help.stderr index 52b9ad496e5f8..057c6ee15f36c 100644 --- a/src/test/ui/borrowck/index-mut-help.stderr +++ b/src/test/ui/borrowck/index-mut-help.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutab --> $DIR/index-mut-help.rs:11:5 | LL | map["peter"].clear(); - | ^^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` diff --git a/src/test/ui/borrowck/issue-17263.rs b/src/test/ui/borrowck/issue-17263.rs index 7e9ff68548225..4f560b065f1b5 100644 --- a/src/test/ui/borrowck/issue-17263.rs +++ b/src/test/ui/borrowck/issue-17263.rs @@ -1,14 +1,12 @@ // check-pass -#![feature(box_syntax)] - struct Foo { a: isize, b: isize } fn main() { - let mut x: Box<_> = box Foo { a: 1, b: 2 }; + let mut x: Box<_> = Box::new(Foo { a: 1, b: 2 }); let (a, b) = (&mut x.a, &mut x.b); - let mut foo: Box<_> = box Foo { a: 1, b: 2 }; + let mut foo: Box<_> = Box::new(Foo { a: 1, b: 2 }); let (c, d) = (&mut foo.a, &foo.b); // We explicitly use the references created above to illustrate that the diff --git a/src/test/ui/borrowck/issue-42344.stderr b/src/test/ui/borrowck/issue-42344.stderr index 5cffa1b51219f..29b4c8c38d769 100644 --- a/src/test/ui/borrowck/issue-42344.stderr +++ b/src/test/ui/borrowck/issue-42344.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `*TAB[_]` as mutable, as `TAB` is an immutable stati --> $DIR/issue-42344.rs:4:5 | LL | TAB[0].iter_mut(); - | ^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-51117.stderr b/src/test/ui/borrowck/issue-51117.stderr index f8a9608ad373a..ef1a16ea953e2 100644 --- a/src/test/ui/borrowck/issue-51117.stderr +++ b/src/test/ui/borrowck/issue-51117.stderr @@ -4,7 +4,7 @@ error[E0499]: cannot borrow `*bar` as mutable more than once at a time LL | Some(baz) => { | --- first mutable borrow occurs here LL | bar.take(); - | ^^^ second mutable borrow occurs here + | ^^^^^^^^^^ second mutable borrow occurs here LL | drop(baz); | --- first borrow later used here diff --git a/src/test/ui/borrowck/issue-81365-10.stderr b/src/test/ui/borrowck/issue-81365-10.stderr index 891f70ed7f6b4..27123ef2be1ef 100644 --- a/src/test/ui/borrowck/issue-81365-10.stderr +++ b/src/test/ui/borrowck/issue-81365-10.stderr @@ -2,7 +2,7 @@ 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 + | ------------ borrow of `self.container_field` occurs here LL | self.container_field = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here LL | first; diff --git a/src/test/ui/borrowck/issue-81365-5.stderr b/src/test/ui/borrowck/issue-81365-5.stderr index 7c0e9f43bd0b0..8201894c6db4c 100644 --- a/src/test/ui/borrowck/issue-81365-5.stderr +++ b/src/test/ui/borrowck/issue-81365-5.stderr @@ -2,7 +2,7 @@ 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 + | ---------- borrow of `self.container_field` occurs here LL | self.container_field = true; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here LL | first; diff --git a/src/test/ui/borrowck/issue-82032.stderr b/src/test/ui/borrowck/issue-82032.stderr index f272477a9f5b3..25f343117a371 100644 --- a/src/test/ui/borrowck/issue-82032.stderr +++ b/src/test/ui/borrowck/issue-82032.stderr @@ -7,7 +7,7 @@ LL | for v in self.0.values() { | | help: use mutable method: `values_mut()` | this iterator yields `&` references LL | v.flush(); - | ^ `v` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^ `v` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-82462.nll.stderr b/src/test/ui/borrowck/issue-82462.nll.stderr deleted file mode 100644 index 10497c30e64f7..0000000000000 --- a/src/test/ui/borrowck/issue-82462.nll.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable - --> $DIR/issue-82462.rs:18:9 - | -LL | for x in DroppingSlice(&*v).iter() { - | ------------------ - | | | - | | immutable borrow occurs here - | a temporary with access to the immutable borrow is created here ... -LL | v.push(*x); - | ^ mutable borrow occurs here -LL | break; -LL | } - | - ... and the immutable borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `DroppingSlice` - | -help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped - | -LL | }; - | + - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/issue-85581.stderr b/src/test/ui/borrowck/issue-85581.stderr index 29c0429f2a046..59ca4867fd747 100644 --- a/src/test/ui/borrowck/issue-85581.stderr +++ b/src/test/ui/borrowck/issue-85581.stderr @@ -7,7 +7,7 @@ LL | match heap.peek_mut() { | first mutable borrow occurs here | a temporary with access to the first borrow is created here ... LL | Some(_) => { heap.pop(); }, - | ^^^^ second mutable borrow occurs here + | ^^^^^^^^^^ second mutable borrow occurs here ... LL | } | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option>` diff --git a/src/test/ui/borrowck/issue-85765.stderr b/src/test/ui/borrowck/issue-85765.stderr index af83c6ea6d903..80acaa7d21c52 100644 --- a/src/test/ui/borrowck/issue-85765.stderr +++ b/src/test/ui/borrowck/issue-85765.stderr @@ -5,7 +5,7 @@ LL | let rofl: &Vec> = &mut test; | ---- help: consider changing this to be a mutable reference: `&mut Vec>` LL | LL | rofl.push(Vec::new()); - | ^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0594]: cannot assign to `*r`, which is behind a `&` reference --> $DIR/issue-85765.rs:12:5 diff --git a/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr b/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr index e4c51bb77c9ed..2ffe7ff64133d 100644 --- a/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr +++ b/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr @@ -53,7 +53,7 @@ error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable --> $DIR/mut-borrow-of-mut-ref.rs:35:5 | LL | f.bar(); - | ^ cannot borrow as mutable + | ^^^^^^^ cannot borrow as mutable | help: consider making the binding mutable | diff --git a/src/test/ui/borrowck/mut-borrow-outside-loop.stderr b/src/test/ui/borrowck/mut-borrow-outside-loop.stderr index 4fcb693f1bf1d..e6895b27f35d8 100644 --- a/src/test/ui/borrowck/mut-borrow-outside-loop.stderr +++ b/src/test/ui/borrowck/mut-borrow-outside-loop.stderr @@ -6,7 +6,7 @@ LL | let first = &mut void; LL | let second = &mut void; | ^^^^^^^^^ second mutable borrow occurs here LL | first.use_mut(); - | ----- first borrow later used here + | --------------- first borrow later used here error[E0499]: cannot borrow `inner_void` as mutable more than once at a time --> $DIR/mut-borrow-outside-loop.rs:15:28 @@ -17,7 +17,7 @@ LL | let inner_second = &mut inner_void; | ^^^^^^^^^^^^^^^ second mutable borrow occurs here LL | inner_second.use_mut(); LL | inner_first.use_mut(); - | ----------- first borrow later used here + | --------------------- first borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/two-phase-across-loop.stderr b/src/test/ui/borrowck/two-phase-across-loop.stderr index d4e515d12bbb5..95896c6bbf987 100644 --- a/src/test/ui/borrowck/two-phase-across-loop.stderr +++ b/src/test/ui/borrowck/two-phase-across-loop.stderr @@ -2,7 +2,7 @@ error[E0499]: cannot borrow `foo` as mutable more than once at a time --> $DIR/two-phase-across-loop.rs:17:22 | LL | strings.push(foo.get_string()); - | ^^^ `foo` was mutably borrowed here in the previous iteration of the loop + | ^^^^^^^^^^^^^^^^ `foo` was mutably borrowed here in the previous iteration of the loop error: aborting due to previous error diff --git a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr index 9bfd8b994bf23..a89bb941532b6 100644 --- a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr +++ b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr @@ -1,13 +1,18 @@ error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:16:9 | -LL | vec.get({ - | --- --- immutable borrow later used by call - | | - | immutable borrow occurs here -LL | -LL | vec.push(2); - | ^^^ mutable borrow occurs here +LL | vec.get({ + | - --- immutable borrow later used by call + | _____| + | | +LL | | +LL | | vec.push(2); + | | ^^^^^^^^^^^ mutable borrow occurs here +LL | | +LL | | +LL | | 0 +LL | | }); + | |______- immutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/two-phase-multi-mut.stderr b/src/test/ui/borrowck/two-phase-multi-mut.stderr index 33fa4a3a15075..2e53e17a31bb0 100644 --- a/src/test/ui/borrowck/two-phase-multi-mut.stderr +++ b/src/test/ui/borrowck/two-phase-multi-mut.stderr @@ -12,8 +12,9 @@ error[E0499]: cannot borrow `foo` as mutable more than once at a time --> $DIR/two-phase-multi-mut.rs:11:16 | LL | foo.method(&mut foo); - | --- ------ ^^^^^^^^ second mutable borrow occurs here - | | | + | -----------^^^^^^^^- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr index e4fceb197be59..6cff53399ca7f 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr @@ -27,8 +27,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here | = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr index e4fceb197be59..6cff53399ca7f 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr @@ -27,8 +27,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here | = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr index 52017394e898e..0ae6fe78c6ae1 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr @@ -5,8 +5,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.extend(shared); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^^^------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable @@ -26,8 +27,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr index 52017394e898e..0ae6fe78c6ae1 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr @@ -5,8 +5,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.extend(shared); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^^^------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable @@ -26,8 +27,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr index d2ea5ab2077e5..52e8de3c4ac7d 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.nll.stderr @@ -5,8 +5,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable @@ -16,8 +17,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable @@ -27,8 +29,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr index 03f49d2d92fa1..aab21c9e78bef 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr @@ -5,8 +5,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here | note: the lint level is defined here @@ -24,8 +25,9 @@ LL | let shared = &v; | -- immutable borrow occurs here LL | LL | v.push(shared.len()); - | ^ ------ immutable borrow later used here - | | + | ^^^^^^^------------^ + | | | + | | immutable borrow later used here | mutable borrow occurs here | note: the lint level is defined here diff --git a/src/test/ui/borrowck/two-phase-sneaky.stderr b/src/test/ui/borrowck/two-phase-sneaky.stderr index c66f3cbed918d..cffbf0706fead 100644 --- a/src/test/ui/borrowck/two-phase-sneaky.stderr +++ b/src/test/ui/borrowck/two-phase-sneaky.stderr @@ -7,7 +7,7 @@ LL | v[0].push_str({ | first mutable borrow occurs here LL | LL | v.push(format!("foo")); - | ^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr b/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr index 7d0e15667505d..5a240d90011e4 100644 --- a/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr +++ b/src/test/ui/borrowck/two-phase-surprise-no-conflict.stderr @@ -13,7 +13,7 @@ error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as im --> $DIR/two-phase-surprise-no-conflict.rs:57:17 | LL | self.hash_expr(&self.cx_mut.body(eid).value); - | ^^^^^---------^^-----------^^^^^^^^^^^^^^^^^ + | ^^^^^---------^^---------------------^^^^^^^ | | | | | | | immutable borrow occurs here | | immutable borrow later used by call @@ -23,8 +23,9 @@ error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time --> $DIR/two-phase-surprise-no-conflict.rs:119:51 | LL | reg.register_static(Box::new(TrivialPass::new(&mut reg.sess_mut))); - | --- --------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ----------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -32,8 +33,9 @@ error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time --> $DIR/two-phase-surprise-no-conflict.rs:122:54 | LL | reg.register_bound(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | -------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -41,8 +43,9 @@ error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time --> $DIR/two-phase-surprise-no-conflict.rs:125:53 | LL | reg.register_univ(Box::new(TrivialPass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -50,8 +53,9 @@ error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time --> $DIR/two-phase-surprise-no-conflict.rs:128:44 | LL | reg.register_ref(&TrivialPass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ---------------------------------------^^^^^^^^^^^^^^^^^-- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -102,8 +106,9 @@ error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time --> $DIR/two-phase-surprise-no-conflict.rs:154:54 | LL | reg.register_bound(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- -------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | -------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -124,8 +129,9 @@ error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time --> $DIR/two-phase-surprise-no-conflict.rs:158:53 | LL | reg.register_univ(Box::new(CapturePass::new_mut(&mut reg.sess_mut))); - | --- ------------- ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ------------------------------------------------^^^^^^^^^^^^^^^^^--- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here @@ -143,8 +149,9 @@ error[E0499]: cannot borrow `reg.sess_mut` as mutable more than once at a time --> $DIR/two-phase-surprise-no-conflict.rs:162:44 | LL | reg.register_ref(&CapturePass::new_mut(&mut reg.sess_mut)); - | --- ------------ ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here - | | | + | ---------------------------------------^^^^^^^^^^^^^^^^^-- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here diff --git a/src/test/ui/box/leak-alloc.stderr b/src/test/ui/box/leak-alloc.stderr index 09beb18146070..e8a6ad0995a0f 100644 --- a/src/test/ui/box/leak-alloc.stderr +++ b/src/test/ui/box/leak-alloc.stderr @@ -2,7 +2,7 @@ error[E0505]: cannot move out of `alloc` because it is borrowed --> $DIR/leak-alloc.rs:26:10 | LL | let boxed = Box::new_in(10, alloc.by_ref()); - | ----- borrow of `alloc` occurs here + | -------------- borrow of `alloc` occurs here LL | let theref = Box::leak(boxed); LL | drop(alloc); | ^^^^^ move out of `alloc` occurs here diff --git a/src/test/ui/cancel-clean-via-immediate-rvalue-ref.rs b/src/test/ui/cancel-clean-via-immediate-rvalue-ref.rs index 781d5c14abe9c..a0a561ab2d21e 100644 --- a/src/test/ui/cancel-clean-via-immediate-rvalue-ref.rs +++ b/src/test/ui/cancel-clean-via-immediate-rvalue-ref.rs @@ -1,12 +1,10 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn foo(x: &mut Box) { - *x = box 5; + *x = Box::new(5); } pub fn main() { - foo(&mut box 4); + foo(&mut Box::new(4)); } diff --git a/src/test/ui/cannot-mutate-captured-non-mut-var.stderr b/src/test/ui/cannot-mutate-captured-non-mut-var.stderr index 2d6e83c9e82f9..06b5ca407db11 100644 --- a/src/test/ui/cannot-mutate-captured-non-mut-var.stderr +++ b/src/test/ui/cannot-mutate-captured-non-mut-var.stderr @@ -12,7 +12,7 @@ error[E0596]: cannot borrow `s` as mutable, as it is not declared as mutable LL | let s = std::io::stdin(); | - help: consider changing this to be mutable: `mut s` LL | to_fn_once(move|| { s.read_to_end(&mut Vec::new()); }); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to 2 previous errors diff --git a/src/test/ui/cast/issue-89497.fixed b/src/test/ui/cast/issue-89497.fixed new file mode 100644 index 0000000000000..04c10a5f79ed4 --- /dev/null +++ b/src/test/ui/cast/issue-89497.fixed @@ -0,0 +1,10 @@ +// Regression test for issue #89497. + +// run-rustfix + +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { &*(pointer as *const i32) }; + //~^ ERROR: non-primitive cast + //~| HELP: consider borrowing the value +} diff --git a/src/test/ui/cast/issue-89497.rs b/src/test/ui/cast/issue-89497.rs new file mode 100644 index 0000000000000..76301b704c81c --- /dev/null +++ b/src/test/ui/cast/issue-89497.rs @@ -0,0 +1,10 @@ +// Regression test for issue #89497. + +// run-rustfix + +fn main() { + let pointer: usize = &1_i32 as *const i32 as usize; + let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; + //~^ ERROR: non-primitive cast + //~| HELP: consider borrowing the value +} diff --git a/src/test/ui/cast/issue-89497.stderr b/src/test/ui/cast/issue-89497.stderr new file mode 100644 index 0000000000000..3726f8a41015e --- /dev/null +++ b/src/test/ui/cast/issue-89497.stderr @@ -0,0 +1,15 @@ +error[E0605]: non-primitive cast: `*const i32` as `&'static i32` + --> $DIR/issue-89497.rs:7:45 + | +LL | let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL - let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; +LL + let _reference: &'static i32 = unsafe { &*(pointer as *const i32) }; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0605`. diff --git a/src/test/ui/class-cast-to-trait.rs b/src/test/ui/class-cast-to-trait.rs index bb4c3fac93806..345d6efd2d90a 100644 --- a/src/test/ui/class-cast-to-trait.rs +++ b/src/test/ui/class-cast-to-trait.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - trait Noisy { fn speak(&self); } @@ -48,7 +46,9 @@ fn cat(in_x : usize, in_y : isize, in_name: String) -> Cat { } } + + fn main() { - let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; + let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; nyan.eat(); //~ ERROR no method named `eat` found } diff --git a/src/test/ui/cleanup-arm-conditional.rs b/src/test/ui/cleanup-arm-conditional.rs index 915842f3e85f2..38c717089c46b 100644 --- a/src/test/ui/cleanup-arm-conditional.rs +++ b/src/test/ui/cleanup-arm-conditional.rs @@ -7,7 +7,7 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax, os)] +#![feature(os)] use std::os; @@ -15,7 +15,7 @@ struct Test { x: isize } impl Test { fn get_x(&self) -> Option> { - Some(box self.x) + Some(Box::new(self.x)) } } diff --git a/src/test/ui/cleanup-rvalue-scopes.rs b/src/test/ui/cleanup-rvalue-scopes.rs index c5dd87c0f5a1f..b80f95b79f91d 100644 --- a/src/test/ui/cleanup-rvalue-scopes.rs +++ b/src/test/ui/cleanup-rvalue-scopes.rs @@ -7,7 +7,6 @@ // lifetime rules. #![feature(box_patterns)] -#![feature(box_syntax)] use std::ops::Drop; @@ -106,8 +105,8 @@ pub fn main() { end_of_block!(AddFlags { bits: ref _x }, AddFlags(1)); end_of_block!(&AddFlags { bits }, &AddFlags(1)); end_of_block!((_, ref _y), (AddFlags(1), 22)); - end_of_block!(box ref _x, box AddFlags(1)); - end_of_block!(box _x, box AddFlags(1)); + end_of_block!(box ref _x, std::boxed::Box::new(AddFlags(1))); + end_of_block!(box _x, std::boxed::Box::new(AddFlags(1))); end_of_block!(_, { { check_flags(0); &AddFlags(1) } }); end_of_block!(_, &((Box { f: AddFlags(1) }).f)); end_of_block!(_, &(([AddFlags(1)])[0])); diff --git a/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs b/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs index 62f8b81385aa3..eadbe44a8e9de 100644 --- a/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs +++ b/src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs @@ -21,8 +21,6 @@ // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; enum Conzabble { @@ -40,7 +38,7 @@ fn get_bar(x: usize) -> Vec { vec![x * 2] } pub fn fails() { let x = 2; let mut y: Vec> = Vec::new(); - y.push(box Conzabble::Bickwick(do_it(&get_bar(x)))); + y.push(Box::new(Conzabble::Bickwick(do_it(&get_bar(x))))); } pub fn main() { diff --git a/src/test/ui/clone-with-exterior.rs b/src/test/ui/clone-with-exterior.rs index 1ef2971926796..9fc661b14777e 100644 --- a/src/test/ui/clone-with-exterior.rs +++ b/src/test/ui/clone-with-exterior.rs @@ -3,8 +3,6 @@ #![allow(unused_must_use)] // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; struct Pair { @@ -13,7 +11,7 @@ struct Pair { } pub fn main() { - let z: Box<_> = box Pair { a : 10, b : 12}; + let z: Box<_> = Box::new(Pair { a : 10, b : 12}); thread::spawn(move|| { assert_eq!(z.a, 10); diff --git a/src/test/ui/close-over-big-then-small-data.rs b/src/test/ui/close-over-big-then-small-data.rs index 4d6edf4ecb0f3..429b21e8b8b99 100644 --- a/src/test/ui/close-over-big-then-small-data.rs +++ b/src/test/ui/close-over-big-then-small-data.rs @@ -5,8 +5,6 @@ // storing closure data (as we used to do), the u64 would // overwrite the u16. -#![feature(box_syntax)] - struct Pair { a: A, b: B } @@ -27,10 +25,10 @@ impl Invokable for Invoker { } fn f(a: A, b: u16) -> Box+'static> { - box Invoker { + Box::new(Invoker { a: a, b: b, - } as Box+'static> + }) as Box+'static> } pub fn main() { diff --git a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr index 768dc8e12db50..26f47eb684dfc 100644 --- a/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr +++ b/src/test/ui/closure-expected-type/expect-fn-supply-fn.nll.stderr @@ -18,8 +18,6 @@ LL | fn expect_free_supply_free_from_fn<'x>(x: &'x u32) { ... LL | with_closure_expecting_fn_with_free_region(|x: fn(&'x u32), y| {}); | ^ requires that `'x` must outlive `'static` - | - = help: consider replacing `'x` with `'static` error[E0308]: mismatched types --> $DIR/expect-fn-supply-fn.rs:32:49 diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs index 6a8c9664051df..5ff7b1242db70 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs @@ -1,10 +1,10 @@ // edition:2021 + + // Tests that two closures cannot simultaneously have mutable // and immutable access to the variable. Issue #6801. -#![feature(box_syntax)] - #[derive(Debug)] struct Point { x: i32, diff --git a/src/test/ui/closures/2229_closure_analysis/issue-88118-2.rs b/src/test/ui/closures/2229_closure_analysis/issue-88118-2.rs new file mode 100644 index 0000000000000..0cfb1a55bf27f --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-88118-2.rs @@ -0,0 +1,24 @@ +// edition:2021 +// run-pass +#![feature(if_let_guard)] +#[allow(unused_must_use)] +#[allow(dead_code)] + +fn print_error_count(registry: &Registry) { + |x: &Registry| { + match &x { + Registry if let _ = registry.try_find_description() => { } + //~^ WARNING: irrefutable `if let` guard pattern + _ => {} + } + }; +} + +struct Registry; +impl Registry { + pub fn try_find_description(&self) { + unimplemented!() + } +} + +fn main() {} diff --git a/src/test/ui/closures/2229_closure_analysis/issue-88118-2.stderr b/src/test/ui/closures/2229_closure_analysis/issue-88118-2.stderr new file mode 100644 index 0000000000000..15689023d818a --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/issue-88118-2.stderr @@ -0,0 +1,12 @@ +warning: irrefutable `if let` guard pattern + --> $DIR/issue-88118-2.rs:10:29 + | +LL | Registry if let _ = registry.try_find_description() => { } + | ^ + | + = note: `#[warn(irrefutable_let_patterns)]` on by default + = note: this pattern will always match, so the guard is useless + = help: consider removing the guard and adding a `let` inside the match arm + +warning: 1 warning emitted + diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed index beebb118399f3..b0fc5120f08f2 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed @@ -4,6 +4,14 @@ use std::thread; +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + /* Test Send Trait Migration */ struct SendPointer(*mut i32); unsafe impl Send for SendPointer {} @@ -42,19 +50,19 @@ fn test_sync_trait() { } /* Test Clone Trait Migration */ -struct S(String); +struct S(Foo); struct T(i32); struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo(0)), T(0)) } } fn test_clone_trait() { - let f = U(S(String::from("Hello World")), T(0)); + let f = U(S(Foo(0)), T(0)); let c = || { let _ = &f; //~^ ERROR: `Clone` trait implementation for closure and drop order diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs index 812ecae262f77..2bcf9a795edbd 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs @@ -4,6 +4,14 @@ use std::thread; +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + /* Test Send Trait Migration */ struct SendPointer(*mut i32); unsafe impl Send for SendPointer {} @@ -42,19 +50,19 @@ fn test_sync_trait() { } /* Test Clone Trait Migration */ -struct S(String); +struct S(Foo); struct T(i32); struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo(0)), T(0)) } } fn test_clone_trait() { - let f = U(S(String::from("Hello World")), T(0)); + let f = U(S(Foo(0)), T(0)); let c = || { //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index 98396abb6ff66..8d2d3553d4040 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure - --> $DIR/auto_traits.rs:14:19 + --> $DIR/auto_traits.rs:22:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send` @@ -24,7 +24,7 @@ LL | *fptr.0 = 20; ... error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure - --> $DIR/auto_traits.rs:34:19 + --> $DIR/auto_traits.rs:42:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send` @@ -44,7 +44,7 @@ LL | *fptr.0.0 = 20; ... error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/auto_traits.rs:58:13 + --> $DIR/auto_traits.rs:66:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed index f91454aa2111e..9a6db588c8bf5 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed @@ -3,6 +3,14 @@ // check-pass #![warn(rust_2021_compatibility)] +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + macro_rules! m { (@ $body:expr) => {{ let f = || $body; @@ -15,11 +23,11 @@ macro_rules! m { } fn main() { - let a = (1.to_string(), 2.to_string()); + let a = (Foo(0), Foo(1)); m!({ let _ = &a; //~^ HELP: add a dummy let x = a.0; - println!("{}", x); + println!("{:?}", x); }); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs index 5a1026d043319..08cc24b4b3fe8 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs @@ -3,6 +3,14 @@ // check-pass #![warn(rust_2021_compatibility)] +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + macro_rules! m { (@ $body:expr) => {{ let f = || $body; @@ -15,10 +23,10 @@ macro_rules! m { } fn main() { - let a = (1.to_string(), 2.to_string()); + let a = (Foo(0), Foo(1)); m!({ //~^ HELP: add a dummy let x = a.0; - println!("{}", x); + println!("{:?}", x); }); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr index e6e5598f6d2a1..a2a9da5f87ced 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr @@ -1,5 +1,5 @@ warning: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/closure-body-macro-fragment.rs:8:17 + --> $DIR/closure-body-macro-fragment.rs:16:17 | LL | let f = || $body; | _________________^ @@ -15,7 +15,7 @@ LL | / m!({ LL | | LL | | let x = a.0; | | --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0` -LL | | println!("{}", x); +LL | | println!("{:?}", x); LL | | }); | |_______- in this macro invocation | diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed index c82bc369f4301..2652bf5988e65 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed @@ -1,169 +1,38 @@ +// run-pass // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] -//~^ NOTE: the lint level is defined here +#![allow(unused)] // Test cases for types that implement an insignificant drop (stlib defined) -// `t` needs Drop because one of its elements needs drop, -// therefore precise capture might affect drop ordering -fn test1_all_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); +macro_rules! test_insig_dtor_for_type { + ($t: ty, $disambiguator: ident) => { + mod $disambiguator { + use std::collections::*; + use std::rc::Rc; + use std::sync::Mutex; - let c = || { - let _ = (&t, &t1, &t2); - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured + fn test_for_type(t: $t) { + let tup = (Mutex::new(0), t); - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` - let _t2 = t2.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0` + let _c = || tup.0; + } + } }; - - c(); } -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure -//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure - -// String implements drop and therefore should be migrated. -// But in this test cases, `t2` is completely captured and when it is dropped won't be affected -fn test2_only_precise_paths_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); - - let c = || { - let _ = (&t, &t1); - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` - let _t2 = t2; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure - -// If a variable would've not been captured by value then it would've not been -// dropped with the closure and therefore doesn't need migration. -fn test3_only_by_value_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let c = || { - let _ = &t; - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - println!("{}", t1.1); - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Copy types get copied into the closure instead of move. Therefore we don't need to -// migrate then as their drop order isn't tied to the closure. -fn test4_only_non_copy_types_need_migration() { - let t = (String::new(), String::new()); - - // `t1` is Copy because all of its elements are Copy - let t1 = (0i32, 0i32); - - let c = || { - let _ = &t; - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn test5_only_drop_types_need_migration() { - struct S(i32, i32); - let t = (String::new(), String::new()); - - // `s` doesn't implement Drop or any elements within it, and doesn't need migration - let s = S(0i32, 0i32); - - let c = || { - let _ = &t; - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _s = s.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Since we are using a move closure here, both `t` and `t1` get moved -// even though they are being used by ref inside the closure. -fn test6_move_closures_non_copy_types_might_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let c = move || { - let _ = (&t1, &t); - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured - println!("{} {}", t1.1, t.1); - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1` - //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure - -// Test migration analysis in case of Drop + Non Drop aggregates. -// Note we need migration here only because the non-copy (because Drop type) is captured, -// otherwise we won't need to, since we can get away with just by ref capture in that case. -fn test7_drop_non_drop_aggregate_need_migration() { - let t = (String::new(), String::new(), 0i32); - - let c = || { - let _ = &t; - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn main() { - test1_all_need_migration(); - test2_only_precise_paths_need_migration(); - test3_only_by_value_need_migration(); - test4_only_non_copy_types_need_migration(); - test5_only_drop_types_need_migration(); - test6_move_closures_non_copy_types_might_need_migration(); - test7_drop_non_drop_aggregate_need_migration(); -} +test_insig_dtor_for_type!(i32, prim_i32); +test_insig_dtor_for_type!(Vec, vec_i32); +test_insig_dtor_for_type!(String, string); +test_insig_dtor_for_type!(Vec, vec_string); +test_insig_dtor_for_type!(HashMap, hash_map); +test_insig_dtor_for_type!(BTreeMap, btree_map); +test_insig_dtor_for_type!(LinkedList, linked_list); +test_insig_dtor_for_type!(Rc, rc_i32); +test_insig_dtor_for_type!(Rc, rc_string); +test_insig_dtor_for_type!(std::vec::IntoIter, vec_into_iter); +test_insig_dtor_for_type!(btree_map::IntoIter, btree_map_into_iter); +test_insig_dtor_for_type!(std::array::IntoIter, array_into_iter); + +fn main() {} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs index 57ab15ae8f243..2652bf5988e65 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs @@ -1,162 +1,38 @@ +// run-pass // run-rustfix #![deny(rust_2021_incompatible_closure_captures)] -//~^ NOTE: the lint level is defined here +#![allow(unused)] // Test cases for types that implement an insignificant drop (stlib defined) -// `t` needs Drop because one of its elements needs drop, -// therefore precise capture might affect drop ordering -fn test1_all_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); +macro_rules! test_insig_dtor_for_type { + ($t: ty, $disambiguator: ident) => { + mod $disambiguator { + use std::collections::*; + use std::rc::Rc; + use std::sync::Mutex; - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured + fn test_for_type(t: $t) { + let tup = (Mutex::new(0), t); - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` - let _t2 = t2.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0` + let _c = || tup.0; + } + } }; - - c(); } -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure -//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure - -// String implements drop and therefore should be migrated. -// But in this test cases, `t2` is completely captured and when it is dropped won't be affected -fn test2_only_precise_paths_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let t2 = (String::new(), String::new()); - - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` - let _t2 = t2; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure - -// If a variable would've not been captured by value then it would've not been -// dropped with the closure and therefore doesn't need migration. -fn test3_only_by_value_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - println!("{}", t1.1); - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Copy types get copied into the closure instead of move. Therefore we don't need to -// migrate then as their drop order isn't tied to the closure. -fn test4_only_non_copy_types_need_migration() { - let t = (String::new(), String::new()); - - // `t1` is Copy because all of its elements are Copy - let t1 = (0i32, 0i32); - - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _t1 = t1.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn test5_only_drop_types_need_migration() { - struct S(i32, i32); - let t = (String::new(), String::new()); - - // `s` doesn't implement Drop or any elements within it, and doesn't need migration - let s = S(0i32, 0i32); - - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - let _s = s.0; - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -// Since we are using a move closure here, both `t` and `t1` get moved -// even though they are being used by ref inside the closure. -fn test6_move_closures_non_copy_types_might_need_migration() { - let t = (String::new(), String::new()); - let t1 = (String::new(), String::new()); - let c = move || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured - println!("{} {}", t1.1, t.1); - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1` - //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure -//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure - -// Test migration analysis in case of Drop + Non Drop aggregates. -// Note we need migration here only because the non-copy (because Drop type) is captured, -// otherwise we won't need to, since we can get away with just by ref capture in that case. -fn test7_drop_non_drop_aggregate_need_migration() { - let t = (String::new(), String::new(), 0i32); - - let c = || { - //~^ ERROR: drop order - //~| NOTE: for more information, see - //~| HELP: add a dummy let to cause `t` to be fully captured - let _t = t.0; - //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` - }; - - c(); -} -//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - -fn main() { - test1_all_need_migration(); - test2_only_precise_paths_need_migration(); - test3_only_by_value_need_migration(); - test4_only_non_copy_types_need_migration(); - test5_only_drop_types_need_migration(); - test6_move_closures_non_copy_types_might_need_migration(); - test7_drop_non_drop_aggregate_need_migration(); -} +test_insig_dtor_for_type!(i32, prim_i32); +test_insig_dtor_for_type!(Vec, vec_i32); +test_insig_dtor_for_type!(String, string); +test_insig_dtor_for_type!(Vec, vec_string); +test_insig_dtor_for_type!(HashMap, hash_map); +test_insig_dtor_for_type!(BTreeMap, btree_map); +test_insig_dtor_for_type!(LinkedList, linked_list); +test_insig_dtor_for_type!(Rc, rc_i32); +test_insig_dtor_for_type!(Rc, rc_string); +test_insig_dtor_for_type!(std::vec::IntoIter, vec_into_iter); +test_insig_dtor_for_type!(btree_map::IntoIter, btree_map_into_iter); +test_insig_dtor_for_type!(std::array::IntoIter, array_into_iter); + +fn main() {} diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr deleted file mode 100644 index 7989a8fa5ccae..0000000000000 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr +++ /dev/null @@ -1,161 +0,0 @@ -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:15:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -LL | -LL | let _t1 = t1.0; - | ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` -LL | -LL | let _t2 = t2.0; - | ---- in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0` -... -LL | } - | - - | | - | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure - | in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure - | -note: the lint level is defined here - --> $DIR/insignificant_drop.rs:3:9 - | -LL | #![deny(rust_2021_incompatible_closure_captures)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: for more information, see -help: add a dummy let to cause `t`, `t1`, `t2` to be fully captured - | -LL ~ let c = || { -LL + let _ = (&t, &t1, &t2); - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:41:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -LL | -LL | let _t1 = t1.0; - | ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0` -... -LL | } - | - - | | - | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t`, `t1` to be fully captured - | -LL ~ let c = || { -LL + let _ = (&t, &t1); - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:62:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -... -LL | } - | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t` to be fully captured - | -LL ~ let c = || { -LL + let _ = &t; - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:83:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -... -LL | } - | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t` to be fully captured - | -LL ~ let c = || { -LL + let _ = &t; - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:104:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -... -LL | } - | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t` to be fully captured - | -LL ~ let c = || { -LL + let _ = &t; - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:122:13 - | -LL | let c = move || { - | ^^^^^^^ -... -LL | println!("{} {}", t1.1, t.1); - | ---- --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1` - | | - | in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1` -... -LL | } - | - - | | - | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure - | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t1`, `t` to be fully captured - | -LL ~ let c = move || { -LL + let _ = (&t1, &t); - | - -error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop.rs:142:13 - | -LL | let c = || { - | ^^ -... -LL | let _t = t.0; - | --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0` -... -LL | } - | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure - | - = note: for more information, see -help: add a dummy let to cause `t` to be fully captured - | -LL ~ let c = || { -LL + let _ = &t; - | - -error: aborting due to 7 previous errors - diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed index e672d9266fcd1..d985e3bb9ec74 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed @@ -5,13 +5,15 @@ #![feature(rustc_attrs)] #![allow(unused)] +use std::sync::Mutex; + + #[rustc_insignificant_dtor] struct InsignificantDropPoint { x: i32, - y: i32, + y: Mutex, } impl Drop for InsignificantDropPoint { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } @@ -21,15 +23,15 @@ impl Drop for SigDrop { fn drop(&mut self) {} } +#[rustc_insignificant_dtor] struct GenericStruct(T, T); -struct Wrapper(GenericStruct, i32); - impl Drop for GenericStruct { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } +struct Wrapper(GenericStruct, i32); + // `SigDrop` implements drop and therefore needs to be migrated. fn significant_drop_needs_migration() { let t = (SigDrop {}, SigDrop {}); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs index 45850ec5f36dc..f95d34eeb299a 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs @@ -5,13 +5,15 @@ #![feature(rustc_attrs)] #![allow(unused)] +use std::sync::Mutex; + + #[rustc_insignificant_dtor] struct InsignificantDropPoint { x: i32, - y: i32, + y: Mutex, } impl Drop for InsignificantDropPoint { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } @@ -21,15 +23,15 @@ impl Drop for SigDrop { fn drop(&mut self) {} } +#[rustc_insignificant_dtor] struct GenericStruct(T, T); -struct Wrapper(GenericStruct, i32); - impl Drop for GenericStruct { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } +struct Wrapper(GenericStruct, i32); + // `SigDrop` implements drop and therefore needs to be migrated. fn significant_drop_needs_migration() { let t = (SigDrop {}, SigDrop {}); diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr index 961834aca194d..832a81711b137 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop_attr_migrations.rs:37:13 + --> $DIR/insignificant_drop_attr_migrations.rs:39:13 | LL | let c = || { | ^^ @@ -23,7 +23,7 @@ LL + let _ = &t; | error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/insignificant_drop_attr_migrations.rs:57:13 + --> $DIR/insignificant_drop_attr_migrations.rs:59:13 | LL | let c = move || { | ^^^^^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs index a527bf42e574a..3f184a67fbac9 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs @@ -3,6 +3,7 @@ #![deny(rust_2021_incompatible_closure_captures)] #![feature(rustc_attrs)] #![allow(unused)] +#[rustc_insignificant_dtor] struct InsignificantDropPoint { x: i32, @@ -10,7 +11,6 @@ struct InsignificantDropPoint { } impl Drop for InsignificantDropPoint { - #[rustc_insignificant_dtor] fn drop(&mut self) {} } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed index b9dd8a20b093f..31fe494dc795a 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed @@ -5,8 +5,17 @@ #![deny(rust_2021_incompatible_closure_captures)] //~^ NOTE: the lint level is defined here + +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + fn main() { - let a = ("hey".to_string(), "123".to_string()); + let a = (Foo(0), Foo(1)); let _ = || { let _ = &a; dbg!(a.0) }; //~^ ERROR: drop order //~| NOTE: will only capture `a.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs b/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs index f7ccdb754b858..0f0c497492290 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.rs @@ -5,8 +5,17 @@ #![deny(rust_2021_incompatible_closure_captures)] //~^ NOTE: the lint level is defined here + +#[derive(Debug)] +struct Foo(i32); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + fn main() { - let a = ("hey".to_string(), "123".to_string()); + let a = (Foo(0), Foo(1)); let _ = || dbg!(a.0); //~^ ERROR: drop order //~| NOTE: will only capture `a.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr index d1f959dfc520e..5046a4bcbb4b3 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/macro.rs:10:13 + --> $DIR/macro.rs:19:13 | LL | let _ = || dbg!(a.0); | ^^^^^^^^---^ diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed index ef90257474a9f..11218eff1337f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed @@ -4,7 +4,22 @@ use std::thread; -struct S(String); +#[derive(Debug)] +struct Foo(String); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +impl Foo { + fn from(s: &str) -> Self { + Self(String::from(s)) + } +} + + +struct S(Foo); #[derive(Clone)] struct T(i32); @@ -13,13 +28,13 @@ struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo::from("Hello World")), T(0)) } } fn test_multi_issues() { - let f1 = U(S(String::from("foo")), T(0)); - let f2 = U(S(String::from("bar")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); + let f2 = U(S(Foo::from("bar")), T(0)); let c = || { let _ = (&f1, &f2); //~^ ERROR: `Clone` trait implementation for closure and drop order @@ -39,7 +54,7 @@ fn test_multi_issues() { //~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure fn test_capturing_all_disjoint_fields_individually() { - let f1 = U(S(String::from("foo")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); let c = || { let _ = &f1; //~^ ERROR: `Clone` trait implementation for closure @@ -60,12 +75,12 @@ struct U1(S, T, S); impl Clone for U1 { fn clone(&self) -> Self { - U1(S(String::from("foo")), T(0), S(String::from("bar"))) + U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))) } } fn test_capturing_several_disjoint_fields_individually_1() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; //~^ ERROR: `Clone` trait implementation for closure @@ -85,7 +100,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { } fn test_capturing_several_disjoint_fields_individually_2() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { let _ = &f1; //~^ ERROR: `Clone` trait implementation for closure and drop order diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs index b9644c18d28e2..02f2faa2e8741 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs @@ -4,7 +4,22 @@ use std::thread; -struct S(String); +#[derive(Debug)] +struct Foo(String); +impl Drop for Foo { + fn drop(&mut self) { + println!("{:?} dropped", self.0); + } +} + +impl Foo { + fn from(s: &str) -> Self { + Self(String::from(s)) + } +} + + +struct S(Foo); #[derive(Clone)] struct T(i32); @@ -13,13 +28,13 @@ struct U(S, T); impl Clone for U { fn clone(&self) -> Self { - U(S(String::from("Hello World")), T(0)) + U(S(Foo::from("Hello World")), T(0)) } } fn test_multi_issues() { - let f1 = U(S(String::from("foo")), T(0)); - let f2 = U(S(String::from("bar")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); + let f2 = U(S(Foo::from("bar")), T(0)); let c = || { //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -38,7 +53,7 @@ fn test_multi_issues() { //~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure fn test_capturing_all_disjoint_fields_individually() { - let f1 = U(S(String::from("foo")), T(0)); + let f1 = U(S(Foo::from("foo")), T(0)); let c = || { //~^ ERROR: `Clone` trait implementation for closure //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -58,12 +73,12 @@ struct U1(S, T, S); impl Clone for U1 { fn clone(&self) -> Self { - U1(S(String::from("foo")), T(0), S(String::from("bar"))) + U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))) } } fn test_capturing_several_disjoint_fields_individually_1() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { //~^ ERROR: `Clone` trait implementation for closure //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -82,7 +97,7 @@ fn test_capturing_several_disjoint_fields_individually_1() { } fn test_capturing_several_disjoint_fields_individually_2() { - let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar"))); + let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar"))); let c = || { //~^ ERROR: `Clone` trait implementation for closure and drop order //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index 8bee950c13eca..d425db5aa998c 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -1,5 +1,5 @@ error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:23:13 + --> $DIR/multi_diagnostics.rs:38:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -26,7 +26,7 @@ LL + let _ = (&f1, &f2); | error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:42:13 + --> $DIR/multi_diagnostics.rs:57:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -42,7 +42,7 @@ LL + let _ = &f1; | error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure - --> $DIR/multi_diagnostics.rs:67:13 + --> $DIR/multi_diagnostics.rs:82:13 | LL | let c = || { | ^^ @@ -64,7 +64,7 @@ LL + let _ = &f1; | error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order - --> $DIR/multi_diagnostics.rs:86:13 + --> $DIR/multi_diagnostics.rs:101:13 | LL | let c = || { | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone` @@ -89,7 +89,7 @@ LL + let _ = &f1; | error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure - --> $DIR/multi_diagnostics.rs:119:19 + --> $DIR/multi_diagnostics.rs:134:19 | LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed index aca0b2a96ac56..63e4000e833eb 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed @@ -165,7 +165,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() { fn test8_drop_order_and_blocks() { { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); { let c = || { let _ = &tuple; @@ -184,7 +184,7 @@ fn test8_drop_order_and_blocks() { fn test9_drop_order_and_nested_closures() { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); let b = || { let c = || { let _ = &tuple; @@ -202,6 +202,19 @@ fn test9_drop_order_and_nested_closures() { b(); } +// Test that we migrate if drop order of Vec would be affected if T is a significant drop type +fn test10_vec_of_significant_drop_type() { + + let tup = (Foo(0), vec![Foo(3)]); + + let _c = || { let _ = &tup; tup.0 }; + //~^ ERROR: drop order + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `tup` to be fully captured + //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0` +} +//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure + fn main() { test1_all_need_migration(); test2_only_precise_paths_need_migration(); @@ -212,4 +225,5 @@ fn main() { test7_move_closures_non_copy_types_might_need_migration(); test8_drop_order_and_blocks(); test9_drop_order_and_nested_closures(); + test10_vec_of_significant_drop_type(); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs index fd4134a770479..9d9c54298cf11 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs @@ -158,7 +158,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() { fn test8_drop_order_and_blocks() { { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); { let c = || { //~^ ERROR: drop order @@ -176,7 +176,7 @@ fn test8_drop_order_and_blocks() { fn test9_drop_order_and_nested_closures() { let tuple = - (String::from("foo"), String::from("bar")); + (Foo(0), Foo(1)); let b = || { let c = || { //~^ ERROR: drop order @@ -193,6 +193,19 @@ fn test9_drop_order_and_nested_closures() { b(); } +// Test that we migrate if drop order of Vec would be affected if T is a significant drop type +fn test10_vec_of_significant_drop_type() { + + let tup = (Foo(0), vec![Foo(3)]); + + let _c = || tup.0; + //~^ ERROR: drop order + //~| NOTE: for more information, see + //~| HELP: add a dummy let to cause `tup` to be fully captured + //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0` +} +//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure + fn main() { test1_all_need_migration(); test2_only_precise_paths_need_migration(); @@ -203,4 +216,5 @@ fn main() { test7_move_closures_non_copy_types_might_need_migration(); test8_drop_order_and_blocks(); test9_drop_order_and_nested_closures(); + test10_vec_of_significant_drop_type(); } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr index e9170eba3f176..fa1f83c37823f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr @@ -195,5 +195,22 @@ LL ~ let c = || { LL + let _ = &tuple; | -error: aborting due to 9 previous errors +error: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/significant_drop.rs:201:18 + | +LL | let _c = || tup.0; + | ^^^----- + | | + | in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0` +... +LL | } + | - in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure + | + = note: for more information, see +help: add a dummy let to cause `tup` to be fully captured + | +LL | let _c = || { let _ = &tup; tup.0 }; + | +++++++++++++++ + + +error: aborting due to 10 previous errors diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs new file mode 100644 index 0000000000000..2f8cddc06bab1 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs @@ -0,0 +1,101 @@ +// edition:2021 + +// Tests that in cases where we individually capture all the fields of a type, +// we still drop them in the order they would have been dropped in the 2018 edition. + +// NOTE: It is *critical* that the order of the min capture NOTES in the stderr output +// does *not* change! + +#![feature(rustc_attrs)] + +#[derive(Debug)] +struct HasDrop; +impl Drop for HasDrop { + fn drop(&mut self) { + println!("dropped"); + } +} + +fn test_one() { + let a = (HasDrop, HasDrop); + let b = (HasDrop, HasDrop); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: Min Capture analysis includes: + //~| ERROR + println!("{:?}", a.0); + //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", a.1); + //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow + //~| NOTE + + println!("{:?}", b.0); + //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", b.1); + //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow + //~| NOTE + }; +} + +fn test_two() { + let a = (HasDrop, HasDrop); + let b = (HasDrop, HasDrop); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: Min Capture analysis includes: + //~| ERROR + println!("{:?}", a.1); + //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", a.0); + //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow + //~| NOTE + + println!("{:?}", b.1); + //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", b.0); + //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow + //~| NOTE + }; +} + +fn test_three() { + let a = (HasDrop, HasDrop); + let b = (HasDrop, HasDrop); + + let c = #[rustc_capture_analysis] + //~^ ERROR: attributes on expressions are experimental + //~| NOTE: see issue #15701 + || { + //~^ ERROR: Min Capture analysis includes: + //~| ERROR + println!("{:?}", b.1); + //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", a.1); + //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow + //~| NOTE + println!("{:?}", a.0); + //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow + //~| NOTE + + println!("{:?}", b.0); + //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow + //~| NOTE + }; +} + +fn main() { + test_one(); + test_two(); + test_three(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr new file mode 100644 index 0000000000000..2d1dc8727c255 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr @@ -0,0 +1,228 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/preserve_field_drop_order.rs:23:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/preserve_field_drop_order.rs:49:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/preserve_field_drop_order.rs:75:13 + | +LL | let c = #[rustc_capture_analysis] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error: First Pass analysis includes: + --> $DIR/preserve_field_drop_order.rs:26:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.0); +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:29:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Capturing a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:32:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Capturing b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:36:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Capturing b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:39:26 + | +LL | println!("{:?}", b.1); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/preserve_field_drop_order.rs:26:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.0); +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:29:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Min Capture a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:32:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Min Capture b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:36:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Min Capture b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:39:26 + | +LL | println!("{:?}", b.1); + | ^^^ + +error: First Pass analysis includes: + --> $DIR/preserve_field_drop_order.rs:52:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:55:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Capturing a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:58:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Capturing b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:62:26 + | +LL | println!("{:?}", b.1); + | ^^^ +note: Capturing b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:65:26 + | +LL | println!("{:?}", b.0); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/preserve_field_drop_order.rs:52:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", a.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:58:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Min Capture a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:55:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Min Capture b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:65:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Min Capture b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:62:26 + | +LL | println!("{:?}", b.1); + | ^^^ + +error: First Pass analysis includes: + --> $DIR/preserve_field_drop_order.rs:78:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", b.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Capturing b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:81:26 + | +LL | println!("{:?}", b.1); + | ^^^ +note: Capturing a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:84:26 + | +LL | println!("{:?}", a.1); + | ^^^ +note: Capturing a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:87:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Capturing b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:91:26 + | +LL | println!("{:?}", b.0); + | ^^^ + +error: Min Capture analysis includes: + --> $DIR/preserve_field_drop_order.rs:78:5 + | +LL | / || { +LL | | +LL | | +LL | | println!("{:?}", b.1); +... | +LL | | +LL | | }; + | |_____^ + | +note: Min Capture b[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:91:26 + | +LL | println!("{:?}", b.0); + | ^^^ +note: Min Capture b[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:81:26 + | +LL | println!("{:?}", b.1); + | ^^^ +note: Min Capture a[(0, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:87:26 + | +LL | println!("{:?}", a.0); + | ^^^ +note: Min Capture a[(1, 0)] -> ImmBorrow + --> $DIR/preserve_field_drop_order.rs:84:26 + | +LL | println!("{:?}", a.1); + | ^^^ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs new file mode 100644 index 0000000000000..1cae776dd68bc --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs @@ -0,0 +1,58 @@ +// run-pass +// check-run-results +// revisions: twenty_eighteen twenty_twentyone +// [twenty_eighteen]compile-flags: --edition 2018 +// [twenty_twentyone]compile-flags: --edition 2021 + +#[derive(Debug)] +struct Dropable(&'static str); + +impl Drop for Dropable { + fn drop(&mut self) { + println!("Dropping {}", self.0) + } +} + +#[derive(Debug)] +struct A { + x: Dropable, + y: Dropable, +} + +#[derive(Debug)] +struct B { + c: A, + d: A, +} + +#[derive(Debug)] +struct R<'a> { + c: &'a A, + d: &'a A, +} + +fn main() { + let a = A { x: Dropable("x"), y: Dropable("y") }; + + let c = move || println!("{:?} {:?}", a.y, a.x); + + c(); + + let b = B { + c: A { x: Dropable("b.c.x"), y: Dropable("b.c.y") }, + d: A { x: Dropable("b.d.x"), y: Dropable("b.d.y") }, + }; + + let d = move || println!("{:?} {:?} {:?} {:?}", b.d.y, b.d.x, b.c.y, b.c.x); + + d(); + + let r = R { + c: &A { x: Dropable("r.c.x"), y: Dropable("r.c.y") }, + d: &A { x: Dropable("r.d.x"), y: Dropable("r.d.y") }, + }; + + let e = move || println!("{:?} {:?} {:?} {:?}", r.d.y, r.d.x, r.c.y, r.c.x); + + e(); +} diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout new file mode 100644 index 0000000000000..557d047c1d524 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout @@ -0,0 +1,13 @@ +Dropable("y") Dropable("x") +Dropable("b.d.y") Dropable("b.d.x") Dropable("b.c.y") Dropable("b.c.x") +Dropable("r.d.y") Dropable("r.d.x") Dropable("r.c.y") Dropable("r.c.x") +Dropping r.d.x +Dropping r.d.y +Dropping r.c.x +Dropping r.c.y +Dropping b.c.x +Dropping b.c.y +Dropping b.d.x +Dropping b.d.y +Dropping x +Dropping y diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout new file mode 100644 index 0000000000000..557d047c1d524 --- /dev/null +++ b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout @@ -0,0 +1,13 @@ +Dropable("y") Dropable("x") +Dropable("b.d.y") Dropable("b.d.x") Dropable("b.c.y") Dropable("b.c.x") +Dropable("r.d.y") Dropable("r.d.x") Dropable("r.c.y") Dropable("r.c.x") +Dropping r.d.x +Dropping r.d.y +Dropping r.c.x +Dropping r.c.y +Dropping b.c.x +Dropping b.c.y +Dropping b.d.x +Dropping b.d.y +Dropping x +Dropping y diff --git a/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr index 52bca8dd63e1f..9aab51c986cac 100644 --- a/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr +++ b/src/test/ui/closures/closure-expected-type/expect-region-supply-region-2.nll.stderr @@ -17,8 +17,6 @@ LL | fn expect_bound_supply_named<'x>() { ... LL | closure_expecting_bound(|x: &'x u32| { | ^ requires that `'x` must outlive `'static` - | - = help: consider replacing `'x` with `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/closures/issue-87814-2.rs b/src/test/ui/closures/issue-87814-2.rs index 7a5facdac58c3..efe77f90f0658 100644 --- a/src/test/ui/closures/issue-87814-2.rs +++ b/src/test/ui/closures/issue-87814-2.rs @@ -1,5 +1,4 @@ // check-pass -#![feature(try_reserve)] fn main() { let mut schema_all: (Vec, Vec) = (vec![], vec![]); diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr index 3564ab4b6cd4d..08b763b260822 100644 --- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr +++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-1.stderr @@ -1,4 +1,4 @@ -error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers. +error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers --> $DIR/wrong-abi-location-1.rs:8:1 | LL | pub extern "C-cmse-nonsecure-call" fn test() {} diff --git a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr index 76073f548848a..3ade9891e48a5 100644 --- a/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr +++ b/src/test/ui/cmse-nonsecure/cmse-nonsecure-call/wrong-abi-location-2.stderr @@ -1,4 +1,4 @@ -error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers. +error[E0781]: the `"C-cmse-nonsecure-call"` ABI is only allowed on function pointers --> $DIR/wrong-abi-location-2.rs:8:1 | LL | / extern "C-cmse-nonsecure-call" { diff --git a/src/test/ui/codemap_tests/issue-11715.stderr b/src/test/ui/codemap_tests/issue-11715.stderr index d0c29c768eb61..a6b2b2e50a3fa 100644 --- a/src/test/ui/codemap_tests/issue-11715.stderr +++ b/src/test/ui/codemap_tests/issue-11715.stderr @@ -7,7 +7,7 @@ LL | let z = &mut x; | ^^^^^^ second mutable borrow occurs here LL | z.use_mut(); LL | y.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/one_line.stderr b/src/test/ui/codemap_tests/one_line.stderr index eddbd29c0ef81..1ee612184def2 100644 --- a/src/test/ui/codemap_tests/one_line.stderr +++ b/src/test/ui/codemap_tests/one_line.stderr @@ -2,8 +2,9 @@ error[E0499]: cannot borrow `v` as mutable more than once at a time --> $DIR/one_line.rs:3:12 | LL | v.push(v.pop().unwrap()); - | - ---- ^ second mutable borrow occurs here - | | | + | -------^^^^^^^---------- + | | | | + | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here diff --git a/src/test/ui/coercion/coerce-expect-unsized.rs b/src/test/ui/coercion/coerce-expect-unsized.rs index d486fdf73aba8..eeb8fe82346c2 100644 --- a/src/test/ui/coercion/coerce-expect-unsized.rs +++ b/src/test/ui/coercion/coerce-expect-unsized.rs @@ -1,6 +1,5 @@ // run-pass #![allow(unused_braces)] -#![feature(box_syntax)] use std::cell::RefCell; use std::fmt::Debug; diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr b/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr new file mode 100644 index 0000000000000..fbaa874792a01 --- /dev/null +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `(): std::error::Error` is not satisfied + --> $DIR/coerce-issue-49593-box-never.rs:17:53 + | +LL | /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` + | + = note: required for the cast to the object type `dyn std::error::Error` + +error[E0277]: the trait bound `(): std::error::Error` is not satisfied + --> $DIR/coerce-issue-49593-box-never.rs:22:49 + | +LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` + | + = note: required for the cast to the object type `(dyn std::error::Error + 'static)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs index 0824ce8cd585b..7a4324bd5adce 100644 --- a/src/test/ui/coercion/coerce-issue-49593-box-never.rs +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs @@ -1,5 +1,9 @@ -// check-pass -#![feature(never_type, never_type_fallback)] +// revisions: nofallback fallback +//[fallback] check-pass +//[nofallback] check-fail + +#![feature(never_type)] +#![cfg_attr(fallback, feature(never_type_fallback))] #![allow(unreachable_code)] use std::error::Error; @@ -11,10 +15,12 @@ fn raw_ptr_box(t: T) -> *mut T { fn foo(x: !) -> Box { /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) + //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn foo_raw_ptr(x: !) -> *mut dyn Error { /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) + //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn no_coercion(d: *mut dyn Error) -> *mut dyn Error { diff --git a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr index 9b3c32a939779..041232e869079 100644 --- a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr @@ -10,9 +10,10 @@ error: overly complex generic constant --> $DIR/array-size-in-generic-struct-param.rs:19:15 | LL | arr: [u8; CFG.arr_size], - | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^ field access is not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr index 95dae4ecc0431..0dfd804be41b4 100644 --- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr @@ -4,9 +4,10 @@ error: overly complex generic constant LL | fn test() -> [u8; N + (|| 42)()] {} | ^^^^-------^^ | | - | unsupported operation in generic constant, this may be supported in the future + | dereferencing is not supported in generic constants | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to previous error diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs new file mode 100644 index 0000000000000..b79bc262d2bac --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs @@ -0,0 +1,29 @@ +// run-pass +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Foo { + type Assoc: Default; +} + +impl Foo<0> for () { + type Assoc = u32; +} + +impl Foo<3> for () { + type Assoc = i64; +} + +fn foo(_: T) -> <() as Foo<{ N + 1 }>>::Assoc +where + (): Foo<{ N + 1 }>, +{ + Default::default() +} + +fn main() { + // Test that we can correctly infer `T` which requires evaluating + // `{ N + 1 }` which has substs containing an inference var + let mut _q = Default::default(); + _q = foo::<_, 2>(_q); +} diff --git a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr index c9f847995223a..5ebb4c3999c36 100644 --- a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr @@ -2,17 +2,19 @@ error: overly complex generic constant --> $DIR/let-bindings.rs:6:68 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: overly complex generic constant --> $DIR/let-bindings.rs:6:35 | LL | fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { - | ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr index 3da91b19a5ed9..df73acf53de65 100644 --- a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr @@ -2,25 +2,28 @@ error: overly complex generic constant --> $DIR/unused_expr.rs:4:34 | LL | fn add() -> [u8; { N + 1; 5 }] { - | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: overly complex generic constant --> $DIR/unused_expr.rs:9:34 | LL | fn div() -> [u8; { N / 1; 5 }] { - | ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: overly complex generic constant --> $DIR/unused_expr.rs:16:38 | LL | fn fn_call() -> [u8; { foo(N); 5 }] { - | ^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future + | ^^^^^^^^^^^^^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/issues/issue-67375.full.stderr b/src/test/ui/const-generics/issues/issue-67375.full.stderr index d7b52063dc4db..0f0e339655bca 100644 --- a/src/test/ui/const-generics/issues/issue-67375.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67375.full.stderr @@ -2,9 +2,9 @@ error: overly complex generic constant --> $DIR/issue-67375.rs:7:17 | LL | inner: [(); { [|_: &T| {}; 0].len() }], - | ^^---------------^^^^^^^^ + | ^^---------------------^^ | | - | unsupported operation in generic constant + | pointer casts are not allowed in generic constants | = help: consider moving this anonymous constant into a `const` function diff --git a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr index fe0351a829220..cce85772aa4da 100644 --- a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr +++ b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr @@ -8,9 +8,10 @@ LL | | let x: Option> = None; LL | | LL | | 0 LL | | }], - | |_____^ unsupported operation in generic constant, this may be supported in the future + | |_____^ blocks are not supported in generic constant | = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future error: aborting due to previous error diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs new file mode 100644 index 0000000000000..99d8e9dea910d --- /dev/null +++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs @@ -0,0 +1,16 @@ +trait Foo { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo for Bar { +//~^ERROR expected lifetime, type, or constant, found keyword `const` + fn do_x(&self) -> [u8; 3] { + [0u8; 3] + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr new file mode 100644 index 0000000000000..ddddd86ab9c06 --- /dev/null +++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-assoc.stderr @@ -0,0 +1,14 @@ +error: expected lifetime, type, or constant, found keyword `const` + --> $DIR/issue-89013-no-assoc.rs:9:10 + | +LL | impl Foo for Bar { + | ^^^^^ + | +help: the `const` keyword is only needed in the definition of the type + | +LL - impl Foo for Bar { +LL + impl Foo<3> for Bar { + | + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs new file mode 100644 index 0000000000000..19e0f38d320c4 --- /dev/null +++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs @@ -0,0 +1,17 @@ +trait Foo { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo for Bar { +//~^ ERROR cannot constrain an associated constant to a value +//~| ERROR associated type bindings are not allowed here + fn do_x(&self) -> [u8; 3] { + [0u8; 3] + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr new file mode 100644 index 0000000000000..bbca92ad63a91 --- /dev/null +++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr @@ -0,0 +1,18 @@ +error: cannot constrain an associated constant to a value + --> $DIR/issue-89013-no-kw.rs:9:10 + | +LL | impl Foo for Bar { + | -^^^- + | | | + | | ...cannot be constrained to this value + | this associated constant... + +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-89013-no-kw.rs:9:10 + | +LL | impl Foo for Bar { + | ^^^^^ associated type not allowed here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0229`. diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs new file mode 100644 index 0000000000000..0ec6762b6e282 --- /dev/null +++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.rs @@ -0,0 +1,16 @@ +trait Foo { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo for Bar { +//~^ERROR missing type to the right of `=` + fn do_x(&self) -> [u8; 3] { + [0u8; 3] + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr new file mode 100644 index 0000000000000..f0d0d90c774f8 --- /dev/null +++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013-type.stderr @@ -0,0 +1,8 @@ +error: missing type to the right of `=` + --> $DIR/issue-89013-type.rs:9:13 + | +LL | impl Foo for Bar { + | ^---- expected type, found keyword `type` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs b/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs new file mode 100644 index 0000000000000..ca1158a2f6d16 --- /dev/null +++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013.rs @@ -0,0 +1,18 @@ +trait Foo { + fn do_x(&self) -> [u8; N]; +} + +struct Bar; + +const T: usize = 42; + +impl Foo for Bar { +//~^ ERROR expected lifetime, type, or constant, found keyword `const` +//~| ERROR cannot constrain an associated constant to a value +//~| ERROR associated type bindings are not allowed here + fn do_x(&self) -> [u8; 3] { + [0u8; 3] + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr b/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr new file mode 100644 index 0000000000000..85379d3f06e4b --- /dev/null +++ b/src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr @@ -0,0 +1,30 @@ +error: expected lifetime, type, or constant, found keyword `const` + --> $DIR/issue-89013.rs:9:14 + | +LL | impl Foo for Bar { + | ^^^^^ + | +help: the `const` keyword is only needed in the definition of the type + | +LL - impl Foo for Bar { +LL + impl Foo for Bar { + | + +error: cannot constrain an associated constant to a value + --> $DIR/issue-89013.rs:9:10 + | +LL | impl Foo for Bar { + | -^^^^^^^^^- + | | | + | | ...cannot be constrained to this value + | this associated constant... + +error[E0229]: associated type bindings are not allowed here + --> $DIR/issue-89013.rs:9:10 + | +LL | impl Foo for Bar { + | ^^^^^^^^^^^ associated type not allowed here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0229`. diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs index 100faded079d5..5b9a8f8e2a279 100644 --- a/src/test/ui/consts/const-eval/const_panic.rs +++ b/src/test/ui/consts/const-eval/const_panic.rs @@ -1,4 +1,3 @@ -#![feature(const_panic)] #![allow(non_fmt_panics)] #![crate_type = "lib"] diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr index e98e4a506c0d6..3932c2bc0ac73 100644 --- a/src/test/ui/consts/const-eval/const_panic.stderr +++ b/src/test/ui/consts/const-eval/const_panic.stderr @@ -1,96 +1,96 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:7:15 + --> $DIR/const_panic.rs:6:15 | LL | const Z: () = std::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:7:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:6:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:10:16 + --> $DIR/const_panic.rs:9:16 | LL | const Z2: () = std::panic!(); - | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:10:16 + | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:9:16 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:13:15 + --> $DIR/const_panic.rs:12:15 | LL | const Y: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:13:15 + | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:12:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:16:15 + --> $DIR/const_panic.rs:15:15 | LL | const X: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:16:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:15:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:19:15 + --> $DIR/const_panic.rs:18:15 | LL | const W: () = std::panic!(MSG); - | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:19:15 + | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:18:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:22:16 + --> $DIR/const_panic.rs:21:16 | LL | const W2: () = std::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:22:16 + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:21:16 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:25:20 + --> $DIR/const_panic.rs:24:20 | LL | const Z_CORE: () = core::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:25:20 + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:24:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:28:21 + --> $DIR/const_panic.rs:27:21 | LL | const Z2_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:28:21 + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:27:21 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:31:20 + --> $DIR/const_panic.rs:30:20 | LL | const Y_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:31:20 + | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:30:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:34:20 + --> $DIR/const_panic.rs:33:20 | LL | const X_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:34:20 + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:33:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:37:20 + --> $DIR/const_panic.rs:36:20 | LL | const W_CORE: () = core::panic!(MSG); - | ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:37:20 + | ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:36:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:40:21 + --> $DIR/const_panic.rs:39:21 | LL | const W2_CORE: () = core::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:40:21 + | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:39:21 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/const-eval/const_panic_2021.rs b/src/test/ui/consts/const-eval/const_panic_2021.rs index 9b8652a776e61..4702aa2f5f01c 100644 --- a/src/test/ui/consts/const-eval/const_panic_2021.rs +++ b/src/test/ui/consts/const-eval/const_panic_2021.rs @@ -1,5 +1,4 @@ // edition:2021 -#![feature(const_panic)] #![crate_type = "lib"] const MSG: &str = "hello"; diff --git a/src/test/ui/consts/const-eval/const_panic_2021.stderr b/src/test/ui/consts/const-eval/const_panic_2021.stderr index 9eb241ae8e59d..975a07e2b0efa 100644 --- a/src/test/ui/consts/const-eval/const_panic_2021.stderr +++ b/src/test/ui/consts/const-eval/const_panic_2021.stderr @@ -1,80 +1,80 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:7:15 + --> $DIR/const_panic_2021.rs:6:15 | LL | const A: () = std::panic!("blåhaj"); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:7:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:6:15 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:10:15 + --> $DIR/const_panic_2021.rs:9:15 | LL | const B: () = std::panic!(); - | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:10:15 + | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:9:15 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:13:15 + --> $DIR/const_panic_2021.rs:12:15 | LL | const C: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:13:15 + | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:12:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:16:15 + --> $DIR/const_panic_2021.rs:15:15 | LL | const D: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:16:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:15:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:19:15 + --> $DIR/const_panic_2021.rs:18:15 | LL | const E: () = std::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:19:15 + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:18:15 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:22:20 + --> $DIR/const_panic_2021.rs:21:20 | LL | const A_CORE: () = core::panic!("shark"); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:22:20 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:21:20 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:25:20 + --> $DIR/const_panic_2021.rs:24:20 | LL | const B_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:25:20 + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:24:20 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:28:20 + --> $DIR/const_panic_2021.rs:27:20 | LL | const C_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:28:20 + | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:27:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:31:20 + --> $DIR/const_panic_2021.rs:30:20 | LL | const D_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:31:20 + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:30:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:34:20 + --> $DIR/const_panic_2021.rs:33:20 | LL | const E_CORE: () = core::panic!("{}", MSG); - | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:34:20 + | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:33:20 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs b/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs index 1ea0845c968c6..d4dc1a51d73aa 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs +++ b/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs @@ -1,6 +1,5 @@ #![crate_type = "bin"] #![feature(lang_items)] -#![feature(const_panic)] #![no_main] #![no_std] diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr index 9abf8a20b8a35..b3fa38241a4ef 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr +++ b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr @@ -1,24 +1,24 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_libcore_bin.rs:9:15 + --> $DIR/const_panic_libcore_bin.rs:8:15 | LL | const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:9:15 + | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:8:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_libcore_bin.rs:12:15 + --> $DIR/const_panic_libcore_bin.rs:11:15 | LL | const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:12:15 + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:11:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_libcore_bin.rs:15:15 + --> $DIR/const_panic_libcore_bin.rs:14:15 | LL | const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:15:15 + | ^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:14:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/const-eval/const_panic_track_caller.rs b/src/test/ui/consts/const-eval/const_panic_track_caller.rs index 7c2532673c835..9cf7a3ba7dc1c 100644 --- a/src/test/ui/consts/const-eval/const_panic_track_caller.rs +++ b/src/test/ui/consts/const-eval/const_panic_track_caller.rs @@ -1,4 +1,3 @@ -#![feature(const_panic)] #![allow(non_fmt_panics)] #![crate_type = "lib"] diff --git a/src/test/ui/consts/const-eval/const_panic_track_caller.stderr b/src/test/ui/consts/const-eval/const_panic_track_caller.stderr index 9a458db6ea24d..5c3b412d37fcc 100644 --- a/src/test/ui/consts/const-eval/const_panic_track_caller.stderr +++ b/src/test/ui/consts/const-eval/const_panic_track_caller.stderr @@ -1,14 +1,14 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_track_caller.rs:16:5 + --> $DIR/const_panic_track_caller.rs:15:5 | LL | b() | ^^^ | | - | the evaluated program panicked at 'hey', $DIR/const_panic_track_caller.rs:16:5 - | inside `c` at $DIR/const_panic_track_caller.rs:16:5 + | the evaluated program panicked at 'hey', $DIR/const_panic_track_caller.rs:15:5 + | inside `c` at $DIR/const_panic_track_caller.rs:15:5 ... LL | const X: u32 = c(); - | --- inside `X` at $DIR/const_panic_track_caller.rs:22:16 + | --- inside `X` at $DIR/const_panic_track_caller.rs:21:16 error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr index 21d3f5e7e8536..1f5bca273d3b0 100644 --- a/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr +++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops.stderr @@ -1,4 +1,4 @@ -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/const_raw_ptr_ops.rs:4:26 | LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; @@ -6,7 +6,7 @@ LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; | = note: see issue #53020 for more information -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/const_raw_ptr_ops.rs:6:27 | LL | const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 }; diff --git a/src/test/ui/consts/const-eval/feature-gate-const_panic.rs b/src/test/ui/consts/const-eval/feature-gate-const_panic.rs deleted file mode 100644 index ba5b07239a200..0000000000000 --- a/src/test/ui/consts/const-eval/feature-gate-const_panic.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn main() {} - -const Z: () = panic!("cheese"); -//~^ ERROR panicking in constants is unstable - -const Y: () = unreachable!(); -//~^ ERROR panicking in constants is unstable - -const X: () = unimplemented!(); -//~^ ERROR panicking in constants is unstable diff --git a/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr b/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr deleted file mode 100644 index 8d8e94cd4ff8a..0000000000000 --- a/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0658]: panicking in constants is unstable - --> $DIR/feature-gate-const_panic.rs:3:15 - | -LL | const Z: () = panic!("cheese"); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: panicking in constants is unstable - --> $DIR/feature-gate-const_panic.rs:6:15 - | -LL | const Y: () = unreachable!(); - | ^^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: panicking in constants is unstable - --> $DIR/feature-gate-const_panic.rs:9:15 - | -LL | const X: () = unimplemented!(); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr index 4e55b36da7392..05c3951c1284b 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr @@ -1,4 +1,4 @@ -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/match-test-ptr-null.rs:6:15 | LL | match &1 as *const i32 as usize { diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs index ab0256a986dbc..2bdf5d5476576 100644 --- a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs @@ -2,7 +2,6 @@ // Regression test for #66975 #![warn(const_err)] -#![feature(const_panic)] #![feature(never_type)] struct PrintName; diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr index f1c606a8a2e5d..9631b7748b546 100644 --- a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation of constant value failed - --> $DIR/panic-assoc-never-type.rs:11:21 + --> $DIR/panic-assoc-never-type.rs:10:21 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:11:21 + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:10:21 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs index dd875768b168f..a74d3ba297189 100644 --- a/src/test/ui/consts/const-eval/panic-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-never-type.rs @@ -1,6 +1,5 @@ // Regression test for #66975 #![warn(const_err)] -#![feature(const_panic)] #![feature(never_type)] const VOID: ! = panic!(); diff --git a/src/test/ui/consts/const-eval/panic-never-type.stderr b/src/test/ui/consts/const-eval/panic-never-type.stderr index 9b7f2181c1662..8f312d673a175 100644 --- a/src/test/ui/consts/const-eval/panic-never-type.stderr +++ b/src/test/ui/consts/const-eval/panic-never-type.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation of constant value failed - --> $DIR/panic-never-type.rs:6:17 + --> $DIR/panic-never-type.rs:5:17 | LL | const VOID: ! = panic!(); - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:6:17 + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:5:17 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/const-eval/unwind-abort.rs b/src/test/ui/consts/const-eval/unwind-abort.rs index 89b5135fd37e3..2b0e58166c254 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.rs +++ b/src/test/ui/consts/const-eval/unwind-abort.rs @@ -1,4 +1,4 @@ -#![feature(c_unwind, const_panic, const_extern_fn)] +#![feature(c_unwind, const_extern_fn)] const extern "C" fn foo() { panic!() //~ ERROR evaluation of constant value failed diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 2e52bae2b676c..2b2d23477f681 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -25,7 +25,7 @@ LL | const unsafe extern "C" fn use_float() { 1.0 + 1.0; } = note: see issue #57241 for more information = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/const-extern-fn-min-const-fn.rs:9:48 | LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } diff --git a/src/test/ui/consts/const-float-bits-conv.rs b/src/test/ui/consts/const-float-bits-conv.rs index 2dfc6de859783..c857ad6df2de2 100644 --- a/src/test/ui/consts/const-float-bits-conv.rs +++ b/src/test/ui/consts/const-float-bits-conv.rs @@ -1,7 +1,6 @@ // compile-flags: -Zmir-opt-level=0 // run-pass -#![feature(const_panic)] #![feature(const_float_bits_conv)] #![feature(const_float_classify)] diff --git a/src/test/ui/consts/const-float-classify.rs b/src/test/ui/consts/const-float-classify.rs index 5d38e032ac408..74238d0dd9231 100644 --- a/src/test/ui/consts/const-float-classify.rs +++ b/src/test/ui/consts/const-float-classify.rs @@ -1,7 +1,6 @@ // compile-flags: -Zmir-opt-level=0 // run-pass -#![feature(const_panic)] #![feature(const_float_bits_conv)] #![feature(const_float_classify)] #![feature(const_trait_impl)] diff --git a/src/test/ui/consts/const_in_pattern/issue-78057.stderr b/src/test/ui/consts/const_in_pattern/issue-78057.stderr index 0d49d0e96c854..35619594f75b8 100644 --- a/src/test/ui/consts/const_in_pattern/issue-78057.stderr +++ b/src/test/ui/consts/const_in_pattern/issue-78057.stderr @@ -7,8 +7,11 @@ LL | FOO => {}, error: unreachable pattern --> $DIR/issue-78057.rs:14:9 | +LL | FOO => {}, + | --- matches any value +LL | LL | _ => {} - | ^ + | ^ unreachable pattern | note: the lint level is defined here --> $DIR/issue-78057.rs:1:9 diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 89073f975e880..b550ac54573f0 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -11,7 +11,7 @@ error[E0658]: mutable references are not allowed in constants --> $DIR/const_let_assign3.rs:14:5 | LL | s.foo(3); - | ^ + | ^^^^^^^^ | = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable diff --git a/src/test/ui/consts/control-flow/assert.rs b/src/test/ui/consts/control-flow/assert.rs index b311cb140ccf6..9d17f65b93cab 100644 --- a/src/test/ui/consts/control-flow/assert.rs +++ b/src/test/ui/consts/control-flow/assert.rs @@ -1,14 +1,8 @@ -// Test that `assert` works when `const_panic` is enabled. - -// revisions: stock const_panic - -#![cfg_attr(const_panic, feature(const_panic))] +// Test that `assert` works in consts. const _: () = assert!(true); -//[stock]~^ ERROR panicking in constants is unstable const _: () = assert!(false); -//[stock]~^ ERROR panicking in constants is unstable -//[const_panic]~^^ ERROR evaluation of constant value failed +//~^ ERROR evaluation of constant value failed fn main() {} diff --git a/src/test/ui/consts/control-flow/assert.const_panic.stderr b/src/test/ui/consts/control-flow/assert.stderr similarity index 82% rename from src/test/ui/consts/control-flow/assert.const_panic.stderr rename to src/test/ui/consts/control-flow/assert.stderr index 1deaa937edb37..8b1ca183de98b 100644 --- a/src/test/ui/consts/control-flow/assert.const_panic.stderr +++ b/src/test/ui/consts/control-flow/assert.stderr @@ -1,8 +1,8 @@ error[E0080]: evaluation of constant value failed - --> $DIR/assert.rs:10:15 + --> $DIR/assert.rs:5:15 | LL | const _: () = assert!(false); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:10:15 + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:5:15 | = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/control-flow/assert.stock.stderr b/src/test/ui/consts/control-flow/assert.stock.stderr deleted file mode 100644 index 0caaeca4ad23f..0000000000000 --- a/src/test/ui/consts/control-flow/assert.stock.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error[E0658]: panicking in constants is unstable - --> $DIR/assert.rs:7:15 - | -LL | const _: () = assert!(true); - | ^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0658]: panicking in constants is unstable - --> $DIR/assert.rs:10:15 - | -LL | const _: () = assert!(false); - | ^^^^^^^^^^^^^^ - | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable - = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/basics.rs b/src/test/ui/consts/control-flow/basics.rs index 3a4f24bbcc339..02e5501f10cfe 100644 --- a/src/test/ui/consts/control-flow/basics.rs +++ b/src/test/ui/consts/control-flow/basics.rs @@ -2,8 +2,6 @@ // run-pass -#![feature(const_panic)] - const X: u32 = 4; const Y: u32 = 5; diff --git a/src/test/ui/consts/control-flow/short-circuit-let.rs b/src/test/ui/consts/control-flow/short-circuit-let.rs index 4dfa22b8ebaf6..8a58d06ac87bd 100644 --- a/src/test/ui/consts/control-flow/short-circuit-let.rs +++ b/src/test/ui/consts/control-flow/short-circuit-let.rs @@ -2,8 +2,6 @@ // run-pass -#![feature(const_panic)] - const X: i32 = { let mut x = 0; let _ = true && { x = 1; false }; diff --git a/src/test/ui/consts/control-flow/short-circuit.rs b/src/test/ui/consts/control-flow/short-circuit.rs index f6a0f03a4a6b8..6abe107855f80 100644 --- a/src/test/ui/consts/control-flow/short-circuit.rs +++ b/src/test/ui/consts/control-flow/short-circuit.rs @@ -3,8 +3,6 @@ // Test that both `&&` and `||` actually short-circuit. // Formerly, both sides were evaluated unconditionally -#![feature(const_panic)] - const TRUE: bool = true || panic!(); const FALSE: bool = false && panic!(); diff --git a/src/test/ui/consts/issue-17458.stderr b/src/test/ui/consts/issue-17458.stderr index aab7d798db2e7..8936c8d84ecff 100644 --- a/src/test/ui/consts/issue-17458.stderr +++ b/src/test/ui/consts/issue-17458.stderr @@ -1,4 +1,4 @@ -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/issue-17458.rs:1:28 | LL | static X: usize = unsafe { core::ptr::null::() as usize }; diff --git a/src/test/ui/consts/issue-25826.stderr b/src/test/ui/consts/issue-25826.stderr index 67d1b3ab9bed6..780edd2149fe1 100644 --- a/src/test/ui/consts/issue-25826.stderr +++ b/src/test/ui/consts/issue-25826.stderr @@ -1,4 +1,4 @@ -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/issue-25826.rs:3:30 | LL | const A: bool = unsafe { id:: as *const () < id:: as *const () }; diff --git a/src/test/ui/consts/issue-32829.rs b/src/test/ui/consts/issue-32829.rs index adfee7b925cc5..25f323b9803c8 100644 --- a/src/test/ui/consts/issue-32829.rs +++ b/src/test/ui/consts/issue-32829.rs @@ -1,5 +1,5 @@ static S : u64 = { { panic!("foo"); 0 } }; -//~^ ERROR panicking in statics is unstable +//~^ ERROR could not evaluate static initializer fn main() { println!("{:?}", S); diff --git a/src/test/ui/consts/issue-32829.stderr b/src/test/ui/consts/issue-32829.stderr index eba15e3fcca8a..4b25bf1c99e18 100644 --- a/src/test/ui/consts/issue-32829.stderr +++ b/src/test/ui/consts/issue-32829.stderr @@ -1,13 +1,11 @@ -error[E0658]: panicking in statics is unstable +error[E0080]: could not evaluate static initializer --> $DIR/issue-32829.rs:1:22 | LL | static S : u64 = { { panic!("foo"); 0 } }; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'foo', $DIR/issue-32829.rs:1:22 | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr b/src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr index 363c7b2c8e462..9a3d5716e001b 100644 --- a/src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr +++ b/src/test/ui/consts/issue-52023-array-size-pointer-cast.stderr @@ -1,4 +1,4 @@ -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/issue-52023-array-size-pointer-cast.rs:2:17 | LL | let _ = [0; (&0 as *const i32) as usize]; diff --git a/src/test/ui/consts/issue-66693-panic-in-array-len.rs b/src/test/ui/consts/issue-66693-panic-in-array-len.rs index 718a19067a6ac..fc0dcd7a44daa 100644 --- a/src/test/ui/consts/issue-66693-panic-in-array-len.rs +++ b/src/test/ui/consts/issue-66693-panic-in-array-len.rs @@ -2,8 +2,6 @@ // in a separate stage before `const`s and `statics` and so the error below is hit and // the compiler exits before generating errors for the others. -#![feature(const_panic)] - fn main() { let _ = [0i32; panic!(2f32)]; //~^ ERROR: argument to `panic!()` in a const context must have type `&str` diff --git a/src/test/ui/consts/issue-66693-panic-in-array-len.stderr b/src/test/ui/consts/issue-66693-panic-in-array-len.stderr index 2dd445b434b58..4ccbeb73c8a25 100644 --- a/src/test/ui/consts/issue-66693-panic-in-array-len.stderr +++ b/src/test/ui/consts/issue-66693-panic-in-array-len.stderr @@ -1,5 +1,5 @@ error: argument to `panic!()` in a const context must have type `&str` - --> $DIR/issue-66693-panic-in-array-len.rs:8:20 + --> $DIR/issue-66693-panic-in-array-len.rs:6:20 | LL | let _ = [0i32; panic!(2f32)]; | ^^^^^^^^^^^^ @@ -7,10 +7,10 @@ LL | let _ = [0i32; panic!(2f32)]; = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/issue-66693-panic-in-array-len.rs:12:21 + --> $DIR/issue-66693-panic-in-array-len.rs:10:21 | LL | let _ = [false; panic!()]; - | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-66693-panic-in-array-len.rs:12:21 + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-66693-panic-in-array-len.rs:10:21 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/issue-66693.rs b/src/test/ui/consts/issue-66693.rs index 77fe4417d5b10..909bef7aefbd3 100644 --- a/src/test/ui/consts/issue-66693.rs +++ b/src/test/ui/consts/issue-66693.rs @@ -1,8 +1,6 @@ // Tests that the compiler does not ICE when const-evaluating a `panic!()` invocation with a // non-`&str` argument. -#![feature(const_panic)] - const _: () = panic!(1); //~^ ERROR: argument to `panic!()` in a const context must have type `&str` diff --git a/src/test/ui/consts/issue-66693.stderr b/src/test/ui/consts/issue-66693.stderr index 3349e9813a809..3db6716a72e8b 100644 --- a/src/test/ui/consts/issue-66693.stderr +++ b/src/test/ui/consts/issue-66693.stderr @@ -1,5 +1,5 @@ error: argument to `panic!()` in a const context must have type `&str` - --> $DIR/issue-66693.rs:6:15 + --> $DIR/issue-66693.rs:4:15 | LL | const _: () = panic!(1); | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | const _: () = panic!(1); = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: argument to `panic!()` in a const context must have type `&str` - --> $DIR/issue-66693.rs:9:19 + --> $DIR/issue-66693.rs:7:19 | LL | static _FOO: () = panic!(true); | ^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | static _FOO: () = panic!(true); = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: argument to `panic!()` in a const context must have type `&str` - --> $DIR/issue-66693.rs:13:5 + --> $DIR/issue-66693.rs:11:5 | LL | panic!(&1); | ^^^^^^^^^^^ diff --git a/src/test/ui/consts/issue-76064.rs b/src/test/ui/consts/issue-76064.rs index d511f75df8129..3c153ad726e28 100644 --- a/src/test/ui/consts/issue-76064.rs +++ b/src/test/ui/consts/issue-76064.rs @@ -1,5 +1,3 @@ -// Note: non-`&str` panic arguments gained a separate error in PR #80734 -// which is why this doesn't match the issue -struct Bug([u8; panic!("panic")]); //~ ERROR panicking in constants is unstable +struct Bug([u8; panic!("panic")]); //~ ERROR evaluation of constant value failed fn main() {} diff --git a/src/test/ui/consts/issue-76064.stderr b/src/test/ui/consts/issue-76064.stderr index 875bc5c5cd330..ef9d140536a3d 100644 --- a/src/test/ui/consts/issue-76064.stderr +++ b/src/test/ui/consts/issue-76064.stderr @@ -1,13 +1,11 @@ -error[E0658]: panicking in constants is unstable - --> $DIR/issue-76064.rs:3:17 +error[E0080]: evaluation of constant value failed + --> $DIR/issue-76064.rs:1:17 | LL | struct Bug([u8; panic!("panic")]); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ the evaluated program panicked at 'panic', $DIR/issue-76064.rs:1:17 | - = note: see issue #51999 for more information - = help: add `#![feature(const_panic)]` to the crate attributes to enable = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr index 04c2febeb9768..5d8483cd111bf 100644 --- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr +++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr @@ -16,7 +16,7 @@ LL | const fn cmp(x: fn(), y: fn()) -> bool { = note: see issue #57563 for more information = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/cmp_fn_pointers.rs:4:14 | LL | unsafe { x == y } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 1e275d77bac67..fd1ab6f64bf56 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -164,7 +164,7 @@ LL | const fn foo26() -> &'static u32 { &BAR } | = help: consider extracting the value of the `static` to a `const`, and referring to that -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/min_const_fn.rs:92:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } @@ -173,7 +173,7 @@ LL | const fn foo30(x: *const u32) -> usize { x as usize } = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/min_const_fn.rs:94:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } @@ -182,7 +182,7 @@ LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/min_const_fn.rs:96:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } @@ -191,7 +191,7 @@ LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } = note: at compile-time, pointers do not have an integer value = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/min_const_fn.rs:98:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index d3017c5602a8c..778b0e55f6620 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -4,7 +4,7 @@ error: `foo` is not yet stable as a const fn LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: `foo2` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:24:26 @@ -12,7 +12,7 @@ error: `foo2` is not yet stable as a const fn LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_fn_libstd_stability.rs:29:26 @@ -35,7 +35,7 @@ error: `foo2_gated` is not yet stable as a const fn LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index 53a59467e3d20..0174cb77f332d 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -4,7 +4,7 @@ error: `foo` is not yet stable as a const fn LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 @@ -12,7 +12,7 @@ error: `foo2` is not yet stable as a const fn LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 @@ -35,7 +35,7 @@ error: `foo2_gated` is not yet stable as a const fn LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index 891c34a888a70..e90ba9b912fe1 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -4,7 +4,7 @@ error: `foo` is not yet stable as a const fn LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 @@ -12,7 +12,7 @@ error: `foo2` is not yet stable as a const fn LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: `foo2_gated` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 @@ -20,7 +20,7 @@ error: `foo2_gated` is not yet stable as a const fn LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/miri_unleashed/box.rs b/src/test/ui/consts/miri_unleashed/box.rs index 1f0b7f7e78a69..32796c67229a7 100644 --- a/src/test/ui/consts/miri_unleashed/box.rs +++ b/src/test/ui/consts/miri_unleashed/box.rs @@ -9,5 +9,5 @@ fn main() {} static TEST_BAD: &mut i32 = { &mut *(box 0) //~^ ERROR could not evaluate static initializer - //~| NOTE heap allocations + //~| NOTE calling non-const function `alloc::alloc::exchange_malloc` }; diff --git a/src/test/ui/consts/miri_unleashed/box.stderr b/src/test/ui/consts/miri_unleashed/box.stderr index 66ea9d5924dfb..05d9858dc09f0 100644 --- a/src/test/ui/consts/miri_unleashed/box.stderr +++ b/src/test/ui/consts/miri_unleashed/box.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/box.rs:10:11 | LL | &mut *(box 0) - | ^^^^^^^ "heap allocations via `box` keyword" needs an rfc before being allowed inside constants + | ^^^^^^^ calling non-const function `alloc::alloc::exchange_malloc` warning: skipping const checks | diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index 64d8540878ec2..186c5b1856baa 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -161,17 +161,11 @@ help: skipping check that does not even have a feature gate | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_panic` feature - --> $DIR/const_refers_to_static_cross_crate.rs:32:77 - | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^ help: skipping check that does not even have a feature gate --> $DIR/const_refers_to_static_cross_crate.rs:32:20 | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors; 3 warnings emitted diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index 8e793ab3f0d91..7a64abd7b9cb8 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -161,17 +161,11 @@ help: skipping check that does not even have a feature gate | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_panic` feature - --> $DIR/const_refers_to_static_cross_crate.rs:32:77 - | -LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } - | ^^^^^^^^ help: skipping check that does not even have a feature gate --> $DIR/const_refers_to_static_cross_crate.rs:32:20 | LL | unsafe { match static_cross_crate::OPT_ZERO { Some(ref u) => u, None => panic!() } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors; 3 warnings emitted diff --git a/src/test/ui/consts/not_const_clusure_in_const.rs b/src/test/ui/consts/not_const_clusure_in_const.rs new file mode 100644 index 0000000000000..fd2cfa442d3f6 --- /dev/null +++ b/src/test/ui/consts/not_const_clusure_in_const.rs @@ -0,0 +1,9 @@ +// run-pass + +const _FOO: fn() -> String = || "foo".into(); + +pub fn bar() -> fn() -> String { + || "bar".into() +} + +fn main(){} diff --git a/src/test/ui/consts/ptr_comparisons.rs b/src/test/ui/consts/ptr_comparisons.rs index 9b5fd18f818b0..971b7c3cb179a 100644 --- a/src/test/ui/consts/ptr_comparisons.rs +++ b/src/test/ui/consts/ptr_comparisons.rs @@ -5,7 +5,6 @@ // normalize-stderr-64bit: "size 8" -> "size $$WORD" #![feature( - const_panic, core_intrinsics, const_raw_ptr_comparison, const_ptr_offset, diff --git a/src/test/ui/consts/ptr_comparisons.stderr b/src/test/ui/consts/ptr_comparisons.stderr index a28ae521d5b9a..48cd5da213f3d 100644 --- a/src/test/ui/consts/ptr_comparisons.stderr +++ b/src/test/ui/consts/ptr_comparisons.stderr @@ -7,19 +7,19 @@ LL | unsafe { intrinsics::offset(self, count) } | pointer arithmetic failed: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - ::: $DIR/ptr_comparisons.rs:61:34 + ::: $DIR/ptr_comparisons.rs:60:34 | LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) }; - | ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:61:34 + | ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:60:34 error[E0080]: evaluation of constant value failed - --> $DIR/ptr_comparisons.rs:64:33 + --> $DIR/ptr_comparisons.rs:63:33 | LL | unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: alloc3 has size $WORD, so pointer to 1000 bytes starting at offset 0 is out-of-bounds error: any use of this value will cause an error - --> $DIR/ptr_comparisons.rs:68:27 + --> $DIR/ptr_comparisons.rs:67:27 | LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 }; | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- @@ -31,7 +31,7 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + = note: for more information, see issue #71800 error: any use of this value will cause an error - --> $DIR/ptr_comparisons.rs:73:27 + --> $DIR/ptr_comparisons.rs:72:27 | LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 }; | --------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--- diff --git a/src/test/ui/consts/ptr_is_null.rs b/src/test/ui/consts/ptr_is_null.rs index 324f59443f721..8babb68585dea 100644 --- a/src/test/ui/consts/ptr_is_null.rs +++ b/src/test/ui/consts/ptr_is_null.rs @@ -1,7 +1,7 @@ // compile-flags: --crate-type=lib // check-pass -#![feature(const_ptr_is_null, const_panic)] +#![feature(const_ptr_is_null)] const FOO: &usize = &42; diff --git a/src/test/ui/consts/unwind-abort.rs b/src/test/ui/consts/unwind-abort.rs index d9d0b91011d9a..6c94fc7b98b75 100644 --- a/src/test/ui/consts/unwind-abort.rs +++ b/src/test/ui/consts/unwind-abort.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(c_unwind, const_panic, const_extern_fn)] +#![feature(c_unwind, const_extern_fn)] // We don't unwind in const-eval anyways. const extern "C" fn foo() { diff --git a/src/test/ui/crate-method-reexport-grrrrrrr.rs b/src/test/ui/crate-method-reexport-grrrrrrr.rs index eefcf7738ada7..55e05cfb203b9 100644 --- a/src/test/ui/crate-method-reexport-grrrrrrr.rs +++ b/src/test/ui/crate-method-reexport-grrrrrrr.rs @@ -1,8 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - // This is a regression test that the metadata for the // name_pool::methods impl in the other crate is reachable from this // crate. @@ -14,7 +12,7 @@ extern crate crate_method_reexport_grrrrrrr2; pub fn main() { use crate_method_reexport_grrrrrrr2::rust::add; use crate_method_reexport_grrrrrrr2::rust::cx; - let x: Box<_> = box (); + let x: Box<_> = Box::new(()); x.cx(); let y = (); y.add("hi".to_string()); diff --git a/src/test/ui/cross-crate/auxiliary/cci_nested_lib.rs b/src/test/ui/cross-crate/auxiliary/cci_nested_lib.rs index 379ed076611f4..23d76ef3656e1 100644 --- a/src/test/ui/cross-crate/auxiliary/cci_nested_lib.rs +++ b/src/test/ui/cross-crate/auxiliary/cci_nested_lib.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - use std::cell::RefCell; pub struct Entry { @@ -37,7 +35,7 @@ pub fn new_int_alist() -> alist { fn eq_int(a: isize, b: isize) -> bool { a == b } return alist { eq_fn: eq_int, - data: box RefCell::new(Vec::new()), + data: Box::new(RefCell::new(Vec::new())), }; } @@ -47,6 +45,6 @@ pub fn new_int_alist_2() -> alist { fn eq_int(a: isize, b: isize) -> bool { a == b } return alist { eq_fn: eq_int, - data: box RefCell::new(Vec::new()), + data: Box::new(RefCell::new(Vec::new())), }; } diff --git a/src/test/ui/cross-crate/cci_borrow.rs b/src/test/ui/cross-crate/cci_borrow.rs index 605a166ffa356..fee6b5d03a9e5 100644 --- a/src/test/ui/cross-crate/cci_borrow.rs +++ b/src/test/ui/cross-crate/cci_borrow.rs @@ -1,13 +1,11 @@ // run-pass // aux-build:cci_borrow_lib.rs -#![feature(box_syntax)] - extern crate cci_borrow_lib; use cci_borrow_lib::foo; pub fn main() { - let p: Box<_> = box 22; + let p: Box<_> = Box::new(22); let r = foo(&*p); println!("r={}", r); assert_eq!(r, 22); diff --git a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs index a0ee3ad31e697..978c1994800c9 100644 --- a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs +++ b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs @@ -1,7 +1,8 @@ // Test that when a trait impl changes, fns whose body uses that trait // must also be recompiled. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-assoc-type-codegen +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(warnings)] diff --git a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr index 4e659648e9edc..cdc268cff992e 100644 --- a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr +++ b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr @@ -1,5 +1,5 @@ error: OK - --> $DIR/dep-graph-assoc-type-codegen.rs:28:5 + --> $DIR/dep-graph-assoc-type-codegen.rs:29:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/dep-graph/dep-graph-caller-callee.rs b/src/test/ui/dep-graph/dep-graph-caller-callee.rs index c95ea53650b47..4a3a8bb6bf939 100644 --- a/src/test/ui/dep-graph/dep-graph-caller-callee.rs +++ b/src/test/ui/dep-graph/dep-graph-caller-callee.rs @@ -1,7 +1,8 @@ // Test that immediate callers have to change when callee changes, but // not callers' callers. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-caller-callee +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr index 3d968aa3ea68a..4d06dc7f3ed37 100644 --- a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr +++ b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr @@ -1,11 +1,11 @@ error: OK - --> $DIR/dep-graph-caller-callee.rs:20:5 + --> $DIR/dep-graph-caller-callee.rs:21:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `x` to `typeck` - --> $DIR/dep-graph-caller-callee.rs:31:5 + --> $DIR/dep-graph-caller-callee.rs:32:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/dep-graph/dep-graph-struct-signature.rs b/src/test/ui/dep-graph/dep-graph-struct-signature.rs index 50a670b877238..fcf9f6387102f 100644 --- a/src/test/ui/dep-graph/dep-graph-struct-signature.rs +++ b/src/test/ui/dep-graph/dep-graph-struct-signature.rs @@ -1,7 +1,8 @@ // Test cases where a changing struct appears in the signature of fns // and methods. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-struct-signature +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr index b81aeabab7ff1..60bfbe94a8a8b 100644 --- a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr +++ b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr @@ -1,131 +1,131 @@ error: no path from `WillChange` to `type_of` - --> $DIR/dep-graph-struct-signature.rs:27:5 + --> $DIR/dep-graph-struct-signature.rs:28:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `associated_item` - --> $DIR/dep-graph-struct-signature.rs:28:5 + --> $DIR/dep-graph-struct-signature.rs:29:5 | LL | #[rustc_then_this_would_need(associated_item)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `trait_def` - --> $DIR/dep-graph-struct-signature.rs:29:5 + --> $DIR/dep-graph-struct-signature.rs:30:5 | LL | #[rustc_then_this_would_need(trait_def)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:31:9 + --> $DIR/dep-graph-struct-signature.rs:32:9 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:35:5 + --> $DIR/dep-graph-struct-signature.rs:36:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:36:5 + --> $DIR/dep-graph-struct-signature.rs:37:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:39:5 + --> $DIR/dep-graph-struct-signature.rs:40:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:40:5 + --> $DIR/dep-graph-struct-signature.rs:41:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:45:5 + --> $DIR/dep-graph-struct-signature.rs:46:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:47:9 + --> $DIR/dep-graph-struct-signature.rs:48:9 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:48:9 + --> $DIR/dep-graph-struct-signature.rs:49:9 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:52:5 + --> $DIR/dep-graph-struct-signature.rs:53:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:54:9 + --> $DIR/dep-graph-struct-signature.rs:55:9 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:55:9 + --> $DIR/dep-graph-struct-signature.rs:56:9 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:60:9 + --> $DIR/dep-graph-struct-signature.rs:61:9 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-struct-signature.rs:62:9 + --> $DIR/dep-graph-struct-signature.rs:63:9 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `type_of` - --> $DIR/dep-graph-struct-signature.rs:67:5 + --> $DIR/dep-graph-struct-signature.rs:68:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `type_of` - --> $DIR/dep-graph-struct-signature.rs:74:5 + --> $DIR/dep-graph-struct-signature.rs:75:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `fn_sig` - --> $DIR/dep-graph-struct-signature.rs:76:9 + --> $DIR/dep-graph-struct-signature.rs:77:9 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `fn_sig` - --> $DIR/dep-graph-struct-signature.rs:80:5 + --> $DIR/dep-graph-struct-signature.rs:81:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `fn_sig` - --> $DIR/dep-graph-struct-signature.rs:83:5 + --> $DIR/dep-graph-struct-signature.rs:84:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `WillChange` to `typeck` - --> $DIR/dep-graph-struct-signature.rs:84:5 + --> $DIR/dep-graph-struct-signature.rs:85:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs index c0a6617316b8d..5da8df5706464 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs @@ -1,7 +1,8 @@ // Test that adding an impl to a trait `Foo` DOES affect functions // that only use `Bar` if they have methods in common. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits-same-method +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr index ae3d725e1c051..6f56cbc8dd7ae 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr @@ -1,11 +1,11 @@ error: OK - --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:32:5 + --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:33:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `x::` to `typeck` - --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:41:5 + --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:42:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs index 56e9762ddb26c..0331e75b2fe8d 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs @@ -1,7 +1,8 @@ // Test that adding an impl to a trait `Foo` does not affect functions // that only use `Bar`, so long as they do not have methods in common. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(warnings)] diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr index 4823927477fe0..08f382cc024c7 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr @@ -1,11 +1,11 @@ error: no path from `x::` to `typeck` - --> $DIR/dep-graph-trait-impl-two-traits.rs:31:5 + --> $DIR/dep-graph-trait-impl-two-traits.rs:32:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `x::` to `typeck` - --> $DIR/dep-graph-trait-impl-two-traits.rs:40:5 + --> $DIR/dep-graph-trait-impl-two-traits.rs:41:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl.rs b/src/test/ui/dep-graph/dep-graph-trait-impl.rs index 3bbe3e745ca69..19002965b9372 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl.rs @@ -1,7 +1,8 @@ // Test that when a trait impl changes, fns whose body uses that trait // must also be recompiled. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(warnings)] diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl.stderr b/src/test/ui/dep-graph/dep-graph-trait-impl.stderr index f8ead80894276..bfee6d5c87b34 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl.stderr +++ b/src/test/ui/dep-graph/dep-graph-trait-impl.stderr @@ -1,29 +1,29 @@ error: OK - --> $DIR/dep-graph-trait-impl.rs:27:5 + --> $DIR/dep-graph-trait-impl.rs:28:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-trait-impl.rs:32:5 + --> $DIR/dep-graph-trait-impl.rs:33:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-trait-impl.rs:37:5 + --> $DIR/dep-graph-trait-impl.rs:38:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-trait-impl.rs:42:5 + --> $DIR/dep-graph-trait-impl.rs:43:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `x::` to `typeck` - --> $DIR/dep-graph-trait-impl.rs:55:5 + --> $DIR/dep-graph-trait-impl.rs:56:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/dep-graph/dep-graph-type-alias.rs b/src/test/ui/dep-graph/dep-graph-type-alias.rs index 5c5e24693a4f5..0e1b3db192518 100644 --- a/src/test/ui/dep-graph/dep-graph-type-alias.rs +++ b/src/test/ui/dep-graph/dep-graph-type-alias.rs @@ -1,6 +1,7 @@ // Test that changing what a `type` points to does not go unnoticed. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-type-alias +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/dep-graph/dep-graph-type-alias.stderr b/src/test/ui/dep-graph/dep-graph-type-alias.stderr index e698ce8f628b4..c59cf8014c3d1 100644 --- a/src/test/ui/dep-graph/dep-graph-type-alias.stderr +++ b/src/test/ui/dep-graph/dep-graph-type-alias.stderr @@ -1,71 +1,71 @@ error: no path from `TypeAlias` to `type_of` - --> $DIR/dep-graph-type-alias.rs:17:1 + --> $DIR/dep-graph-type-alias.rs:18:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:19:5 + --> $DIR/dep-graph-type-alias.rs:20:5 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `TypeAlias` to `type_of` - --> $DIR/dep-graph-type-alias.rs:24:1 + --> $DIR/dep-graph-type-alias.rs:25:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:27:9 + --> $DIR/dep-graph-type-alias.rs:28:9 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `TypeAlias` to `type_of` - --> $DIR/dep-graph-type-alias.rs:33:1 + --> $DIR/dep-graph-type-alias.rs:34:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:35:5 + --> $DIR/dep-graph-type-alias.rs:36:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: no path from `TypeAlias` to `type_of` - --> $DIR/dep-graph-type-alias.rs:41:1 + --> $DIR/dep-graph-type-alias.rs:42:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:43:5 + --> $DIR/dep-graph-type-alias.rs:44:5 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:44:5 + --> $DIR/dep-graph-type-alias.rs:45:5 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:48:1 + --> $DIR/dep-graph-type-alias.rs:49:1 | LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:51:1 + --> $DIR/dep-graph-type-alias.rs:52:1 | LL | #[rustc_then_this_would_need(fn_sig)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK - --> $DIR/dep-graph-type-alias.rs:52:1 + --> $DIR/dep-graph-type-alias.rs:53:1 | LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/dep-graph/dep-graph-variance-alias.rs b/src/test/ui/dep-graph/dep-graph-variance-alias.rs index 4f1612759559d..008434696d63d 100644 --- a/src/test/ui/dep-graph/dep-graph-variance-alias.rs +++ b/src/test/ui/dep-graph/dep-graph-variance-alias.rs @@ -1,7 +1,8 @@ // Test that changing what a `type` points to does not go unnoticed // by the variance analysis. -// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-variance-alias +// incremental +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/src/test/ui/dep-graph/dep-graph-variance-alias.stderr b/src/test/ui/dep-graph/dep-graph-variance-alias.stderr index 2422cb9bb2f52..554ff455a2073 100644 --- a/src/test/ui/dep-graph/dep-graph-variance-alias.stderr +++ b/src/test/ui/dep-graph/dep-graph-variance-alias.stderr @@ -1,5 +1,5 @@ error: OK - --> $DIR/dep-graph-variance-alias.rs:18:1 + --> $DIR/dep-graph-variance-alias.rs:19:1 | LL | #[rustc_then_this_would_need(variances_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/deref.rs b/src/test/ui/deref.rs index cad4ede06a561..0d4e08ad95476 100644 --- a/src/test/ui/deref.rs +++ b/src/test/ui/deref.rs @@ -1,9 +1,7 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let x: Box = box 10; + let x: Box = Box::new(10); let _y: isize = *x; } diff --git a/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr index abcba6da8aaee..19d2425ff23f7 100644 --- a/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr @@ -7,8 +7,16 @@ LL | #[derive(PartialEq)] LL | x: Error | ^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:9:6 @@ -19,8 +27,16 @@ LL | #[derive(PartialEq)] LL | x: Error | ^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to 2 previous errors diff --git a/src/test/ui/derives/derives-span-PartialEq-enum.stderr b/src/test/ui/derives/derives-span-PartialEq-enum.stderr index cdb40c39f169c..419832817ca18 100644 --- a/src/test/ui/derives/derives-span-PartialEq-enum.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-enum.stderr @@ -7,8 +7,16 @@ LL | #[derive(PartialEq)] LL | Error | ^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-enum.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-enum.rs:9:6 @@ -19,8 +27,16 @@ LL | #[derive(PartialEq)] LL | Error | ^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-enum.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to 2 previous errors diff --git a/src/test/ui/derives/derives-span-PartialEq-struct.stderr b/src/test/ui/derives/derives-span-PartialEq-struct.stderr index 4cf8851a098bc..0000f882542ae 100644 --- a/src/test/ui/derives/derives-span-PartialEq-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-struct.stderr @@ -7,8 +7,16 @@ LL | struct Struct { LL | x: Error | ^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-struct.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-struct.rs:8:5 @@ -19,8 +27,16 @@ LL | struct Struct { LL | x: Error | ^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-struct.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to 2 previous errors diff --git a/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr b/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr index 66bc168735389..07fa900a8c829 100644 --- a/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialEq-tuple-struct.stderr @@ -7,8 +7,16 @@ LL | struct Struct( LL | Error | ^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-tuple-struct.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `Error` --> $DIR/derives-span-PartialEq-tuple-struct.rs:8:5 @@ -19,8 +27,16 @@ LL | struct Struct( LL | Error | ^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `Error` +note: an implementation of `PartialEq<_>` might be missing for `Error` + --> $DIR/derives-span-PartialEq-tuple-struct.rs:4:1 + | +LL | struct Error; + | ^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `Error` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to 2 previous errors diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr index 2538b5533a6d6..1d0554ad0477f 100644 --- a/src/test/ui/derives/deriving-copyclone.stderr +++ b/src/test/ui/derives/deriving-copyclone.stderr @@ -2,10 +2,8 @@ error[E0277]: the trait bound `C: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:31:13 | LL | is_copy(B { a: 1, b: C }); - | ------- ^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Copy` - | | help: consider borrowing here: `&B { a: 1, b: C }` + | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy` + | | | required by a bound introduced by this call | note: required because of the requirements on the impl of `Copy` for `B` @@ -19,15 +17,17 @@ note: required by a bound in `is_copy` LL | fn is_copy(_: T) {} | ^^^^ required by this bound in `is_copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | is_copy(&B { a: 1, b: C }); + | + error[E0277]: the trait bound `C: Clone` is not satisfied --> $DIR/deriving-copyclone.rs:32:14 | LL | is_clone(B { a: 1, b: C }); - | -------- ^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Clone` - | | help: consider borrowing here: `&B { a: 1, b: C }` + | -------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone` + | | | required by a bound introduced by this call | note: required because of the requirements on the impl of `Clone` for `B` @@ -41,15 +41,17 @@ note: required by a bound in `is_clone` LL | fn is_clone(_: T) {} | ^^^^^ required by this bound in `is_clone` = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | is_clone(&B { a: 1, b: C }); + | + error[E0277]: the trait bound `D: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:35:13 | LL | is_copy(B { a: 1, b: D }); - | ------- ^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Copy` - | | help: consider borrowing here: `&B { a: 1, b: D }` + | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy` + | | | required by a bound introduced by this call | note: required because of the requirements on the impl of `Copy` for `B` @@ -63,6 +65,10 @@ note: required by a bound in `is_copy` LL | fn is_copy(_: T) {} | ^^^^ required by this bound in `is_copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | is_copy(&B { a: 1, b: D }); + | + error: aborting due to 3 previous errors diff --git a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr index b97f87da4bfce..e322db97fab49 100644 --- a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr +++ b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr @@ -7,8 +7,16 @@ LL | struct E { LL | x: NoCloneOrEq | ^^^^^^^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq` +note: an implementation of `PartialEq<_>` might be missing for `NoCloneOrEq` + --> $DIR/deriving-no-inner-impl-error-message.rs:1:1 + | +LL | struct NoCloneOrEq; + | ^^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `NoCloneOrEq` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0369]: binary operation `!=` cannot be applied to type `NoCloneOrEq` --> $DIR/deriving-no-inner-impl-error-message.rs:5:5 @@ -19,8 +27,16 @@ LL | struct E { LL | x: NoCloneOrEq | ^^^^^^^^^^^^^^ | - = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq` +note: an implementation of `PartialEq<_>` might be missing for `NoCloneOrEq` + --> $DIR/deriving-no-inner-impl-error-message.rs:1:1 + | +LL | struct NoCloneOrEq; + | ^^^^^^^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `NoCloneOrEq` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error[E0277]: the trait bound `NoCloneOrEq: Clone` is not satisfied --> $DIR/deriving-no-inner-impl-error-message.rs:10:5 diff --git a/src/test/ui/deriving/deriving-default-box.rs b/src/test/ui/deriving/deriving-default-box.rs index 237dbfaa05674..b71e114961388 100644 --- a/src/test/ui/deriving/deriving-default-box.rs +++ b/src/test/ui/deriving/deriving-default-box.rs @@ -1,6 +1,4 @@ // run-pass -#![feature(box_syntax)] - use std::default::Default; #[derive(Default)] diff --git a/src/test/ui/deriving/issue-89188-gat-hrtb.rs b/src/test/ui/deriving/issue-89188-gat-hrtb.rs new file mode 100644 index 0000000000000..abd85a616a4ad --- /dev/null +++ b/src/test/ui/deriving/issue-89188-gat-hrtb.rs @@ -0,0 +1,39 @@ +// check-pass + +#![feature(generic_associated_types)] + +trait CallWithShim: Sized { + type Shim<'s> + where + Self: 's; +} + +#[derive(Clone)] +struct ShimMethod(pub &'static dyn for<'s> Fn(&'s mut T::Shim<'s>)); + +trait CallWithShim2: Sized { + type Shim; +} + +struct S<'s>(&'s ()); + +#[derive(Clone)] +struct ShimMethod2(pub &'static dyn for<'s> Fn(&'s mut T::Shim>)); + +trait Trait<'s, 't, 'u> {} + +#[derive(Clone)] +struct ShimMethod3( + pub &'static dyn for<'s> Fn( + &'s mut T::Shim Fn(&'s mut T::Shim Trait<'s, 't, 'u>>)>, + ), +); + +trait Trait2 { + type As; +} + +#[derive(Clone)] +struct ShimMethod4(pub &'static dyn for<'s> Fn(&'s mut T::As)); + +pub fn main() {} diff --git a/src/test/ui/destructure-trait-ref.rs b/src/test/ui/destructure-trait-ref.rs index fdc9bbab73067..50b64aeebf0ef 100644 --- a/src/test/ui/destructure-trait-ref.rs +++ b/src/test/ui/destructure-trait-ref.rs @@ -2,11 +2,11 @@ // reference work properly. #![feature(box_patterns)] -#![feature(box_syntax)] trait T { fn foo(&self) {} } impl T for isize {} + fn main() { // For an expression of the form: // @@ -25,7 +25,7 @@ fn main() { // n == m let &x = &1isize as &dyn T; //~ ERROR type `&dyn T` cannot be dereferenced let &&x = &(&1isize as &dyn T); //~ ERROR type `&dyn T` cannot be dereferenced - let box x = box 1isize as Box; + let box x = Box::new(1isize) as Box; //~^ ERROR type `Box` cannot be dereferenced // n > m @@ -37,7 +37,7 @@ fn main() { //~^ ERROR mismatched types //~| expected trait object `dyn T` //~| found reference `&_` - let box box x = box 1isize as Box; + let box box x = Box::new(1isize) as Box; //~^ ERROR mismatched types //~| expected trait object `dyn T` //~| found struct `Box<_>` diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index fb43ca760b8c0..302917ca02e00 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -13,7 +13,7 @@ LL | let &&x = &(&1isize as &dyn T); error[E0033]: type `Box` cannot be dereferenced --> $DIR/destructure-trait-ref.rs:28:9 | -LL | let box x = box 1isize as Box; +LL | let box x = Box::new(1isize) as Box; | ^^^^^ type `Box` cannot be dereferenced error[E0308]: mismatched types @@ -43,8 +43,8 @@ LL | let &&&x = &(&1isize as &dyn T); error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:40:13 | -LL | let box box x = box 1isize as Box; - | ^^^^^ ------------------------ this expression has type `Box` +LL | let box box x = Box::new(1isize) as Box; + | ^^^^^ ------------------------------ this expression has type `Box` | | | expected trait object `dyn T`, found struct `Box` | diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr index a81324b99e586..7b9788ca0fef3 100644 --- a/src/test/ui/destructuring-assignment/note-unsupported.stderr +++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr @@ -99,7 +99,22 @@ LL | S { x: a, y: b } += s; | | | cannot use `+=` on type `S` | - = note: an implementation of `std::ops::AddAssign` might be missing for `S` +note: an implementation of `AddAssign<_>` might be missing for `S` + --> $DIR/note-unsupported.rs:1:1 + | +LL | struct S { x: u8, y: u8 } + | ^^^^^^^^ must implement `AddAssign<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait AddAssign { +LL | | /// Performs the `+=` operation. +LL | | /// +LL | | /// # Example +... | +LL | | fn add_assign(&mut self, rhs: Rhs); +LL | | } + | |_^ error[E0067]: invalid left-hand side of assignment --> $DIR/note-unsupported.rs:17:22 diff --git a/src/test/ui/did_you_mean/issue-34126.stderr b/src/test/ui/did_you_mean/issue-34126.stderr index 666172197ce9b..0503fac4a6680 100644 --- a/src/test/ui/did_you_mean/issue-34126.stderr +++ b/src/test/ui/did_you_mean/issue-34126.stderr @@ -19,8 +19,9 @@ error[E0502]: cannot borrow `self` as mutable because it is also borrowed as imm --> $DIR/issue-34126.rs:6:18 | LL | self.run(&mut self); - | ---- --- ^^^^^^^^^ mutable borrow occurs here - | | | + | ---------^^^^^^^^^- + | | | | + | | | mutable borrow occurs here | | immutable borrow later used by call | immutable borrow occurs here diff --git a/src/test/ui/did_you_mean/issue-35937.stderr b/src/test/ui/did_you_mean/issue-35937.stderr index 1f578d18a1ce5..9562d94509ea8 100644 --- a/src/test/ui/did_you_mean/issue-35937.stderr +++ b/src/test/ui/did_you_mean/issue-35937.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `f.v` as mutable, as `f` is not declared as mutable LL | let f = Foo { v: Vec::new() }; | - help: consider changing this to be mutable: `mut f` LL | f.v.push("cat".to_string()); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable error[E0594]: cannot assign to `s.x`, as `s` is not declared as mutable --> $DIR/issue-35937.rs:16:5 diff --git a/src/test/ui/did_you_mean/issue-38147-1.stderr b/src/test/ui/did_you_mean/issue-38147-1.stderr index 6efac371c028e..dd193458b3726 100644 --- a/src/test/ui/did_you_mean/issue-38147-1.stderr +++ b/src/test/ui/did_you_mean/issue-38147-1.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` referenc LL | fn f(&self) { | ----- help: consider changing this to be a mutable reference: `&mut self` LL | self.s.push('x'); - | ^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-38147-2.stderr b/src/test/ui/did_you_mean/issue-38147-2.stderr index cb4981089310a..8bf5c76977da5 100644 --- a/src/test/ui/did_you_mean/issue-38147-2.stderr +++ b/src/test/ui/did_you_mean/issue-38147-2.stderr @@ -5,7 +5,7 @@ LL | s: &'a String | ---------- help: consider changing this to be mutable: `&'a mut String` ... LL | self.s.push('x'); - | ^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-38147-3.stderr b/src/test/ui/did_you_mean/issue-38147-3.stderr index 67782578a2c64..0e1e42261c42b 100644 --- a/src/test/ui/did_you_mean/issue-38147-3.stderr +++ b/src/test/ui/did_you_mean/issue-38147-3.stderr @@ -5,7 +5,7 @@ LL | s: &'a String | ---------- help: consider changing this to be mutable: `&'a mut String` ... LL | self.s.push('x'); - | ^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-38147-4.stderr b/src/test/ui/did_you_mean/issue-38147-4.stderr index db3e6b8942646..a2d162f08a173 100644 --- a/src/test/ui/did_you_mean/issue-38147-4.stderr +++ b/src/test/ui/did_you_mean/issue-38147-4.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `*f.s` as mutable, as it is behind a `&` reference LL | fn f(x: usize, f: &Foo) { | ---- help: consider changing this to be a mutable reference: `&mut Foo<'_>` LL | f.s.push('x'); - | ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-40823.stderr b/src/test/ui/did_you_mean/issue-40823.stderr index 73473406a9ace..67703a1497f50 100644 --- a/src/test/ui/did_you_mean/issue-40823.stderr +++ b/src/test/ui/did_you_mean/issue-40823.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `*buf` as mutable, as it is behind a `&` reference LL | let mut buf = &[1, 2, 3, 4]; | ------------- help: consider changing this to be a mutable reference: `&mut [1, 2, 3, 4]` LL | buf.iter_mut(); - | ^^^ `buf` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^ `buf` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index fa8bee184a74f..247fe4b5b07bd 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `K: Send` LL | is_send::(); | ^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit`) note: required because it appears within the type `J` --> $DIR/recursion_limit.rs:24:9 | diff --git a/src/test/ui/did_you_mean/recursion_limit_deref.stderr b/src/test/ui/did_you_mean/recursion_limit_deref.stderr index 8339cc291cf30..658207a47c9ab 100644 --- a/src/test/ui/did_you_mean/recursion_limit_deref.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_deref.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `J` LL | let x: &Bottom = &t; | ^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit_deref`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit_deref`) error[E0308]: mismatched types --> $DIR/recursion_limit_deref.rs:50:22 diff --git a/src/test/ui/did_you_mean/recursion_limit_macro.stderr b/src/test/ui/did_you_mean/recursion_limit_macro.stderr index 0c6fdebd50955..609488e4f2f93 100644 --- a/src/test/ui/did_you_mean/recursion_limit_macro.stderr +++ b/src/test/ui/did_you_mean/recursion_limit_macro.stderr @@ -7,7 +7,7 @@ LL | ($t:tt $($tail:tt)*) => { recurse!($($tail)*) }; LL | recurse!(0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9); | -------------------------------------------------- in this macro invocation | - = help: consider adding a `#![recursion_limit="20"]` attribute to your crate (`recursion_limit_macro`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit_macro`) = note: this error originates in the macro `recurse` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/drop/drop-on-empty-block-exit.rs b/src/test/ui/drop/drop-on-empty-block-exit.rs index 1747bf029aa33..ef3a90a53a6a0 100644 --- a/src/test/ui/drop/drop-on-empty-block-exit.rs +++ b/src/test/ui/drop/drop-on-empty-block-exit.rs @@ -2,11 +2,9 @@ // pretty-expanded FIXME #23616 #![allow(non_camel_case_types)] -#![feature(box_syntax)] - enum t { foo(Box), } pub fn main() { - let tt = t::foo(box 10); + let tt = t::foo(Box::new(10)); match tt { t::foo(_z) => { } } } diff --git a/src/test/ui/drop/drop-struct-as-object.rs b/src/test/ui/drop/drop-struct-as-object.rs index 1bc3b4c157ca8..377027a4fc5f2 100644 --- a/src/test/ui/drop/drop-struct-as-object.rs +++ b/src/test/ui/drop/drop-struct-as-object.rs @@ -5,8 +5,6 @@ // Test that destructor on a struct runs successfully after the struct // is boxed and converted to an object. -#![feature(box_syntax)] - static mut value: usize = 0; struct Cat { @@ -29,7 +27,7 @@ impl Drop for Cat { pub fn main() { { - let x = box Cat {name: 22}; + let x = Box::new(Cat {name: 22}); let nyan: Box = x as Box; } unsafe { diff --git a/src/test/ui/drop/drop-trait-enum.rs b/src/test/ui/drop/drop-trait-enum.rs index aec46575f97fc..4ab8f733ad75a 100644 --- a/src/test/ui/drop/drop-trait-enum.rs +++ b/src/test/ui/drop/drop-trait-enum.rs @@ -4,8 +4,6 @@ #![allow(unused_variables)] // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; use std::sync::mpsc::{channel, Sender}; @@ -57,7 +55,7 @@ pub fn main() { let (sender, receiver) = channel(); { - let v = Foo::NestedVariant(box 42, SendOnDrop { sender: sender.clone() }, sender); + let v = Foo::NestedVariant(Box::new(42), SendOnDrop { sender: sender.clone() }, sender); } assert_eq!(receiver.recv().unwrap(), Message::DestructorRan); assert_eq!(receiver.recv().unwrap(), Message::Dropped); @@ -74,10 +72,10 @@ pub fn main() { let (sender, receiver) = channel(); let t = { thread::spawn(move|| { - let mut v = Foo::NestedVariant(box 42, SendOnDrop { + let mut v = Foo::NestedVariant(Box::new(42), SendOnDrop { sender: sender.clone() }, sender.clone()); - v = Foo::NestedVariant(box 42, + v = Foo::NestedVariant(Box::new(42), SendOnDrop { sender: sender.clone() }, sender.clone()); v = Foo::SimpleVariant(sender.clone()); diff --git a/src/test/ui/dropck/drop-with-active-borrows-1.stderr b/src/test/ui/dropck/drop-with-active-borrows-1.stderr index 7fed27adaff2b..8d6a7f3721f0f 100644 --- a/src/test/ui/dropck/drop-with-active-borrows-1.stderr +++ b/src/test/ui/dropck/drop-with-active-borrows-1.stderr @@ -2,7 +2,7 @@ error[E0505]: cannot move out of `a` because it is borrowed --> $DIR/drop-with-active-borrows-1.rs:4:10 | LL | let b: Vec<&str> = a.lines().collect(); - | - borrow of `a` occurs here + | --------- borrow of `a` occurs here LL | drop(a); | ^ move out of `a` occurs here LL | for s in &b { diff --git a/src/test/ui/dropck/drop-with-active-borrows-2.stderr b/src/test/ui/dropck/drop-with-active-borrows-2.stderr index ffec9306b7771..24650dfac02d9 100644 --- a/src/test/ui/dropck/drop-with-active-borrows-2.stderr +++ b/src/test/ui/dropck/drop-with-active-borrows-2.stderr @@ -2,7 +2,7 @@ error[E0515]: cannot return value referencing local variable `raw_lines` --> $DIR/drop-with-active-borrows-2.rs:3:5 | LL | raw_lines.iter().map(|l| l.trim()).collect() - | ---------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ----------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | returns a value referencing data owned by the current function | `raw_lines` is borrowed here diff --git a/src/test/ui/duplicate_doc_alias.rs b/src/test/ui/duplicate_doc_alias.rs new file mode 100644 index 0000000000000..a564ab64532b7 --- /dev/null +++ b/src/test/ui/duplicate_doc_alias.rs @@ -0,0 +1,9 @@ +#![deny(unused_attributes)] + +#[doc(alias = "A")] +#[doc(alias = "A")] //~ ERROR +#[doc(alias = "B")] +#[doc(alias("B"))] //~ ERROR +pub struct Foo; + +fn main() {} diff --git a/src/test/ui/duplicate_doc_alias.stderr b/src/test/ui/duplicate_doc_alias.stderr new file mode 100644 index 0000000000000..4b2dd1f8eb68e --- /dev/null +++ b/src/test/ui/duplicate_doc_alias.stderr @@ -0,0 +1,24 @@ +error: doc alias is duplicated + --> $DIR/duplicate_doc_alias.rs:4:7 + | +LL | #[doc(alias = "A")] + | ----------- first defined here +LL | #[doc(alias = "A")] + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/duplicate_doc_alias.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: doc alias is duplicated + --> $DIR/duplicate_doc_alias.rs:6:13 + | +LL | #[doc(alias = "B")] + | ----------- first defined here +LL | #[doc(alias("B"))] + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs b/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs index 70bcc3de07d29..c1e45215ad8c4 100644 --- a/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs +++ b/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs @@ -2,7 +2,6 @@ #![allow(type_alias_bounds)] #![allow(unused_features)] -#![feature(box_syntax)] #![feature(unsized_tuple_coercion)] type Fat = (isize, &'static str, T); diff --git a/src/test/ui/dynamically-sized-types/dst-tuple.rs b/src/test/ui/dynamically-sized-types/dst-tuple.rs index f70a45a1b3574..604ac51129010 100644 --- a/src/test/ui/dynamically-sized-types/dst-tuple.rs +++ b/src/test/ui/dynamically-sized-types/dst-tuple.rs @@ -1,7 +1,6 @@ // run-pass #![allow(type_alias_bounds)] -#![feature(box_syntax)] #![feature(unsized_tuple_coercion)] type Fat = (isize, &'static str, T); @@ -109,7 +108,7 @@ pub fn main() { assert_eq!((*f2)[1], 2); // Nested Box. - let f1 : Box> = box (5, "some str", [1, 2, 3]); + let f1 : Box> = Box::new((5, "some str", [1, 2, 3])); foo(&*f1); let f2 : Box> = f1; foo(&*f2); diff --git a/src/test/ui/enum-discriminant/niche.rs b/src/test/ui/enum-discriminant/niche.rs index b3694bb4216c6..8d30610504f7d 100644 --- a/src/test/ui/enum-discriminant/niche.rs +++ b/src/test/ui/enum-discriminant/niche.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(const_panic)] - //! Make sure that we read and write enum discriminants correctly for corner cases caused //! by layout optimizations. diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr index 83718a1e27371..e296217026570 100644 --- a/src/test/ui/error-codes/E0034.stderr +++ b/src/test/ui/error-codes/E0034.stderr @@ -16,12 +16,12 @@ LL | fn foo() {} | ^^^^^^^^ help: disambiguate the associated function for candidate #1 | -LL | Trait1::foo() - | ~~~~~~~~ +LL | ::foo() + | ~~~~~~~~~~~~~~~~~~ help: disambiguate the associated function for candidate #2 | -LL | Trait2::foo() - | ~~~~~~~~ +LL | ::foo() + | ~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0055.stderr b/src/test/ui/error-codes/E0055.stderr index 1b8c5760e65bf..a52c90962355f 100644 --- a/src/test/ui/error-codes/E0055.stderr +++ b/src/test/ui/error-codes/E0055.stderr @@ -4,7 +4,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | ref_foo.foo(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="8"]` attribute to your crate (`E0055`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "8"]` attribute to your crate (`E0055`) error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0161.edition.stderr b/src/test/ui/error-codes/E0161.edition.stderr index 6beb29c57d527..1060675cd45f4 100644 --- a/src/test/ui/error-codes/E0161.edition.stderr +++ b/src/test/ui/error-codes/E0161.edition.stderr @@ -2,7 +2,7 @@ error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be --> $DIR/E0161.rs:29:5 | LL | x.f(); - | ^ + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0161.migrate.stderr b/src/test/ui/error-codes/E0161.migrate.stderr index 6beb29c57d527..1060675cd45f4 100644 --- a/src/test/ui/error-codes/E0161.migrate.stderr +++ b/src/test/ui/error-codes/E0161.migrate.stderr @@ -2,7 +2,7 @@ error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be --> $DIR/E0161.rs:29:5 | LL | x.f(); - | ^ + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0161.nll.stderr b/src/test/ui/error-codes/E0161.nll.stderr index 6beb29c57d527..1060675cd45f4 100644 --- a/src/test/ui/error-codes/E0161.nll.stderr +++ b/src/test/ui/error-codes/E0161.nll.stderr @@ -2,7 +2,7 @@ error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be --> $DIR/E0161.rs:29:5 | LL | x.f(); - | ^ + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0161.zflags.stderr b/src/test/ui/error-codes/E0161.zflags.stderr index 6beb29c57d527..1060675cd45f4 100644 --- a/src/test/ui/error-codes/E0161.zflags.stderr +++ b/src/test/ui/error-codes/E0161.zflags.stderr @@ -2,7 +2,7 @@ error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be --> $DIR/E0161.rs:29:5 | LL | x.f(); - | ^ + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0225.stderr b/src/test/ui/error-codes/E0225.stderr index 435a2c9396273..a4b33a0b7b408 100644 --- a/src/test/ui/error-codes/E0225.stderr +++ b/src/test/ui/error-codes/E0225.stderr @@ -6,7 +6,7 @@ LL | let _: Box; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -23,7 +23,7 @@ LL | let _: Box; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0275.stderr b/src/test/ui/error-codes/E0275.stderr index 15d851aa9340d..e13f0961a18cf 100644 --- a/src/test/ui/error-codes/E0275.stderr +++ b/src/test/ui/error-codes/E0275.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `Bar Foo for T where Bar: Foo {} | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`E0275`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`E0275`) note: required because of the requirements on the impl of `Foo` for `Bar>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/E0275.rs:5:9 | diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr index 674cc69645029..ea17e95a719af 100644 --- a/src/test/ui/error-codes/E0395.stderr +++ b/src/test/ui/error-codes/E0395.stderr @@ -1,4 +1,4 @@ -error: pointers cannot be reliably compared during const eval. +error: pointers cannot be reliably compared during const eval --> $DIR/E0395.rs:4:29 | LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; diff --git a/src/test/ui/error-codes/E0407.stderr b/src/test/ui/error-codes/E0407.stderr index 567fc879040d3..6f6d1ff6a8f41 100644 --- a/src/test/ui/error-codes/E0407.stderr +++ b/src/test/ui/error-codes/E0407.stderr @@ -2,7 +2,10 @@ error[E0407]: method `b` is not a member of trait `Foo` --> $DIR/E0407.rs:9:5 | LL | fn b() {} - | ^^^^^^^^^ not a member of trait `Foo` + | ^^^-^^^^^ + | | | + | | help: there is an associated function with a similar name: `a` + | not a member of trait `Foo` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0499.stderr b/src/test/ui/error-codes/E0499.stderr index d56baf7227201..af5a1e186332f 100644 --- a/src/test/ui/error-codes/E0499.stderr +++ b/src/test/ui/error-codes/E0499.stderr @@ -7,7 +7,7 @@ LL | let mut a = &mut i; | ^^^^^^ second mutable borrow occurs here LL | a.use_mut(); LL | x.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0502.nll.stderr b/src/test/ui/error-codes/E0502.nll.stderr index e5671ee49e654..a3c7ef7618989 100644 --- a/src/test/ui/error-codes/E0502.nll.stderr +++ b/src/test/ui/error-codes/E0502.nll.stderr @@ -6,7 +6,7 @@ LL | let ref y = a; LL | bar(a); | ^ mutable borrow occurs here LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0502.stderr b/src/test/ui/error-codes/E0502.stderr index cade6d71852f8..94cc89754db5f 100644 --- a/src/test/ui/error-codes/E0502.stderr +++ b/src/test/ui/error-codes/E0502.stderr @@ -6,7 +6,7 @@ LL | let ref y = a; LL | bar(a); | ^^^^^^ mutable borrow occurs here LL | y.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0503.stderr b/src/test/ui/error-codes/E0503.stderr index 106dda2bc2260..fafe363eb47a6 100644 --- a/src/test/ui/error-codes/E0503.stderr +++ b/src/test/ui/error-codes/E0503.stderr @@ -6,7 +6,7 @@ LL | let _borrow = &mut value; LL | let _sum = value + 1; | ^^^^^ use of borrowed `value` LL | _borrow.use_mut(); - | ------- borrow later used here + | ----------------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0505.stderr b/src/test/ui/error-codes/E0505.stderr index 4d9d1ef121c69..bd3f37f54e0a8 100644 --- a/src/test/ui/error-codes/E0505.stderr +++ b/src/test/ui/error-codes/E0505.stderr @@ -6,7 +6,7 @@ LL | let _ref_to_val: &Value = &x; LL | eat(x); | ^ move out of `x` occurs here LL | _ref_to_val.use_ref(); - | ----------- borrow later used here + | --------------------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0507.stderr b/src/test/ui/error-codes/E0507.stderr index cd5e467944bcd..3837e206169d4 100644 --- a/src/test/ui/error-codes/E0507.stderr +++ b/src/test/ui/error-codes/E0507.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of dereference of `Ref<'_, TheDarkKnight>` --> $DIR/E0507.rs:12:5 | LL | x.borrow().nothing_is_true(); - | ^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `TheDarkKnight`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr index e5647ee6d0968..d082b6c10cc2a 100644 --- a/src/test/ui/error-codes/E0605.stderr +++ b/src/test/ui/error-codes/E0605.stderr @@ -12,8 +12,9 @@ LL | v as &u8; | help: consider borrowing the value | -LL | &*v as &u8; - | ++ +LL - v as &u8; +LL + &*v; + | error: aborting due to 2 previous errors diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 89a9d965de24a..b8cd7b7464ae3 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -36,7 +36,22 @@ error[E0600]: cannot apply unary operator `!` to type `Question` LL | !Question::Yes; | ^^^^^^^^^^^^^^ cannot apply unary operator `!` | - = note: an implementation of `std::ops::Not` might be missing for `Question` +note: an implementation of `Not` might be missing for `Question` + --> $DIR/error-festival.rs:1:1 + | +LL | enum Question { + | ^^^^^^^^^^^^^ must implement `Not` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait Not { +LL | | /// The resulting type after applying the `!` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn not(self) -> Self::Output; +LL | | } + | |_^ error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/error-festival.rs:25:5 diff --git a/src/test/ui/expr-block-generic-unique1.rs b/src/test/ui/expr-block-generic-unique1.rs index d081cb2be7ee3..14603a2c71fc4 100644 --- a/src/test/ui/expr-block-generic-unique1.rs +++ b/src/test/ui/expr-block-generic-unique1.rs @@ -1,6 +1,5 @@ // run-pass #![allow(unused_braces)] -#![feature(box_syntax)] fn test_generic(expected: Box, eq: F) where T: Clone, F: FnOnce(Box, Box) -> bool { let actual: Box = { expected.clone() }; @@ -13,7 +12,7 @@ fn test_box() { println!("{}", *b2); return *b1 == *b2; } - test_generic::(box true, compare_box); + test_generic::(Box::new(true), compare_box); } pub fn main() { test_box(); } diff --git a/src/test/ui/expr-block-generic-unique2.rs b/src/test/ui/expr-block-generic-unique2.rs index 9362eb86fc309..7879c144b1092 100644 --- a/src/test/ui/expr-block-generic-unique2.rs +++ b/src/test/ui/expr-block-generic-unique2.rs @@ -1,6 +1,5 @@ // run-pass #![allow(unused_braces)] -#![feature(box_syntax)] fn test_generic(expected: T, eq: F) where T: Clone, F: FnOnce(T, T) -> bool { let actual: T = { expected.clone() }; @@ -9,7 +8,7 @@ fn test_generic(expected: T, eq: F) where T: Clone, F: FnOnce(T, T) -> boo fn test_vec() { fn compare_vec(v1: Box, v2: Box) -> bool { return v1 == v2; } - test_generic::, _>(box 1, compare_vec); + test_generic::, _>(Box::new(1), compare_vec); } pub fn main() { test_vec(); } diff --git a/src/test/ui/expr-block-unique.rs b/src/test/ui/expr-block-unique.rs index eff3fd3a15152..5fa11ad1283b9 100644 --- a/src/test/ui/expr-block-unique.rs +++ b/src/test/ui/expr-block-unique.rs @@ -1,5 +1,4 @@ // run-pass #![allow(unused_braces)] -#![feature(box_syntax)] -pub fn main() { let x: Box<_> = { box 100 }; assert_eq!(*x, 100); } +pub fn main() { let x: Box<_> = { Box::new(100) }; assert_eq!(*x, 100); } diff --git a/src/test/ui/expr-if-unique.rs b/src/test/ui/expr-if-unique.rs index 509d069d40fec..86232683549b6 100644 --- a/src/test/ui/expr-if-unique.rs +++ b/src/test/ui/expr-if-unique.rs @@ -1,10 +1,8 @@ // run-pass -#![feature(box_syntax)] - // Tests for if as expressions returning boxed types fn test_box() { - let rs: Box<_> = if true { box 100 } else { box 101 }; + let rs: Box<_> = if true { Box::new(100) } else { Box::new(101) }; assert_eq!(*rs, 100); } diff --git a/src/test/ui/feature-gates/feature-gate-closure_track_caller.rs b/src/test/ui/feature-gates/feature-gate-closure_track_caller.rs new file mode 100644 index 0000000000000..a8d63a8145a2a --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-closure_track_caller.rs @@ -0,0 +1,7 @@ +#![feature(stmt_expr_attributes)] +#![feature(generators)] + +fn main() { + let _closure = #[track_caller] || {}; //~ `#[track_caller]` on closures + let _generator = #[track_caller] || { yield; }; //~ `#[track_caller]` on closures +} diff --git a/src/test/ui/feature-gates/feature-gate-closure_track_caller.stderr b/src/test/ui/feature-gates/feature-gate-closure_track_caller.stderr new file mode 100644 index 0000000000000..ed63d74fe4d4e --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-closure_track_caller.stderr @@ -0,0 +1,21 @@ +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/feature-gate-closure_track_caller.rs:5:20 + | +LL | let _closure = #[track_caller] || {}; + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error[E0658]: `#[track_caller]` on closures is currently unstable + --> $DIR/feature-gate-closure_track_caller.rs:6:22 + | +LL | let _generator = #[track_caller] || { yield; }; + | ^^^^^^^^^^^^^^^ + | + = note: see issue #87417 for more information + = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-try_reserve.rs b/src/test/ui/feature-gates/feature-gate-try_reserve.rs deleted file mode 100644 index a19dd58da11b3..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-try_reserve.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let v = Vec::new(); - v.try_reserve(10); //~ ERROR: use of unstable library feature 'try_reserve' -} diff --git a/src/test/ui/feature-gates/feature-gate-try_reserve.stderr b/src/test/ui/feature-gates/feature-gate-try_reserve.stderr deleted file mode 100644 index 4da9a23a1bd5f..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-try_reserve.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: use of unstable library feature 'try_reserve': new API - --> $DIR/feature-gate-try_reserve.rs:3:7 - | -LL | v.try_reserve(10); - | ^^^^^^^^^^^ - | - = note: see issue #48043 for more information - = help: add `#![feature(try_reserve)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/fmt/issue-89173.rs b/src/test/ui/fmt/issue-89173.rs new file mode 100644 index 0000000000000..96277d4d0d9d7 --- /dev/null +++ b/src/test/ui/fmt/issue-89173.rs @@ -0,0 +1,14 @@ +// Regression test for #89173: Make sure a helpful note is issued for +// printf-style format strings using `*` to specify the width. + +fn main() { + let num = 0x0abcde; + let width = 6; + print!("%0*x", width, num); + //~^ ERROR: multiple unused formatting arguments + //~| NOTE: multiple missing formatting specifiers + //~| NOTE: argument never used + //~| NOTE: argument never used + //~| NOTE: format specifiers use curly braces, and you have to use a positional or named parameter for the width + //~| NOTE: printf formatting not supported +} diff --git a/src/test/ui/fmt/issue-89173.stderr b/src/test/ui/fmt/issue-89173.stderr new file mode 100644 index 0000000000000..7b21e0a4fc896 --- /dev/null +++ b/src/test/ui/fmt/issue-89173.stderr @@ -0,0 +1,18 @@ +error: multiple unused formatting arguments + --> $DIR/issue-89173.rs:7:20 + | +LL | print!("%0*x", width, num); + | ------ ^^^^^ ^^^ argument never used + | | | + | | argument never used + | multiple missing formatting specifiers + | +note: format specifiers use curly braces, and you have to use a positional or named parameter for the width + --> $DIR/issue-89173.rs:7:13 + | +LL | print!("%0*x", width, num); + | ^^^^ + = note: printf formatting not supported; see the documentation for `std::fmt` + +error: aborting due to previous error + diff --git a/src/test/ui/fn/fn-trait-formatting.rs b/src/test/ui/fn/fn-trait-formatting.rs index 0c389e1dc57a9..636ac7107e62a 100644 --- a/src/test/ui/fn/fn-trait-formatting.rs +++ b/src/test/ui/fn/fn-trait-formatting.rs @@ -1,17 +1,17 @@ -#![feature(box_syntax)] - fn needs_fn(x: F) where F: Fn(isize) -> isize {} + + fn main() { - let _: () = (box |_: isize| {}) as Box; + let _: () = Box::new(|_: isize| {}) as Box; //~^ ERROR mismatched types //~| expected unit type `()` //~| found struct `Box` - let _: () = (box |_: isize, isize| {}) as Box; + let _: () = Box::new(|_: isize, isize| {}) as Box; //~^ ERROR mismatched types //~| expected unit type `()` //~| found struct `Box` - let _: () = (box || -> isize { unimplemented!() }) as Box isize>; + let _: () = Box::new(|| -> isize { unimplemented!() }) as Box isize>; //~^ ERROR mismatched types //~| expected unit type `()` //~| found struct `Box isize>` diff --git a/src/test/ui/fn/fn-trait-formatting.stderr b/src/test/ui/fn/fn-trait-formatting.stderr index f9fb3a0ef267d..ea88e401bed87 100644 --- a/src/test/ui/fn/fn-trait-formatting.stderr +++ b/src/test/ui/fn/fn-trait-formatting.stderr @@ -1,8 +1,8 @@ error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:6:17 | -LL | let _: () = (box |_: isize| {}) as Box; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` +LL | let _: () = Box::new(|_: isize| {}) as Box; + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | @@ -12,8 +12,8 @@ LL | let _: () = (box |_: isize| {}) as Box; error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:10:17 | -LL | let _: () = (box |_: isize, isize| {}) as Box; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` +LL | let _: () = Box::new(|_: isize, isize| {}) as Box; + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | @@ -23,8 +23,8 @@ LL | let _: () = (box |_: isize, isize| {}) as Box; error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:14:17 | -LL | let _: () = (box || -> isize { unimplemented!() }) as Box isize>; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` +LL | let _: () = Box::new(|| -> isize { unimplemented!() }) as Box isize>; + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | @@ -41,7 +41,7 @@ LL | needs_fn(1); | = help: the trait `Fn<(isize,)>` is not implemented for `{integer}` note: required by a bound in `needs_fn` - --> $DIR/fn-trait-formatting.rs:3:31 + --> $DIR/fn-trait-formatting.rs:1:31 | LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} | ^^^^^^^^^^^^^^^^^^ required by this bound in `needs_fn` diff --git a/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs b/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs index 6fecb4e76da32..afc77355ab00a 100644 --- a/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs +++ b/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs @@ -2,8 +2,6 @@ // This test verifies that temporaries created for `while`'s and `if` // conditions are dropped after the condition is evaluated. -#![feature(box_syntax)] - struct Temporary; static mut DROPPED: isize = 0; @@ -18,7 +16,7 @@ impl Temporary { fn do_stuff(&self) -> bool {true} } -fn borrow() -> Box { box Temporary } +fn borrow() -> Box { Box::new(Temporary) } pub fn main() { diff --git a/src/test/ui/future-incompatible-lint-group.stderr b/src/test/ui/future-incompatible-lint-group.stderr index cb9be88c9ee44..d822847a7a589 100644 --- a/src/test/ui/future-incompatible-lint-group.stderr +++ b/src/test/ui/future-incompatible-lint-group.stderr @@ -1,4 +1,4 @@ -warning: anonymous parameters are deprecated and will be removed in the next edition. +warning: anonymous parameters are deprecated and will be removed in the next edition --> $DIR/future-incompatible-lint-group.rs:7:10 | LL | fn f(u8) {} diff --git a/src/test/ui/gated-bad-feature.stderr b/src/test/ui/gated-bad-feature.stderr index 79e59f76311fd..a8ec9391523c7 100644 --- a/src/test/ui/gated-bad-feature.stderr +++ b/src/test/ui/gated-bad-feature.stderr @@ -20,13 +20,13 @@ error: malformed `feature` attribute input --> $DIR/gated-bad-feature.rs:5:1 | LL | #![feature] - | ^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]` + | ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name1, ...)]` error: malformed `feature` attribute input --> $DIR/gated-bad-feature.rs:6:1 | LL | #![feature = "foo"] - | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]` + | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name1, ...)]` error: aborting due to 5 previous errors diff --git a/src/test/ui/generator/dropck-resume.stderr b/src/test/ui/generator/dropck-resume.stderr index ecf92e7e3ae79..b0756eb5589b7 100644 --- a/src/test/ui/generator/dropck-resume.stderr +++ b/src/test/ui/generator/dropck-resume.stderr @@ -5,7 +5,7 @@ LL | let z = &mut y; | ------ mutable borrow occurs here ... LL | r = y.as_ref().unwrap(); - | ^ immutable borrow occurs here + | ^^^^^^^^^^ immutable borrow occurs here LL | LL | } | - mutable borrow might be used here, when `g` is dropped and runs the destructor for generator diff --git a/src/test/ui/generator/dropck.stderr b/src/test/ui/generator/dropck.stderr index 8bb860f288f10..7bb188352d7a2 100644 --- a/src/test/ui/generator/dropck.stderr +++ b/src/test/ui/generator/dropck.stderr @@ -2,7 +2,7 @@ error[E0597]: `*cell` does not live long enough --> $DIR/dropck.rs:10:40 | LL | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); - | ^^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^^^^ borrowed value does not live long enough ... LL | } | - diff --git a/src/test/ui/generator/resume-arg-late-bound.nll.stderr b/src/test/ui/generator/resume-arg-late-bound.nll.stderr index 25bc6afc550b3..b5144c607a880 100644 --- a/src/test/ui/generator/resume-arg-late-bound.nll.stderr +++ b/src/test/ui/generator/resume-arg-late-bound.nll.stderr @@ -6,6 +6,11 @@ LL | test(gen); | = note: expected type `for<'a> Generator<&'a mut bool>` found type `Generator<&mut bool>` +note: the lifetime requirement is introduced here + --> $DIR/resume-arg-late-bound.rs:8:17 + | +LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/generator/yield-in-box.rs b/src/test/ui/generator/yield-in-box.rs index 65f368df9cb33..dd6fa7c151aa7 100644 --- a/src/test/ui/generator/yield-in-box.rs +++ b/src/test/ui/generator/yield-in-box.rs @@ -1,8 +1,10 @@ // run-pass - // Test that box-statements with yields in them work. -#![feature(generators, box_syntax)] +#![feature(generators, box_syntax, generator_trait)] +use std::pin::Pin; +use std::ops::Generator; +use std::ops::GeneratorState; fn main() { let x = 0i32; @@ -15,4 +17,8 @@ fn main() { _t => {} } }; + + let mut g = |_| box yield; + assert_eq!(Pin::new(&mut g).resume(1), GeneratorState::Yielded(())); + assert_eq!(Pin::new(&mut g).resume(2), GeneratorState::Complete(box 2)); } diff --git a/src/test/ui/generator/yield-in-box.stderr b/src/test/ui/generator/yield-in-box.stderr index 24de18edb0f8c..7602e803945dc 100644 --- a/src/test/ui/generator/yield-in-box.stderr +++ b/src/test/ui/generator/yield-in-box.stderr @@ -1,5 +1,5 @@ warning: unused generator that must be used - --> $DIR/yield-in-box.rs:9:5 + --> $DIR/yield-in-box.rs:11:5 | LL | / || { LL | | let y = 2u32; diff --git a/src/test/ui/generics/generic-alias-unique.rs b/src/test/ui/generics/generic-alias-unique.rs index 76a184d8d256a..fc138398634d5 100644 --- a/src/test/ui/generics/generic-alias-unique.rs +++ b/src/test/ui/generics/generic-alias-unique.rs @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] fn id(t: T) -> T { return t; } pub fn main() { - let expected: Box<_> = box 100; + let expected: Box<_> = Box::new(100); let actual = id::>(expected.clone()); println!("{}", *actual); assert_eq!(*expected, *actual); diff --git a/src/test/ui/generics/generic-exterior-unique.rs b/src/test/ui/generics/generic-exterior-unique.rs index 9b3e1ee02a2af..10d87f9f43d0d 100644 --- a/src/test/ui/generics/generic-exterior-unique.rs +++ b/src/test/ui/generics/generic-exterior-unique.rs @@ -1,9 +1,8 @@ // run-pass -#![feature(box_syntax)] struct Recbox {x: Box} -fn reclift(t: T) -> Recbox { return Recbox {x: box t}; } +fn reclift(t: T) -> Recbox { return Recbox { x: Box::new(t) }; } pub fn main() { let foo: isize = 17; diff --git a/src/test/ui/generics/generic-fn-unique.rs b/src/test/ui/generics/generic-fn-unique.rs index 6cda1c3dc15e1..7e246bce9a10c 100644 --- a/src/test/ui/generics/generic-fn-unique.rs +++ b/src/test/ui/generics/generic-fn-unique.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(box_syntax)] fn f(x: Box) -> Box { return x; } -pub fn main() { let x = f(box 3); println!("{}", *x); } +pub fn main() { + let x = f(Box::new(3)); + println!("{}", *x); +} diff --git a/src/test/ui/generics/generic-object.rs b/src/test/ui/generics/generic-object.rs index 870ff980ec64d..851424a11b5c1 100644 --- a/src/test/ui/generics/generic-object.rs +++ b/src/test/ui/generics/generic-object.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] trait Foo { fn get(&self) -> T; @@ -16,7 +15,7 @@ impl Foo for S { } pub fn main() { - let x = box S { x: 1 }; + let x = Box::new(S { x: 1 }); let y = x as Box>; assert_eq!(y.get(), 1); } diff --git a/src/test/ui/generics/generic-recursive-tag.rs b/src/test/ui/generics/generic-recursive-tag.rs index e1875f0abbe61..74f5b701d98a5 100644 --- a/src/test/ui/generics/generic-recursive-tag.rs +++ b/src/test/ui/generics/generic-recursive-tag.rs @@ -1,13 +1,12 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] enum list { cons(Box, Box>), nil, } pub fn main() { let _a: list = - list::cons::(box 10, - box list::cons::(box 12, - box list::cons::(box 13, - box list::nil::))); + list::cons::(Box::new(10), + Box::new(list::cons::(Box::new(12), + Box::new(list::cons::(Box::new(13), + Box::new(list::nil::)))))); } diff --git a/src/test/ui/generics/generic-tag.rs b/src/test/ui/generics/generic-tag.rs index 74ef4eeba8ab7..67f2ccdde34a1 100644 --- a/src/test/ui/generics/generic-tag.rs +++ b/src/test/ui/generics/generic-tag.rs @@ -5,11 +5,10 @@ // pretty-expanded FIXME #23616 #![allow(unused_variables)] -#![feature(box_syntax)] enum option { some(Box), none, } pub fn main() { - let mut a: option = option::some::(box 10); + let mut a: option = option::some::(Box::new(10)); a = option::none::; } diff --git a/src/test/ui/generics/generic-unique.rs b/src/test/ui/generics/generic-unique.rs index d36504c75dd9c..2f34712ecfbf3 100644 --- a/src/test/ui/generics/generic-unique.rs +++ b/src/test/ui/generics/generic-unique.rs @@ -1,10 +1,9 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct Triple { x: T, y: T, z: T } -fn box_it(x: Triple) -> Box> { return box x; } +fn box_it(x: Triple) -> Box> { return Box::new(x); } pub fn main() { let x: Box> = box_it::(Triple{x: 1, y: 2, z: 3}); diff --git a/src/test/ui/hashmap/hashmap-iter-value-lifetime.nll.stderr b/src/test/ui/hashmap/hashmap-iter-value-lifetime.nll.stderr deleted file mode 100644 index 312a91adca678..0000000000000 --- a/src/test/ui/hashmap/hashmap-iter-value-lifetime.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as immutable - --> $DIR/hashmap-iter-value-lifetime.rs:7:5 - | -LL | let (_, thing) = my_stuff.iter().next().unwrap(); - | -------- immutable borrow occurs here -LL | -LL | my_stuff.clear(); - | ^^^^^^^^ mutable borrow occurs here -LL | -LL | println!("{}", *thing); - | ------ immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/hashmap/hashmap-iter-value-lifetime.stderr b/src/test/ui/hashmap/hashmap-iter-value-lifetime.stderr index f7626b13bad36..0724fec905524 100644 --- a/src/test/ui/hashmap/hashmap-iter-value-lifetime.stderr +++ b/src/test/ui/hashmap/hashmap-iter-value-lifetime.stderr @@ -2,7 +2,7 @@ error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as --> $DIR/hashmap-iter-value-lifetime.rs:7:5 | LL | let (_, thing) = my_stuff.iter().next().unwrap(); - | -------- immutable borrow occurs here + | --------------- immutable borrow occurs here LL | LL | my_stuff.clear(); | ^^^^^^^^^^^^^^^^ mutable borrow occurs here diff --git a/src/test/ui/hashmap/hashmap-lifetimes.nll.stderr b/src/test/ui/hashmap/hashmap-lifetimes.nll.stderr deleted file mode 100644 index aa8e890c168dc..0000000000000 --- a/src/test/ui/hashmap/hashmap-lifetimes.nll.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as immutable - --> $DIR/hashmap-lifetimes.rs:6:5 - | -LL | let mut it = my_stuff.iter(); - | -------- immutable borrow occurs here -LL | my_stuff.insert(1, 43); - | ^^^^^^^^ mutable borrow occurs here -LL | it; - | -- immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/hashmap/hashmap-lifetimes.stderr b/src/test/ui/hashmap/hashmap-lifetimes.stderr index 497c7d1216cd9..d1bcd53ae3b80 100644 --- a/src/test/ui/hashmap/hashmap-lifetimes.stderr +++ b/src/test/ui/hashmap/hashmap-lifetimes.stderr @@ -2,7 +2,7 @@ error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as --> $DIR/hashmap-lifetimes.rs:6:5 | LL | let mut it = my_stuff.iter(); - | -------- immutable borrow occurs here + | --------------- immutable borrow occurs here LL | my_stuff.insert(1, 43); | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | it; diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs new file mode 100644 index 0000000000000..fffb54f86ca03 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.rs @@ -0,0 +1,32 @@ +trait BufferMut {} +struct Ctx(D); + +trait BufferUdpStateContext {} +impl BufferUdpStateContext for C {} + +trait StackContext +where + Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>, +{ + type Dispatcher; +} + +trait TimerContext { + type Handler; +} +impl TimerContext for C +where + C: StackContext, + //~^ ERROR: is not satisfied [E0277] +{ + type Handler = Ctx; + //~^ ERROR: is not satisfied [E0277] +} + +struct EthernetWorker(C) +where + Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>; +impl EthernetWorker {} +//~^ ERROR: is not satisfied [E0277] + +fn main() {} diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr new file mode 100644 index 0000000000000..7f45fb83cef08 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-89118.stderr @@ -0,0 +1,63 @@ +error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied + --> $DIR/issue-89118.rs:19:8 + | +LL | C: StackContext, + | ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` + | +note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` + --> $DIR/issue-89118.rs:5:23 + | +LL | impl BufferUdpStateContext for C {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ ^ +note: required by a bound in `StackContext` + --> $DIR/issue-89118.rs:9:14 + | +LL | trait StackContext + | ------------ required by a bound in this +LL | where +LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext` + +error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied + --> $DIR/issue-89118.rs:22:20 + | +LL | type Handler = Ctx; + | ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` + | +note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` + --> $DIR/issue-89118.rs:5:23 + | +LL | impl BufferUdpStateContext for C {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ ^ +note: required by a bound in `StackContext` + --> $DIR/issue-89118.rs:9:14 + | +LL | trait StackContext + | ------------ required by a bound in this +LL | where +LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StackContext` + +error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied + --> $DIR/issue-89118.rs:29:9 + | +LL | impl EthernetWorker {} + | ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()` + | +note: required because of the requirements on the impl of `for<'a> BufferUdpStateContext<&'a ()>` for `Ctx<()>` + --> $DIR/issue-89118.rs:5:23 + | +LL | impl BufferUdpStateContext for C {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ ^ +note: required by a bound in `EthernetWorker` + --> $DIR/issue-89118.rs:28:14 + | +LL | struct EthernetWorker(C) + | -------------- required by a bound in this +LL | where +LL | Ctx<()>: for<'a> BufferUdpStateContext<&'a ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `EthernetWorker` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr index 439a113ef3811..87d826021b703 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.nll.stderr @@ -8,8 +8,8 @@ LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u3 LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } | |_____________________________________________- in this macro invocation | - = note: expected enum `Option fn(&'r u32, &'s u32) -> &'r u32>` - found enum `Option fn(&'r u32, &'r u32) -> &'r u32>` + = note: expected enum `Option fn(&'a u32, &'b u32) -> &'a u32>` + found enum `Option fn(&'a u32, &'a u32) -> &'a u32>` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr index 61b3f0ca2847c..bd97f6f090646 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.nll.stderr @@ -8,7 +8,7 @@ LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), LL | | fn(&'x u32)) } | |______________- in this macro invocation | - = note: expected enum `Option fn(&'r u32)>` + = note: expected enum `Option fn(&'a u32)>` found enum `Option` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr index 75e2ba58f33fb..874909bf486c8 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.nll.stderr @@ -8,8 +8,8 @@ LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } | |__________________________________- in this macro invocation | - = note: expected enum `Option fn(Inv<'r>, Inv<'s>)>` - found enum `Option fn(Inv<'r>, Inv<'r>)>` + = note: expected enum `Option fn(Inv<'a>, Inv<'b>)>` + found enum `Option fn(Inv<'a>, Inv<'a>)>` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0308]: mismatched types @@ -22,8 +22,8 @@ LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } | |__________________________________- in this macro invocation | - = note: expected enum `Option fn(Inv<'r>, Inv<'s>)>` - found enum `Option fn(Inv<'r>, Inv<'r>)>` + = note: expected enum `Option fn(Inv<'a>, Inv<'b>)>` + found enum `Option fn(Inv<'a>, Inv<'a>)>` = note: this error originates in the macro `check` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr b/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr index 70d5b3c2ec58c..fa391ecba8a95 100644 --- a/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr +++ b/src/test/ui/hrtb/hrtb-debruijn-in-receiver.stderr @@ -2,9 +2,9 @@ error[E0499]: cannot borrow `foo` as mutable more than once at a time --> $DIR/hrtb-debruijn-in-receiver.rs:17:5 | LL | foo.insert(); - | --- first mutable borrow occurs here + | ------------ first mutable borrow occurs here LL | foo.insert(); - | ^^^ + | ^^^^^^^^^^^^ | | | second mutable borrow occurs here | first borrow later used here diff --git a/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr index 17d59bb321a45..a5770431eaff1 100644 --- a/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr +++ b/src/test/ui/hrtb/hrtb-just-for-static.nll.stderr @@ -14,8 +14,6 @@ LL | fn give_some<'a>() { | -- lifetime `'a` defined here LL | want_hrtb::<&'a u32>() | ^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: implementation of `Foo` is not general enough --> $DIR/hrtb-just-for-static.rs:30:5 diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr index aefe3cdfd6487..68da46d46bd14 100644 --- a/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr +++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.nll.stderr @@ -54,8 +54,6 @@ LL | fn foo_hrtb_bar_not<'b, T>(mut t: T) ... LL | foo_hrtb_bar_not(&mut t); | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'static` - | - = help: consider replacing `'b` with `'static` error: implementation of `Bar` is not general enough --> $DIR/hrtb-perfect-forwarding.rs:43:5 diff --git a/src/test/ui/hygiene/assoc_item_ctxt.stderr b/src/test/ui/hygiene/assoc_item_ctxt.stderr index 6e4fecf0ce4b2..517b1ff598888 100644 --- a/src/test/ui/hygiene/assoc_item_ctxt.stderr +++ b/src/test/ui/hygiene/assoc_item_ctxt.stderr @@ -2,7 +2,10 @@ error[E0407]: method `method` is not a member of trait `Tr` --> $DIR/assoc_item_ctxt.rs:35:13 | LL | fn method() {} - | ^^^^^^^^^^^^^^ not a member of trait `Tr` + | ^^^------^^^^^ + | | | + | | help: there is an associated function with a similar name: `method` + | not a member of trait `Tr` ... LL | mac_trait_impl!(); | ------------------ in this macro invocation diff --git a/src/test/ui/hygiene/fields-numeric-borrowck.stderr b/src/test/ui/hygiene/fields-numeric-borrowck.stderr index fb90825c0d93d..bc13aa62f4d68 100644 --- a/src/test/ui/hygiene/fields-numeric-borrowck.stderr +++ b/src/test/ui/hygiene/fields-numeric-borrowck.stderr @@ -7,7 +7,7 @@ LL | let S { 0: ref mut borrow2 } = s; | ^^^^^^^^^^^^^^^ second mutable borrow occurs here ... LL | borrow1.use_mut(); - | ------- first borrow later used here + | ----------------- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr index c2497f8ff74d2..6c8b707b8e2f1 100644 --- a/src/test/ui/hygiene/globs.stderr +++ b/src/test/ui/hygiene/globs.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find function `f` in this scope LL | f(); | ^ not found in this scope | -help: consider importing one of these items +help: consider importing this function | LL | use foo::f; | @@ -37,7 +37,7 @@ LL | n!(f); LL | n!(f); | ^ not found in this scope | - = note: consider importing one of these items: + = note: consider importing this function: foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -50,7 +50,7 @@ LL | n!(f); LL | f | ^ not found in this scope | - = note: consider importing one of these items: + = note: consider importing this function: foo::f = note: this error originates in the macro `n` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr index d72435bc63111..88c260b18cbb0 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr @@ -2,11 +2,14 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/dyn-trait.rs:20:5 | LL | fn with_dyn_debug_static<'a>(x: Box) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | static_val(x); - | ^^^^^^^^^^^^^ `x` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index a31c104d8f58b..634ff14869eb4 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -34,7 +34,7 @@ note: ...which requires type-checking `cycle1`... | LL | send(cycle2().clone()); | ^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... note: ...which requires computing type of `cycle2::{opaque#0}`... --> $DIR/auto-trait-leak.rs:19:16 | @@ -70,7 +70,7 @@ note: ...which requires type-checking `cycle2`... | LL | send(cycle1().clone()); | ^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... + = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`... = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle note: cycle used when checking item types in top-level module --> $DIR/auto-trait-leak.rs:1:1 diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr index 8cf89f164b16d..0fe9b06355f0b 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr @@ -4,7 +4,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> | ^^^^^^^^^^^^^^^^^^ | - = note: hidden type `Ordinary<'_>` captures lifetime '_#9r +note: hidden type `Ordinary<'b>` captures the lifetime `'b` as defined on the function body at 16:21 + --> $DIR/ordinary-bounds-unrelated.rs:16:21 + | +LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> + | ^^ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr index 1bcb28120ed1b..6de77523db577 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr @@ -4,7 +4,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> | ^^^^^^^^^^^^^^^^^^ | - = note: hidden type `Ordinary<'_>` captures lifetime '_#6r +note: hidden type `Ordinary<'b>` captures the lifetime `'b` as defined on the function body at 18:21 + --> $DIR/ordinary-bounds-unsuited.rs:18:21 + | +LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> + | ^^ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr index 3b75939ff02c5..812093e6e7621 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -19,7 +19,6 @@ LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } | | | lifetime `'a` defined here | - = help: consider replacing `'a` with `'static` help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound | LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x } @@ -42,7 +41,6 @@ LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` | = help: consider replacing `'a` with `'static` - = help: consider replacing `'a` with `'static` error[E0621]: explicit lifetime required in the type of `x` --> $DIR/must_outlive_least_region_or_bound.rs:11:41 @@ -67,7 +65,6 @@ LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } | -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static` | = help: consider replacing `'a` with `'static` - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:32:61 diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr index 05a9ed1d4e15d..a3aeff50eee4c 100644 --- a/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr +++ b/src/test/ui/impl-trait/static-return-lifetime-infered.nll.stderr @@ -19,7 +19,6 @@ LL | fn iter_values<'a>(&'a self) -> impl Iterator { | | | lifetime `'a` defined here | - = help: consider replacing `'a` with `'static` help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound | LL | fn iter_values<'a>(&'a self) -> impl Iterator + 'a { diff --git a/src/test/ui/imports/glob-resolve1.stderr b/src/test/ui/imports/glob-resolve1.stderr index 2c7a8ad5c1adb..3b66a5e315050 100644 --- a/src/test/ui/imports/glob-resolve1.stderr +++ b/src/test/ui/imports/glob-resolve1.stderr @@ -4,10 +4,11 @@ error[E0425]: cannot find function `fpriv` in this scope LL | fpriv(); | ^^^^^ not found in this scope | -help: consider importing this function - | -LL | use bar::fpriv; +note: function `bar::fpriv` exists but is inaccessible + --> $DIR/glob-resolve1.rs:7:5 | +LL | fn fpriv() {} + | ^^^^^^^^^^ not accessible error[E0425]: cannot find function `epriv` in this scope --> $DIR/glob-resolve1.rs:27:5 @@ -15,10 +16,11 @@ error[E0425]: cannot find function `epriv` in this scope LL | epriv(); | ^^^^^ not found in this scope | -help: consider importing this function - | -LL | use bar::epriv; +note: function `bar::epriv` exists but is inaccessible + --> $DIR/glob-resolve1.rs:9:9 | +LL | fn epriv(); + | ^^^^^^^^^^^ not accessible error[E0423]: expected value, found enum `B` --> $DIR/glob-resolve1.rs:28:5 @@ -44,10 +46,11 @@ error[E0425]: cannot find value `C` in this scope LL | C; | ^ not found in this scope | -help: consider importing this unit struct - | -LL | use bar::C; +note: unit struct `bar::C` exists but is inaccessible + --> $DIR/glob-resolve1.rs:18:5 | +LL | struct C; + | ^^^^^^^^^ not accessible error[E0425]: cannot find function `import` in this scope --> $DIR/glob-resolve1.rs:30:5 @@ -67,16 +70,13 @@ LL | pub enum B { | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ - | -help: an enum with a similar name exists + | ^ help: an enum with a similar name exists: `B` | -LL | foo::(); - | ~ -help: consider importing this enum - | -LL | use bar::A; +note: enum `bar::A` exists but is inaccessible + --> $DIR/glob-resolve1.rs:11:5 | +LL | enum A { + | ^^^^^^ not accessible error[E0412]: cannot find type `C` in this scope --> $DIR/glob-resolve1.rs:33:11 @@ -85,16 +85,13 @@ LL | pub enum B { | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ - | -help: an enum with a similar name exists - | -LL | foo::(); - | ~ -help: consider importing this struct + | ^ help: an enum with a similar name exists: `B` | -LL | use bar::C; +note: struct `bar::C` exists but is inaccessible + --> $DIR/glob-resolve1.rs:18:5 | +LL | struct C; + | ^^^^^^^^^ not accessible error[E0412]: cannot find type `D` in this scope --> $DIR/glob-resolve1.rs:34:11 @@ -103,16 +100,13 @@ LL | pub enum B { | ---------- similarly named enum `B` defined here ... LL | foo::(); - | ^ - | -help: an enum with a similar name exists - | -LL | foo::(); - | ~ -help: consider importing this type alias + | ^ help: an enum with a similar name exists: `B` | -LL | use bar::D; +note: type alias `bar::D` exists but is inaccessible + --> $DIR/glob-resolve1.rs:20:5 | +LL | type D = isize; + | ^^^^^^^^^^^^^^^ not accessible error: aborting due to 8 previous errors diff --git a/src/test/ui/imports/issue-30560.stderr b/src/test/ui/imports/issue-30560.stderr index b74134aaccc0d..69cfd4c06a8b8 100644 --- a/src/test/ui/imports/issue-30560.stderr +++ b/src/test/ui/imports/issue-30560.stderr @@ -1,4 +1,4 @@ -error: items in traits are not importable. +error: items in traits are not importable --> $DIR/issue-30560.rs:7:5 | LL | use T::*; diff --git a/src/test/ui/imports/issue-4366-2.stderr b/src/test/ui/imports/issue-4366-2.stderr index a86ec7fabea4b..4c94634ee60f7 100644 --- a/src/test/ui/imports/issue-4366-2.stderr +++ b/src/test/ui/imports/issue-4366-2.stderr @@ -4,10 +4,11 @@ error[E0412]: cannot find type `Bar` in this scope LL | fn sub() -> Bar { 1 } | ^^^ not found in this scope | -help: consider importing this type alias - | -LL | use a::b::Bar; +note: type alias `a::b::Bar` exists but is inaccessible + --> $DIR/issue-4366-2.rs:11:9 | +LL | type Bar = isize; + | ^^^^^^^^^^^^^^^^^ not accessible error[E0423]: expected function, found module `foo` --> $DIR/issue-4366-2.rs:25:5 diff --git a/src/test/ui/infinite/infinite-autoderef.rs b/src/test/ui/infinite/infinite-autoderef.rs index 6d6908ef7f63e..ca26252832bcd 100644 --- a/src/test/ui/infinite/infinite-autoderef.rs +++ b/src/test/ui/infinite/infinite-autoderef.rs @@ -1,6 +1,6 @@ // error-pattern: reached the recursion limit while auto-dereferencing -#![feature(box_syntax)] + use std::ops::Deref; @@ -17,7 +17,7 @@ impl Deref for Foo { pub fn main() { let mut x; loop { - x = box x; + x = Box::new(x); x.foo; x.bar(); } diff --git a/src/test/ui/infinite/infinite-autoderef.stderr b/src/test/ui/infinite/infinite-autoderef.stderr index cbefbf83be0a2..03e4718f5dfef 100644 --- a/src/test/ui/infinite/infinite-autoderef.stderr +++ b/src/test/ui/infinite/infinite-autoderef.stderr @@ -1,13 +1,10 @@ error[E0308]: mismatched types --> $DIR/infinite-autoderef.rs:20:13 | -LL | x = box x; - | ^^^^^ cyclic type of infinite size - | -help: try using a conversion method - | -LL | x = (box x).to_string(); - | + +++++++++++++ +LL | x = Box::new(x); + | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | cyclic type of infinite size error[E0055]: reached the recursion limit while auto-dereferencing `Foo` --> $DIR/infinite-autoderef.rs:25:5 @@ -15,7 +12,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.foo; | ^^^^^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_autoderef`) error[E0055]: reached the recursion limit while auto-dereferencing `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -23,7 +20,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.foo; | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_autoderef`) error[E0609]: no field `foo` on type `Foo` --> $DIR/infinite-autoderef.rs:25:9 @@ -37,7 +34,7 @@ error[E0055]: reached the recursion limit while auto-dereferencing `Foo` LL | Foo.bar(); | ^^^ deref recursion limit reached | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_autoderef`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_autoderef`) error[E0599]: no method named `bar` found for struct `Foo` in the current scope --> $DIR/infinite-autoderef.rs:26:9 diff --git a/src/test/ui/infinite/infinite-macro-expansion.stderr b/src/test/ui/infinite/infinite-macro-expansion.stderr index c7d9118d3f3a8..15654dfaf88f1 100644 --- a/src/test/ui/infinite/infinite-macro-expansion.stderr +++ b/src/test/ui/infinite/infinite-macro-expansion.stderr @@ -7,7 +7,7 @@ LL | () => (recursive!()) LL | recursive!() | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`infinite_macro_expansion`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`infinite_macro_expansion`) = note: this error originates in the macro `recursive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/init-res-into-things.rs b/src/test/ui/init-res-into-things.rs index ed0c600c1d2e7..7f416262dcb8c 100644 --- a/src/test/ui/init-res-into-things.rs +++ b/src/test/ui/init-res-into-things.rs @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -#![feature(box_syntax)] use std::cell::Cell; @@ -58,7 +57,7 @@ fn test_tup() { fn test_unique() { let i = &Cell::new(0); { - let _a: Box<_> = box r(i); + let _a: Box<_> = Box::new(r(i)); } assert_eq!(i.get(), 1); } @@ -66,9 +65,9 @@ fn test_unique() { fn test_unique_rec() { let i = &Cell::new(0); { - let _a: Box<_> = box BoxR { + let _a: Box<_> = Box::new(BoxR { x: r(i) - }; + }); } assert_eq!(i.get(), 1); } diff --git a/src/test/ui/intrinsics/intrinsic-atomics.rs b/src/test/ui/intrinsics/intrinsic-atomics.rs index 608cf3dee5230..c6e48e8b5afba 100644 --- a/src/test/ui/intrinsics/intrinsic-atomics.rs +++ b/src/test/ui/intrinsics/intrinsic-atomics.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] #![feature(intrinsics)] mod rusti { @@ -34,7 +33,7 @@ mod rusti { pub fn main() { unsafe { - let mut x: Box<_> = box 1; + let mut x: Box<_> = Box::new(1); assert_eq!(rusti::atomic_load(&*x), 1); *x = 5; diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 88ef8182f0238..50f1a2f25b95d 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -2,6 +2,7 @@ // ignore-wasm32-bare compiled with panic=abort by default // revisions: mir thir // [thir]compile-flags: -Zthir-unsafeck +// ignore-tidy-linelength // This test checks panic emitted from `mem::{uninitialized,zeroed}`. @@ -114,11 +115,11 @@ fn main() { test_panic_msg( || mem::uninitialized::<*const dyn Send>(), - "attempted to leave type `*const dyn std::marker::Send` uninitialized, which is invalid" + "attempted to leave type `*const dyn core::marker::Send` uninitialized, which is invalid" ); test_panic_msg( || mem::zeroed::<*const dyn Send>(), - "attempted to zero-initialize type `*const dyn std::marker::Send`, which is invalid" + "attempted to zero-initialize type `*const dyn core::marker::Send`, which is invalid" ); /* FIXME(#66151) we conservatively do not error here yet. @@ -145,12 +146,12 @@ fn main() { test_panic_msg( || mem::uninitialized::<(NonNull, u32, u32)>(), - "attempted to leave type `(std::ptr::NonNull, u32, u32)` uninitialized, \ + "attempted to leave type `(core::ptr::non_null::NonNull, u32, u32)` uninitialized, \ which is invalid" ); test_panic_msg( || mem::zeroed::<(NonNull, u32, u32)>(), - "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ + "attempted to zero-initialize type `(core::ptr::non_null::NonNull, u32, u32)`, \ which is invalid" ); @@ -187,7 +188,7 @@ fn main() { ); test_panic_msg( || mem::uninitialized::>(), - "attempted to leave type `std::mem::ManuallyDrop` uninitialized, which is invalid" + "attempted to leave type `core::mem::manually_drop::ManuallyDrop` uninitialized, which is invalid" ); // Some things that should work. diff --git a/src/test/ui/invalid/invalid-crate-type-macro.rs b/src/test/ui/invalid/invalid-crate-type-macro.rs new file mode 100644 index 0000000000000..9ba5e79ba947a --- /dev/null +++ b/src/test/ui/invalid/invalid-crate-type-macro.rs @@ -0,0 +1,7 @@ +#![crate_type = foo!()] //~ ERROR malformed `crate_type` attribute + +macro_rules! foo { + () => {"rlib"}; +} + +fn main() {} diff --git a/src/test/ui/invalid/invalid-crate-type-macro.stderr b/src/test/ui/invalid/invalid-crate-type-macro.stderr new file mode 100644 index 0000000000000..c196d4278a277 --- /dev/null +++ b/src/test/ui/invalid/invalid-crate-type-macro.stderr @@ -0,0 +1,8 @@ +error: malformed `crate_type` attribute input + --> $DIR/invalid-crate-type-macro.rs:1:1 + | +LL | #![crate_type = foo!()] + | ^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]` + +error: aborting due to previous error + diff --git a/src/test/ui/invalid_crate_type_syntax.stderr b/src/test/ui/invalid_crate_type_syntax.stderr index 92bed231586f9..4072a2fa1624a 100644 --- a/src/test/ui/invalid_crate_type_syntax.stderr +++ b/src/test/ui/invalid_crate_type_syntax.stderr @@ -2,7 +2,7 @@ error: malformed `crate_type` attribute input --> $DIR/invalid_crate_type_syntax.rs:2:1 | LL | #![crate_type(lib)] - | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]` + | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-10291.nll.stderr b/src/test/ui/issues/issue-10291.nll.stderr index 1ebb0c6cf1e7b..a7b827d27a87b 100644 --- a/src/test/ui/issues/issue-10291.nll.stderr +++ b/src/test/ui/issues/issue-10291.nll.stderr @@ -6,8 +6,6 @@ LL | fn test<'x>(x: &'x isize) { LL | drop:: FnMut(&'z isize) -> &'z isize>>(Box::new(|z| { LL | x | ^ returning this value requires that `'x` must outlive `'static` - | - = help: consider replacing `'x` with `'static` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13497-2.stderr b/src/test/ui/issues/issue-13497-2.stderr index 8ad921027e2e3..6f72b79f2a5e0 100644 --- a/src/test/ui/issues/issue-13497-2.stderr +++ b/src/test/ui/issues/issue-13497-2.stderr @@ -1,13 +1,14 @@ error[E0515]: cannot return value referencing local variable `rawLines` --> $DIR/issue-13497-2.rs:3:5 | -LL | rawLines - | ^------- - | | - | _____`rawLines` is borrowed here - | | -LL | | .iter().map(|l| l.trim()).collect() - | |___________________________________________^ returns a value referencing data owned by the current function +LL | rawLines + | _____^ + | |_____| + | || +LL | || .iter().map(|l| l.trim()).collect() + | ||_______________-___________________________^ returns a value referencing data owned by the current function + | |________________| + | `rawLines` is borrowed here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14091-2.stderr b/src/test/ui/issues/issue-14091-2.stderr index acf837d0f76b8..0b1cc9c768407 100644 --- a/src/test/ui/issues/issue-14091-2.stderr +++ b/src/test/ui/issues/issue-14091-2.stderr @@ -4,7 +4,22 @@ error[E0600]: cannot apply unary operator `!` to type `BytePos` LL | assert!(x, x); | ^^^^^^^^^^^^^^ cannot apply unary operator `!` | - = note: an implementation of `std::ops::Not` might be missing for `BytePos` +note: an implementation of `Not` might be missing for `BytePos` + --> $DIR/issue-14091-2.rs:6:1 + | +LL | pub struct BytePos(pub u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ must implement `Not` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait Not { +LL | | /// The resulting type after applying the `!` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn not(self) -> Self::Output; +LL | | } + | |_^ = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16098.stderr b/src/test/ui/issues/issue-16098.stderr index a63bcd9ba5c76..64280219d7592 100644 --- a/src/test/ui/issues/issue-16098.stderr +++ b/src/test/ui/issues/issue-16098.stderr @@ -7,7 +7,7 @@ LL | $n + prob1!($n - 1); LL | println!("Problem 1: {}", prob1!(1000)); | ------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_16098`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_16098`) = note: this error originates in the macro `prob1` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16683.nll.stderr b/src/test/ui/issues/issue-16683.nll.stderr index 51d86eaf9e60c..0e8f520353fba 100644 --- a/src/test/ui/issues/issue-16683.nll.stderr +++ b/src/test/ui/issues/issue-16683.nll.stderr @@ -1,10 +1,19 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-16683.rs:4:9 | +LL | trait T<'a> { + | -- lifetime `'a` defined here +LL | fn a(&'a self) -> &'a bool; LL | fn b(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | self.a(); - | ^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'a` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17758.nll.stderr b/src/test/ui/issues/issue-17758.nll.stderr index 075c141ed7af6..b929fdbf3687a 100644 --- a/src/test/ui/issues/issue-17758.nll.stderr +++ b/src/test/ui/issues/issue-17758.nll.stderr @@ -1,10 +1,19 @@ error[E0521]: borrowed data escapes outside of associated function --> $DIR/issue-17758.rs:7:9 | +LL | trait Foo<'a> { + | -- lifetime `'a` defined here +LL | fn foo(&'a self); LL | fn bar(&self) { - | ----- `self` is a reference that is only valid in the associated function body + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | self.foo(); - | ^^^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'a` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18294.stderr b/src/test/ui/issues/issue-18294.stderr index 432e9a6518765..e0cbd2a216dbb 100644 --- a/src/test/ui/issues/issue-18294.stderr +++ b/src/test/ui/issues/issue-18294.stderr @@ -1,4 +1,4 @@ -error: pointers cannot be cast to integers during const eval. +error: pointers cannot be cast to integers during const eval --> $DIR/issue-18294.rs:3:31 | LL | const Y: usize = unsafe { &X as *const u32 as usize }; diff --git a/src/test/ui/issues/issue-18400.stderr b/src/test/ui/issues/issue-18400.stderr index 92d53088442e6..92e0f60079f72 100644 --- a/src/test/ui/issues/issue-18400.stderr +++ b/src/test/ui/issues/issue-18400.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `_: Sized` LL | 0.contains(bits); | ^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_18400`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_18400`) note: required because of the requirements on the impl of `Set<&[_]>` for `{integer}` --> $DIR/issue-18400.rs:6:16 | diff --git a/src/test/ui/issues/issue-19163.stderr b/src/test/ui/issues/issue-19163.stderr index af509aa59d481..def032ba1bb7a 100644 --- a/src/test/ui/issues/issue-19163.stderr +++ b/src/test/ui/issues/issue-19163.stderr @@ -1,8 +1,10 @@ error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/issue-19163.rs:9:14 + --> $DIR/issue-19163.rs:9:5 | LL | mywrite!(&v, "Hello world"); - | ^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | + = note: this error originates in the macro `mywrite` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index 572c8ee33ce3c..9135c5ac36af5 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -13,7 +13,7 @@ error[E0275]: overflow evaluating the requirement `NoData Foo for T where NoData: Foo { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:8:9 | @@ -33,7 +33,7 @@ error[E0275]: overflow evaluating the requirement `NoData Foo for T where NoData: Foo { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Foo` for `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:8:9 | @@ -53,7 +53,7 @@ error[E0275]: overflow evaluating the requirement `EvenLessData Bar for T where EvenLessData: Baz { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Bar` for `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:28:9 | @@ -78,7 +78,7 @@ error[E0275]: overflow evaluating the requirement `EvenLessData Bar for T where EvenLessData: Baz { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Bar` for `AlmostNoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:28:9 | @@ -103,7 +103,7 @@ error[E0275]: overflow evaluating the requirement `AlmostNoData Baz for T where AlmostNoData: Bar { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Baz` for `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:36:9 | @@ -128,7 +128,7 @@ error[E0275]: overflow evaluating the requirement `AlmostNoData Baz for T where AlmostNoData: Bar { | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_20413`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`) note: required because of the requirements on the impl of `Baz` for `EvenLessData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/issue-20413.rs:36:9 | diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index ce3ab6b599864..5a67aead75a73 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -2,10 +2,7 @@ error[E0277]: the size for values of type `dyn Iterator` cann --> $DIR/issue-20605.rs:2:17 | LL | for item in *things { *item = 0 } - | ^^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider mutably borrowing here: `&mut *things` + | ^^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `dyn Iterator` @@ -14,6 +11,10 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider mutably borrowing here + | +LL | for item in &mut *things { *item = 0 } + | ++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21600.stderr b/src/test/ui/issues/issue-21600.stderr index 84c7106e89016..dab3c3d179725 100644 --- a/src/test/ui/issues/issue-21600.stderr +++ b/src/test/ui/issues/issue-21600.stderr @@ -5,7 +5,7 @@ LL | fn call_it(f: F) where F: Fn() { f(); } | - change this to accept `FnMut` instead of `Fn` ... LL | call_it(|| x.gen_mut()); - | ------- ^ cannot borrow as mutable + | ------- ^^^^^^^^^^^ cannot borrow as mutable | | | expects `Fn` instead of `FnMut` diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index 68a95dc265e82..b345e90178742 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<< LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_23122_2`) note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` --> $DIR/issue-23122-2.rs:8:15 | diff --git a/src/test/ui/issues/issue-26217.nll.stderr b/src/test/ui/issues/issue-26217.nll.stderr index 83f10c67d43a5..c7601caacdca3 100644 --- a/src/test/ui/issues/issue-26217.nll.stderr +++ b/src/test/ui/issues/issue-26217.nll.stderr @@ -5,8 +5,6 @@ LL | fn bar<'a>() { | -- lifetime `'a` defined here LL | foo::<&'a i32>(); | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr index 455d32e233ab9..7616f987d7312 100644 --- a/src/test/ui/issues/issue-2995.stderr +++ b/src/test/ui/issues/issue-2995.stderr @@ -6,8 +6,9 @@ LL | let _q: &isize = p as &isize; | help: consider borrowing the value | -LL | let _q: &isize = &*p as &isize; - | ++ +LL - let _q: &isize = p as &isize; +LL + let _q: &isize = &*p; + | error: aborting due to previous error diff --git a/src/test/ui/issues/issue-31076.rs b/src/test/ui/issues/issue-31076.rs index f9c35526ec342..cdb196d4ff23f 100644 --- a/src/test/ui/issues/issue-31076.rs +++ b/src/test/ui/issues/issue-31076.rs @@ -11,7 +11,7 @@ impl Add for i32 {} fn main() { let x = 5 + 6; - //~^ ERROR cannot add `{integer}` to `{integer}` + //~^ ERROR cannot add `i32` to `{integer}` let y = 5i32 + 6i32; //~^ ERROR cannot add `i32` to `i32` } diff --git a/src/test/ui/issues/issue-31076.stderr b/src/test/ui/issues/issue-31076.stderr index 4c0e1cf7ebb0b..ac0d9dc752879 100644 --- a/src/test/ui/issues/issue-31076.stderr +++ b/src/test/ui/issues/issue-31076.stderr @@ -1,8 +1,8 @@ -error[E0369]: cannot add `{integer}` to `{integer}` +error[E0369]: cannot add `i32` to `{integer}` --> $DIR/issue-31076.rs:13:15 | LL | let x = 5 + 6; - | - ^ - {integer} + | - ^ - i32 | | | {integer} diff --git a/src/test/ui/issues/issue-32963.stderr b/src/test/ui/issues/issue-32963.stderr index b5aa7b1b94d15..5e7762b32200a 100644 --- a/src/test/ui/issues/issue-32963.stderr +++ b/src/test/ui/issues/issue-32963.stderr @@ -6,7 +6,7 @@ LL | size_of_copy::(); | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Misc + Copy {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -17,7 +17,7 @@ LL | size_of_copy::(); | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Misc + Copy {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied diff --git a/src/test/ui/issues/issue-3820.stderr b/src/test/ui/issues/issue-3820.stderr index 84f8f9bd14786..d5c24e1bb6cdb 100644 --- a/src/test/ui/issues/issue-3820.stderr +++ b/src/test/ui/issues/issue-3820.stderr @@ -6,7 +6,22 @@ LL | let w = u * 3; | | | Thing | - = note: an implementation of `std::ops::Mul` might be missing for `Thing` +note: an implementation of `Mul<_>` might be missing for `Thing` + --> $DIR/issue-3820.rs:1:1 + | +LL | struct Thing { + | ^^^^^^^^^^^^ must implement `Mul<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Mul { +LL | | /// The resulting type after applying the `*` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn mul(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41726.stderr b/src/test/ui/issues/issue-41726.stderr index b00a420bc37d3..22631e7c2a332 100644 --- a/src/test/ui/issues/issue-41726.stderr +++ b/src/test/ui/issues/issue-41726.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow data in an index of `HashMap>` a --> $DIR/issue-41726.rs:5:9 | LL | things[src.as_str()].sort(); - | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap>` diff --git a/src/test/ui/issues/issue-42106.stderr b/src/test/ui/issues/issue-42106.stderr index d5a9d233bc969..73cf8652f6d20 100644 --- a/src/test/ui/issues/issue-42106.stderr +++ b/src/test/ui/issues/issue-42106.stderr @@ -4,9 +4,9 @@ error[E0502]: cannot borrow `*collection` as mutable because it is also borrowed LL | let _a = &collection; | ----------- immutable borrow occurs here LL | collection.swap(1, 2); - | ^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | _a.use_ref(); - | -- immutable borrow later used here + | ------------ immutable borrow later used here error: aborting due to previous error diff --git a/src/test/ui/issues/issue-44405.stderr b/src/test/ui/issues/issue-44405.stderr index 1fd69f6e77799..626cb2999e119 100644 --- a/src/test/ui/issues/issue-44405.stderr +++ b/src/test/ui/issues/issue-44405.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow data in an index of `Container` as mutable --> $DIR/issue-44405.rs:21:5 | LL | container[&mut val].test(); - | ^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `Container` diff --git a/src/test/ui/issues/issue-47646.stderr b/src/test/ui/issues/issue-47646.stderr index b46c277d04566..eff1de3e01752 100644 --- a/src/test/ui/issues/issue-47646.stderr +++ b/src/test/ui/issues/issue-47646.stderr @@ -2,7 +2,7 @@ error[E0502]: cannot borrow `heap` as immutable because it is also borrowed as m --> $DIR/issue-47646.rs:9:30 | LL | let borrow = heap.peek_mut(); - | ---- mutable borrow occurs here + | --------------- mutable borrow occurs here LL | LL | match (borrow, ()) { | ------------ a temporary with access to the mutable borrow is created here ... diff --git a/src/test/ui/issues/issue-50403.stderr b/src/test/ui/issues/issue-50403.stderr index d20a98ecc6ad5..a3a2ed044db3e 100644 --- a/src/test/ui/issues/issue-50403.stderr +++ b/src/test/ui/issues/issue-50403.stderr @@ -1,4 +1,4 @@ -error: concat_idents! takes 1 or more arguments. +error: concat_idents! takes 1 or more arguments --> $DIR/issue-50403.rs:4:13 | LL | let x = concat_idents!(); diff --git a/src/test/ui/issues/issue-52126-assign-op-invariance.stderr b/src/test/ui/issues/issue-52126-assign-op-invariance.stderr index d231f621e59c7..d450675776268 100644 --- a/src/test/ui/issues/issue-52126-assign-op-invariance.stderr +++ b/src/test/ui/issues/issue-52126-assign-op-invariance.stderr @@ -2,7 +2,7 @@ error[E0597]: `line` does not live long enough --> $DIR/issue-52126-assign-op-invariance.rs:34:28 | LL | let v: Vec<&str> = line.split_whitespace().collect(); - | ^^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough ... LL | acc += cnt2; | --- borrow later used here diff --git a/src/test/ui/issues/issue-54943.nll.stderr b/src/test/ui/issues/issue-54943.nll.stderr index 5bf6d3382d2eb..59be0f983b907 100644 --- a/src/test/ui/issues/issue-54943.nll.stderr +++ b/src/test/ui/issues/issue-54943.nll.stderr @@ -6,8 +6,6 @@ LL | fn boo<'a>() { ... LL | let x = foo::<&'a u32>(); | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-55796.nll.stderr b/src/test/ui/issues/issue-55796.nll.stderr index 61d4070d485e7..c1a3084f30eae 100644 --- a/src/test/ui/issues/issue-55796.nll.stderr +++ b/src/test/ui/issues/issue-55796.nll.stderr @@ -6,8 +6,6 @@ LL | pub trait Graph<'a> { ... LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-55796.rs:23:9 @@ -17,8 +15,6 @@ LL | pub trait Graph<'a> { ... LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index fb242f738c87e..6f345f56d1aa1 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -10,7 +10,7 @@ LL | for l in bad_letters { | help: consider borrowing to avoid moving into the for loop: `&bad_letters` ... LL | bad_letters.push('s'); - | ^^^^^^^^^^^ value borrowed here after move + | ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move | note: this function takes ownership of the receiver `self`, which moves `bad_letters` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL diff --git a/src/test/ui/issues/issue-62375.stderr b/src/test/ui/issues/issue-62375.stderr index 6db45630b9437..478e025bed230 100644 --- a/src/test/ui/issues/issue-62375.stderr +++ b/src/test/ui/issues/issue-62375.stderr @@ -6,7 +6,15 @@ LL | a == A::Value; | | | A | - = note: an implementation of `std::cmp::PartialEq` might be missing for `A` +note: an implementation of `PartialEq<_>` might be missing for `A` + --> $DIR/issue-62375.rs:1:1 + | +LL | enum A { + | ^^^^^^ must implement `PartialEq<_>` +help: consider annotating `A` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to previous error diff --git a/src/test/ui/issues/issue-75777.nll.stderr b/src/test/ui/issues/issue-75777.nll.stderr index 98aacb1711906..d779753687ed5 100644 --- a/src/test/ui/issues/issue-75777.nll.stderr +++ b/src/test/ui/issues/issue-75777.nll.stderr @@ -6,8 +6,6 @@ LL | fn inject<'a, Env: 'a, A: 'a + Send>(v: A) -> Box Bo LL | let fut: BoxFuture<'a, A> = Box::pin(future::ready(v)); LL | Box::new(move |_| fut) | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-81584.stderr b/src/test/ui/issues/issue-81584.stderr index d57f1b778df17..54973cfa34e61 100644 --- a/src/test/ui/issues/issue-81584.stderr +++ b/src/test/ui/issues/issue-81584.stderr @@ -2,7 +2,7 @@ error[E0515]: cannot return value referencing function parameter `y` --> $DIR/issue-81584.rs:5:22 | LL | .map(|y| y.iter().map(|x| x + 1)) - | -^^^^^^^^^^^^^^^^^^^^^^ + | --------^^^^^^^^^^^^^^^ | | | returns a value referencing data owned by the current function | `y` is borrowed here diff --git a/src/test/ui/iterators/into-iter-on-arrays-2018.stderr b/src/test/ui/iterators/into-iter-on-arrays-2018.stderr index bc08fdcafa08d..e994d69110698 100644 --- a/src/test/ui/iterators/into-iter-on-arrays-2018.stderr +++ b/src/test/ui/iterators/into-iter-on-arrays-2018.stderr @@ -1,4 +1,4 @@ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:14:34 | LL | let _: Iter<'_, i32> = array.into_iter(); @@ -16,7 +16,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | let _: Iter<'_, i32> = IntoIterator::into_iter(array); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:18:44 | LL | let _: Iter<'_, i32> = Box::new(array).into_iter(); @@ -25,7 +25,7 @@ LL | let _: Iter<'_, i32> = Box::new(array).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:22:43 | LL | let _: Iter<'_, i32> = Rc::new(array).into_iter(); @@ -34,7 +34,7 @@ LL | let _: Iter<'_, i32> = Rc::new(array).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:25:41 | LL | let _: Iter<'_, i32> = Array(array).into_iter(); @@ -43,7 +43,7 @@ LL | let _: Iter<'_, i32> = Array(array).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-2018.rs:32:24 | LL | for _ in [1, 2, 3].into_iter() {} diff --git a/src/test/ui/iterators/into-iter-on-arrays-lint.stderr b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr index 2df1a06df20ab..634728096ed69 100644 --- a/src/test/ui/iterators/into-iter-on-arrays-lint.stderr +++ b/src/test/ui/iterators/into-iter-on-arrays-lint.stderr @@ -1,4 +1,4 @@ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:10:11 | LL | small.into_iter(); @@ -16,7 +16,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | IntoIterator::into_iter(small); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:13:12 | LL | [1, 2].into_iter(); @@ -33,7 +33,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | IntoIterator::into_iter([1, 2]); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:16:9 | LL | big.into_iter(); @@ -50,7 +50,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | IntoIterator::into_iter(big); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:19:15 | LL | [0u8; 33].into_iter(); @@ -67,7 +67,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit LL | IntoIterator::into_iter([0u8; 33]); | ++++++++++++++++++++++++ ~ -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:23:21 | LL | Box::new(small).into_iter(); @@ -76,7 +76,7 @@ LL | Box::new(small).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:26:22 | LL | Box::new([1, 2]).into_iter(); @@ -85,7 +85,7 @@ LL | Box::new([1, 2]).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:29:19 | LL | Box::new(big).into_iter(); @@ -94,7 +94,7 @@ LL | Box::new(big).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:32:25 | LL | Box::new([0u8; 33]).into_iter(); @@ -103,7 +103,7 @@ LL | Box::new([0u8; 33]).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:36:31 | LL | Box::new(Box::new(small)).into_iter(); @@ -112,7 +112,7 @@ LL | Box::new(Box::new(small)).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:39:32 | LL | Box::new(Box::new([1, 2])).into_iter(); @@ -121,7 +121,7 @@ LL | Box::new(Box::new([1, 2])).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:42:29 | LL | Box::new(Box::new(big)).into_iter(); @@ -130,7 +130,7 @@ LL | Box::new(Box::new(big)).into_iter(); = warning: this changes meaning in Rust 2021 = note: for more information, see -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021. +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021 --> $DIR/into-iter-on-arrays-lint.rs:45:35 | LL | Box::new(Box::new([0u8; 33])).into_iter(); diff --git a/src/test/ui/kindck/kindck-impl-type-params-2.rs b/src/test/ui/kindck/kindck-impl-type-params-2.rs index c08f776dbf20a..8b0771985dc3f 100644 --- a/src/test/ui/kindck/kindck-impl-type-params-2.rs +++ b/src/test/ui/kindck/kindck-impl-type-params-2.rs @@ -1,15 +1,15 @@ -#![feature(box_syntax)] - trait Foo { } + + impl Foo for T { } fn take_param(foo: &T) { } fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); take_param(&x); //~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied } diff --git a/src/test/ui/kindck/kindck-impl-type-params.rs b/src/test/ui/kindck/kindck-impl-type-params.rs index 4d4d191b6aaee..5622d65cb175b 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.rs +++ b/src/test/ui/kindck/kindck-impl-type-params.rs @@ -1,7 +1,7 @@ // Issue #14061: tests the interaction between generic implementation // parameter bounds and trait objects. -#![feature(box_syntax)] + use std::marker; @@ -34,7 +34,7 @@ fn foo<'a>() { } fn foo2<'a>() { - let t: Box> = box S(marker::PhantomData); + let t: Box> = Box::new(S(marker::PhantomData)); let a = t as Box>; //~^ ERROR : Copy` is not satisfied } @@ -42,7 +42,7 @@ fn foo2<'a>() { fn foo3<'a>() { struct Foo; // does not impl Copy - let t: Box> = box S(marker::PhantomData); + let t: Box> = Box::new(S(marker::PhantomData)); let a: Box> = t; //~^ ERROR : Copy` is not satisfied } diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.rs b/src/test/ui/kindck/kindck-inherited-copy-bound.rs index aad693e5b1937..87d47556bdd25 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.rs +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.rs @@ -3,7 +3,7 @@ // revisions: curr object_safe_for_dispatch #![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))] -#![feature(box_syntax)] + use std::any::Any; @@ -17,13 +17,13 @@ impl Foo for T { fn take_param(foo: &T) { } fn a() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); take_param(&x); //[curr]~ ERROR E0277 //[object_safe_for_dispatch]~^ ERROR E0277 } fn b() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); let y = &x; let z = &x as &dyn Foo; //[curr]~^ ERROR E0038 diff --git a/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs new file mode 100644 index 0000000000000..52bd8136d9c0c --- /dev/null +++ b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs @@ -0,0 +1,27 @@ +// Make sure that an error is reported if the `call` function of the +// `fn`/`fn_mut` lang item is grossly ill-formed. + +#![feature(lang_items)] +#![feature(no_core)] +#![no_core] + +#[lang = "fn"] +trait MyFn { + const call: i32 = 42; + //~^ ERROR: `call` trait item in `fn` lang item must be a function +} + +#[lang = "fn_mut"] +trait MyFnMut { + fn call(i: i32, j: i32) -> i32 { i + j } + //~^ ERROR: first argument of `call` in `fn_mut` lang item must be a reference +} + +fn main() { + let a = || 42; + a(); + + let mut i = 0; + let mut b = || { i += 1; }; + b(); +} diff --git a/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr new file mode 100644 index 0000000000000..82bdae270c8bb --- /dev/null +++ b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr @@ -0,0 +1,14 @@ +error: `call` trait item in `fn` lang item must be a function + --> $DIR/fn-fn_mut-call-ill-formed.rs:10:5 + | +LL | const call: i32 = 42; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: first argument of `call` in `fn_mut` lang item must be a reference + --> $DIR/fn-fn_mut-call-ill-formed.rs:16:16 + | +LL | fn call(i: i32, j: i32) -> i32 { i + j } + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lang-items/issue-83471.rs b/src/test/ui/lang-items/issue-83471.rs new file mode 100644 index 0000000000000..b32aa03415152 --- /dev/null +++ b/src/test/ui/lang-items/issue-83471.rs @@ -0,0 +1,23 @@ +// Regression test for the ICE reported in issue #83471. + +#![crate_type="lib"] +#![feature(no_core)] +#![no_core] + +#[lang = "sized"] +//~^ ERROR: language items are subject to change [E0658] +trait Sized {} + +#[lang = "fn"] +//~^ ERROR: language items are subject to change [E0658] +//~| ERROR: `fn` language item must be applied to a trait with 1 generic argument +trait Fn { + fn call(export_name); + //~^ ERROR: expected type + //~| WARNING: anonymous parameters are deprecated + //~| WARNING: this is accepted in the current edition +} +fn call_through_fn_trait() { + a() + //~^ ERROR: cannot find function +} diff --git a/src/test/ui/lang-items/issue-83471.stderr b/src/test/ui/lang-items/issue-83471.stderr new file mode 100644 index 0000000000000..6d796fe7f500b --- /dev/null +++ b/src/test/ui/lang-items/issue-83471.stderr @@ -0,0 +1,51 @@ +error[E0573]: expected type, found built-in attribute `export_name` + --> $DIR/issue-83471.rs:15:13 + | +LL | fn call(export_name); + | ^^^^^^^^^^^ not a type + +error[E0425]: cannot find function `a` in this scope + --> $DIR/issue-83471.rs:21:5 + | +LL | a() + | ^ not found in this scope + +error[E0658]: language items are subject to change + --> $DIR/issue-83471.rs:7:1 + | +LL | #[lang = "sized"] + | ^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(lang_items)]` to the crate attributes to enable + +error[E0658]: language items are subject to change + --> $DIR/issue-83471.rs:11:1 + | +LL | #[lang = "fn"] + | ^^^^^^^^^^^^^^ + | + = help: add `#![feature(lang_items)]` to the crate attributes to enable + +warning: anonymous parameters are deprecated and will be removed in the next edition + --> $DIR/issue-83471.rs:15:13 + | +LL | fn call(export_name); + | ^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: export_name` + | + = note: `#[warn(anonymous_parameters)]` on by default + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #41686 + +error[E0718]: `fn` language item must be applied to a trait with 1 generic argument + --> $DIR/issue-83471.rs:11:1 + | +LL | #[lang = "fn"] + | ^^^^^^^^^^^^^^ +... +LL | trait Fn { + | - this trait has 0 generic arguments + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0425, E0573, E0658, E0718. +For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/lang-items/lang-item-generic-requirements.rs b/src/test/ui/lang-items/lang-item-generic-requirements.rs index d785749afc9c2..c0b958f2bf221 100644 --- a/src/test/ui/lang-items/lang-item-generic-requirements.rs +++ b/src/test/ui/lang-items/lang-item-generic-requirements.rs @@ -1,9 +1,8 @@ -// Checks whether declaring a lang item with the wrong number -// of generic arguments crashes the compiler (issue #83893, #87573, and part of #9307). +// Checks that declaring a lang item with the wrong number +// of generic arguments errors rather than crashing (issue #83893, #87573, part of #9307, #79559). #![feature(lang_items, no_core)] #![no_core] -#![crate_type = "lib"] #[lang = "sized"] trait MySized {} @@ -26,6 +25,14 @@ struct MyPhantomData; //~^ ERROR parameter `T` is never used //~| ERROR parameter `U` is never used +// When the `start` lang item is missing generics very odd things can happen, especially when +// it comes to cross-crate monomorphization +#[lang = "start"] +//~^ ERROR `start` language item must be applied to a function with 1 generic argument [E0718] +fn start(_: *const u8, _: isize, _: *const *const u8) -> isize { + 0 +} + fn ice() { // Use add let r = 5; @@ -42,3 +49,6 @@ fn ice() { // Use phantomdata let _ = MyPhantomData::<(), i32>; } + +// use `start` +fn main() {} diff --git a/src/test/ui/lang-items/lang-item-generic-requirements.stderr b/src/test/ui/lang-items/lang-item-generic-requirements.stderr index add5938811c28..df5a77850f14d 100644 --- a/src/test/ui/lang-items/lang-item-generic-requirements.stderr +++ b/src/test/ui/lang-items/lang-item-generic-requirements.stderr @@ -1,5 +1,5 @@ error[E0718]: `add` language item must be applied to a trait with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:11:1 + --> $DIR/lang-item-generic-requirements.rs:10:1 | LL | #[lang = "add"] | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | trait MyAdd<'a, T> {} | ------- this trait has 2 generic arguments error[E0718]: `drop_in_place` language item must be applied to a function with at least 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:15:1 + --> $DIR/lang-item-generic-requirements.rs:14:1 | LL | #[lang = "drop_in_place"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn my_ptr_drop() {} | - this function has 0 generic arguments error[E0718]: `index` language item must be applied to a trait with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:19:1 + --> $DIR/lang-item-generic-requirements.rs:18:1 | LL | #[lang = "index"] | ^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | trait MyIndex<'a, T> {} | ------- this trait has 2 generic arguments error[E0718]: `phantom_data` language item must be applied to a struct with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:23:1 + --> $DIR/lang-item-generic-requirements.rs:22:1 | LL | #[lang = "phantom_data"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,8 +32,17 @@ LL | LL | struct MyPhantomData; | ------ this struct has 2 generic arguments +error[E0718]: `start` language item must be applied to a function with 1 generic argument + --> $DIR/lang-item-generic-requirements.rs:30:1 + | +LL | #[lang = "start"] + | ^^^^^^^^^^^^^^^^^ +LL | +LL | fn start(_: *const u8, _: isize, _: *const *const u8) -> isize { + | - this function has 0 generic arguments + error[E0392]: parameter `T` is never used - --> $DIR/lang-item-generic-requirements.rs:25:22 + --> $DIR/lang-item-generic-requirements.rs:24:22 | LL | struct MyPhantomData; | ^ unused parameter @@ -42,7 +51,7 @@ LL | struct MyPhantomData; = help: if you intended `T` to be a const parameter, use `const T: usize` instead error[E0392]: parameter `U` is never used - --> $DIR/lang-item-generic-requirements.rs:25:25 + --> $DIR/lang-item-generic-requirements.rs:24:25 | LL | struct MyPhantomData; | ^ unused parameter @@ -50,7 +59,7 @@ LL | struct MyPhantomData; = help: consider removing `U` or referring to it in a field = help: if you intended `U` to be a const parameter, use `const U: usize` instead -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0392, E0718. For more information about an error, try `rustc --explain E0392`. diff --git a/src/test/ui/last-use-is-capture.rs b/src/test/ui/last-use-is-capture.rs index af2308777939e..1055fe7995ba6 100644 --- a/src/test/ui/last-use-is-capture.rs +++ b/src/test/ui/last-use-is-capture.rs @@ -3,13 +3,11 @@ #![allow(dead_code)] // Make sure #1399 stays fixed -#![feature(box_syntax)] - struct A { a: Box } pub fn main() { fn invoke(f: F) where F: FnOnce() { f(); } - let k: Box<_> = box 22; + let k: Box<_> = 22.into(); let _u = A {a: k.clone()}; invoke(|| println!("{}", k.clone()) ) } diff --git a/src/test/ui/leak-unique-as-tydesc.rs b/src/test/ui/leak-unique-as-tydesc.rs index 752081b78f275..322f726156d0c 100644 --- a/src/test/ui/leak-unique-as-tydesc.rs +++ b/src/test/ui/leak-unique-as-tydesc.rs @@ -1,8 +1,9 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn leaky(_t: T) { } -pub fn main() { let x = box 10; leaky::>(x); } +pub fn main() { + let x = Box::new(10); + leaky::>(x); +} diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr index 4a605cfb8621b..bbf04c98436e8 100644 --- a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr @@ -7,7 +7,7 @@ LL | let mut x = vec![1].iter(); | creates a temporary which is freed while still in use LL | LL | x.use_mut(); - | - borrow later used here + | ----------- borrow later used here | = note: consider using a `let` binding to create a longer lived value = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/lifetimes/issue-79187-2.nll.stderr b/src/test/ui/lifetimes/issue-79187-2.nll.stderr index 907b43d6762e9..04d9b64d64fdd 100644 --- a/src/test/ui/lifetimes/issue-79187-2.nll.stderr +++ b/src/test/ui/lifetimes/issue-79187-2.nll.stderr @@ -38,6 +38,11 @@ note: this closure does not fulfill the lifetime requirements | LL | take_foo(|a| a); | ^^^^^ +note: the lifetime requirement is introduced here + --> $DIR/issue-79187-2.rs:5:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ error[E0308]: mismatched types --> $DIR/issue-79187-2.rs:9:5 @@ -47,6 +52,11 @@ LL | take_foo(|a: &i32| a); | = note: expected reference `&i32` found reference `&i32` +note: the lifetime requirement is introduced here + --> $DIR/issue-79187-2.rs:5:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ error[E0308]: mismatched types --> $DIR/issue-79187-2.rs:10:5 @@ -56,6 +66,11 @@ LL | take_foo(|a: &i32| -> &i32 { a }); | = note: expected reference `&i32` found reference `&i32` +note: the lifetime requirement is introduced here + --> $DIR/issue-79187-2.rs:5:21 + | +LL | fn take_foo(_: impl Foo) {} + | ^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/lifetimes/issue-79187.nll.stderr b/src/test/ui/lifetimes/issue-79187.nll.stderr index 725b132e83a12..3a993e88d8a92 100644 --- a/src/test/ui/lifetimes/issue-79187.nll.stderr +++ b/src/test/ui/lifetimes/issue-79187.nll.stderr @@ -11,6 +11,11 @@ note: this closure does not fulfill the lifetime requirements | LL | let f = |_| (); | ^^^^^^ +note: the lifetime requirement is introduced here + --> $DIR/issue-79187.rs:1:18 + | +LL | fn thing(x: impl FnOnce(&u32)) {} + | ^^^^^^^^^^^^ error: implementation of `FnOnce` is not general enough --> $DIR/issue-79187.rs:5:5 diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr index 57dab46df6b6a..6f3f84096e400 100644 --- a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr @@ -2,23 +2,29 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/lifetime-bound-will-change-warning.rs:34:5 | LL | fn test2<'a>(x: &'a Box) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | // but ref_obj will not, so warn. LL | ref_obj(x) - | ^^^^^^^^^^ `x` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/lifetime-bound-will-change-warning.rs:39:5 | LL | fn test2cc<'a>(x: &'a Box) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | // same as test2, but cross crate LL | lib::ref_obj(x) - | ^^^^^^^^^^^^^^^ `x` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr index 33be98c64910d..825c45b243441 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr @@ -1,11 +1,3 @@ -error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable - --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3 - | -LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { - | - help: consider changing this to be mutable: `mut y` -LL | y.push(z); - | ^ cannot borrow as mutable - error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3 | @@ -16,6 +8,14 @@ LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { LL | y.push(z); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable + --> $DIR/ex3-both-anon-regions-using-fn-items.rs:2:3 + | +LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { + | - help: consider changing this to be mutable: `mut y` +LL | y.push(z); + | ^^^^^^^^^ cannot borrow as mutable + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr index 3c95be95db080..78a828dde866f 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr @@ -1,11 +1,3 @@ -error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable - --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 - | -LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { - | - help: consider changing this to be mutable: `mut y` -LL | y.push(z); - | ^ cannot borrow as mutable - error: lifetime may not live long enough --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 | @@ -16,6 +8,14 @@ LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { LL | y.push(z); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable + --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:2:3 + | +LL | fn foo(x:Box , y: Vec<&u8>, z: &u8) { + | - help: consider changing this to be mutable: `mut y` +LL | y.push(z); + | ^^^^^^^^^ cannot borrow as mutable + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr index 5a1294f948f1c..5509226cb1cdd 100644 --- a/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr @@ -14,6 +14,11 @@ LL | f(data, identity) | = note: expected type `for<'r> Fn<(&'r T,)>` found type `Fn<(&T,)>` +note: the lifetime requirement is introduced here + --> $DIR/issue_74400.rs:8:34 + | +LL | fn f(data: &[T], key: impl Fn(&T) -> S) { + | ^^^^^^^^^^^ error: implementation of `FnOnce` is not general enough --> $DIR/issue_74400.rs:12:5 diff --git a/src/test/ui/lint/issue-87308.rs b/src/test/ui/lint/issue-87308.rs new file mode 100644 index 0000000000000..48fbb2a0139f0 --- /dev/null +++ b/src/test/ui/lint/issue-87308.rs @@ -0,0 +1,12 @@ +// Regression test for issue #87308. + +// compile-flags: -Zunpretty=everybody_loops +// check-pass + +macro_rules! foo { + () => { break 'x; } +} + +pub fn main() { + 'x: loop { foo!() } +} diff --git a/src/test/ui/lint/issue-87308.stdout b/src/test/ui/lint/issue-87308.stdout new file mode 100644 index 0000000000000..68a076c93be61 --- /dev/null +++ b/src/test/ui/lint/issue-87308.stdout @@ -0,0 +1,14 @@ +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +// Regression test for issue #87308. + +// compile-flags: -Zunpretty=everybody_loops +// check-pass + +macro_rules! foo { () => { break 'x ; } } + +pub fn main() { loop { } } diff --git a/src/test/ui/lint/issue-89469.rs b/src/test/ui/lint/issue-89469.rs new file mode 100644 index 0000000000000..3a6ab452840ac --- /dev/null +++ b/src/test/ui/lint/issue-89469.rs @@ -0,0 +1,20 @@ +// Regression test for #89469, where an extra non_snake_case warning was +// reported for a shorthand field binding. + +// check-pass +#![deny(non_snake_case)] + +#[allow(non_snake_case)] +struct Entry { + A: u16, + a: u16 +} + +fn foo() -> Entry {todo!()} + +pub fn f() { + let Entry { A, a } = foo(); + let _ = (A, a); +} + +fn main() {} diff --git a/src/test/ui/lint/known-tool-in-submodule/root.rs b/src/test/ui/lint/known-tool-in-submodule/root.rs new file mode 100644 index 0000000000000..80806dcbd280a --- /dev/null +++ b/src/test/ui/lint/known-tool-in-submodule/root.rs @@ -0,0 +1,10 @@ +// check-pass + +#![feature(register_tool)] +#![register_tool(tool)] + +mod submodule; + +fn main() { + submodule::foo(); +} diff --git a/src/test/ui/lint/known-tool-in-submodule/submodule.rs b/src/test/ui/lint/known-tool-in-submodule/submodule.rs new file mode 100644 index 0000000000000..bb25e10056fae --- /dev/null +++ b/src/test/ui/lint/known-tool-in-submodule/submodule.rs @@ -0,0 +1,4 @@ +// ignore-test: not a test + +#[allow(tool::lint)] +pub fn foo() {} diff --git a/src/test/ui/lint/lint-ctypes-fn.rs b/src/test/ui/lint/lint-ctypes-fn.rs index c18cb881032a6..d3b36a9d59c70 100644 --- a/src/test/ui/lint/lint-ctypes-fn.rs +++ b/src/test/ui/lint/lint-ctypes-fn.rs @@ -66,6 +66,10 @@ pub extern "C" fn ptr_type1(size: *const Foo) { } pub extern "C" fn ptr_type2(size: *const Foo) { } +pub extern "C" fn ptr_unit(p: *const ()) { } + +pub extern "C" fn ptr_tuple(p: *const ((),)) { } + pub extern "C" fn slice_type(p: &[u32]) { } //~^ ERROR: uses type `[u32]` diff --git a/src/test/ui/lint/lint-ctypes-fn.stderr b/src/test/ui/lint/lint-ctypes-fn.stderr index d591d4ad292dd..740075ca7dfff 100644 --- a/src/test/ui/lint/lint-ctypes-fn.stderr +++ b/src/test/ui/lint/lint-ctypes-fn.stderr @@ -1,5 +1,5 @@ error: `extern` fn uses type `[u32]`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:69:33 + --> $DIR/lint-ctypes-fn.rs:73:33 | LL | pub extern "C" fn slice_type(p: &[u32]) { } | ^^^^^^ not FFI-safe @@ -13,7 +13,7 @@ LL | #![deny(improper_ctypes_definitions)] = note: slices have no C equivalent error: `extern` fn uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:72:31 + --> $DIR/lint-ctypes-fn.rs:76:31 | LL | pub extern "C" fn str_type(p: &str) { } | ^^^^ not FFI-safe @@ -22,7 +22,7 @@ LL | pub extern "C" fn str_type(p: &str) { } = note: string slices have no C equivalent error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:79:34 + --> $DIR/lint-ctypes-fn.rs:83:34 | LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { } | ^^^^^^^^^ not FFI-safe @@ -30,7 +30,7 @@ LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { } = note: box cannot be represented as a single pointer error: `extern` fn uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:82:35 + --> $DIR/lint-ctypes-fn.rs:86:35 | LL | pub extern "C" fn boxed_string(p: Box) { } | ^^^^^^^^ not FFI-safe @@ -38,7 +38,7 @@ LL | pub extern "C" fn boxed_string(p: Box) { } = note: box cannot be represented as a single pointer error: `extern` fn uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:85:34 + --> $DIR/lint-ctypes-fn.rs:89:34 | LL | pub extern "C" fn boxed_trait(p: Box) { } | ^^^^^^^^^^^^^^ not FFI-safe @@ -46,7 +46,7 @@ LL | pub extern "C" fn boxed_trait(p: Box) { } = note: box cannot be represented as a single pointer error: `extern` fn uses type `char`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:88:32 + --> $DIR/lint-ctypes-fn.rs:92:32 | LL | pub extern "C" fn char_type(p: char) { } | ^^^^ not FFI-safe @@ -55,7 +55,7 @@ LL | pub extern "C" fn char_type(p: char) { } = note: the `char` type has no C equivalent error: `extern` fn uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:91:32 + --> $DIR/lint-ctypes-fn.rs:95:32 | LL | pub extern "C" fn i128_type(p: i128) { } | ^^^^ not FFI-safe @@ -63,7 +63,7 @@ LL | pub extern "C" fn i128_type(p: i128) { } = note: 128-bit integers don't currently have a known stable ABI error: `extern` fn uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:94:32 + --> $DIR/lint-ctypes-fn.rs:98:32 | LL | pub extern "C" fn u128_type(p: u128) { } | ^^^^ not FFI-safe @@ -71,7 +71,7 @@ LL | pub extern "C" fn u128_type(p: u128) { } = note: 128-bit integers don't currently have a known stable ABI error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:97:33 + --> $DIR/lint-ctypes-fn.rs:101:33 | LL | pub extern "C" fn tuple_type(p: (i32, i32)) { } | ^^^^^^^^^^ not FFI-safe @@ -80,7 +80,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { } = note: tuples have unspecified layout error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:100:34 + --> $DIR/lint-ctypes-fn.rs:104:34 | LL | pub extern "C" fn tuple_type2(p: I32Pair) { } | ^^^^^^^ not FFI-safe @@ -89,7 +89,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { } = note: tuples have unspecified layout error: `extern` fn uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:103:32 + --> $DIR/lint-ctypes-fn.rs:107:32 | LL | pub extern "C" fn zero_size(p: ZeroSize) { } | ^^^^^^^^ not FFI-safe @@ -103,7 +103,7 @@ LL | pub struct ZeroSize; | ^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:106:40 + --> $DIR/lint-ctypes-fn.rs:110:40 | LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { } | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -116,7 +116,7 @@ LL | pub struct ZeroSizeWithPhantomData(PhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` fn uses type `PhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:109:51 + --> $DIR/lint-ctypes-fn.rs:113:51 | LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData { | ^^^^^^^^^^^^^^^^^ not FFI-safe @@ -124,7 +124,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData { = note: composed only of `PhantomData` error: `extern` fn uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:114:30 + --> $DIR/lint-ctypes-fn.rs:118:30 | LL | pub extern "C" fn fn_type(p: RustFn) { } | ^^^^^^ not FFI-safe @@ -133,7 +133,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { } = note: this function pointer has Rust-specific calling convention error: `extern` fn uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:117:31 + --> $DIR/lint-ctypes-fn.rs:121:31 | LL | pub extern "C" fn fn_type2(p: fn()) { } | ^^^^ not FFI-safe @@ -142,7 +142,7 @@ LL | pub extern "C" fn fn_type2(p: fn()) { } = note: this function pointer has Rust-specific calling convention error: `extern` fn uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:122:39 + --> $DIR/lint-ctypes-fn.rs:126:39 | LL | pub extern "C" fn transparent_i128(p: TransparentI128) { } | ^^^^^^^^^^^^^^^ not FFI-safe @@ -150,7 +150,7 @@ LL | pub extern "C" fn transparent_i128(p: TransparentI128) { } = note: 128-bit integers don't currently have a known stable ABI error: `extern` fn uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:125:38 + --> $DIR/lint-ctypes-fn.rs:129:38 | LL | pub extern "C" fn transparent_str(p: TransparentStr) { } | ^^^^^^^^^^^^^^ not FFI-safe @@ -159,7 +159,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { } = note: string slices have no C equivalent error: `extern` fn uses type `PhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:171:43 + --> $DIR/lint-ctypes-fn.rs:175:43 | LL | pub extern "C" fn unused_generic2() -> PhantomData { | ^^^^^^^^^^^^^^^^^ not FFI-safe @@ -167,7 +167,7 @@ LL | pub extern "C" fn unused_generic2() -> PhantomData { = note: composed only of `PhantomData` error: `extern` fn uses type `Vec`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:184:39 + --> $DIR/lint-ctypes-fn.rs:188:39 | LL | pub extern "C" fn used_generic4(x: Vec) { } | ^^^^^^ not FFI-safe @@ -176,7 +176,7 @@ LL | pub extern "C" fn used_generic4(x: Vec) { } = note: this struct has unspecified layout error: `extern` fn uses type `Vec`, which is not FFI-safe - --> $DIR/lint-ctypes-fn.rs:187:41 + --> $DIR/lint-ctypes-fn.rs:191:41 | LL | pub extern "C" fn used_generic5() -> Vec { | ^^^^^^ not FFI-safe diff --git a/src/test/ui/lint/lint-ctypes.rs b/src/test/ui/lint/lint-ctypes.rs index a291471f56670..9165e14b7ffe3 100644 --- a/src/test/ui/lint/lint-ctypes.rs +++ b/src/test/ui/lint/lint-ctypes.rs @@ -47,6 +47,8 @@ pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); extern "C" { pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo` pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` + pub fn ptr_unit(p: *const ()); + pub fn ptr_tuple(p: *const ((),)); //~ ERROR: uses type `((),)` pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]` pub fn str_type(p: &str); //~ ERROR: uses type `str` pub fn box_type(p: Box); //~ ERROR uses type `Box` diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr index 7f21e412c385c..342b6bfc6f87a 100644 --- a/src/test/ui/lint/lint-ctypes.stderr +++ b/src/test/ui/lint/lint-ctypes.stderr @@ -31,8 +31,17 @@ note: the type is defined here LL | pub struct Foo; | ^^^^^^^^^^^^^^^ +error: `extern` block uses type `((),)`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:51:25 + | +LL | pub fn ptr_tuple(p: *const ((),)); + | ^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a struct instead + = note: tuples have unspecified layout + error: `extern` block uses type `[u32]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:50:26 + --> $DIR/lint-ctypes.rs:52:26 | LL | pub fn slice_type(p: &[u32]); | ^^^^^^ not FFI-safe @@ -41,7 +50,7 @@ LL | pub fn slice_type(p: &[u32]); = note: slices have no C equivalent error: `extern` block uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:51:24 + --> $DIR/lint-ctypes.rs:53:24 | LL | pub fn str_type(p: &str); | ^^^^ not FFI-safe @@ -50,7 +59,7 @@ LL | pub fn str_type(p: &str); = note: string slices have no C equivalent error: `extern` block uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:52:24 + --> $DIR/lint-ctypes.rs:54:24 | LL | pub fn box_type(p: Box); | ^^^^^^^^ not FFI-safe @@ -59,7 +68,7 @@ LL | pub fn box_type(p: Box); = note: this struct has unspecified layout error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:53:28 + --> $DIR/lint-ctypes.rs:55:28 | LL | pub fn opt_box_type(p: Option>); | ^^^^^^^^^^^^^^^^ not FFI-safe @@ -68,7 +77,7 @@ LL | pub fn opt_box_type(p: Option>); = note: enum has no representation hint error: `extern` block uses type `char`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:55:25 + --> $DIR/lint-ctypes.rs:57:25 | LL | pub fn char_type(p: char); | ^^^^ not FFI-safe @@ -77,7 +86,7 @@ LL | pub fn char_type(p: char); = note: the `char` type has no C equivalent error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:56:25 + --> $DIR/lint-ctypes.rs:58:25 | LL | pub fn i128_type(p: i128); | ^^^^ not FFI-safe @@ -85,7 +94,7 @@ LL | pub fn i128_type(p: i128); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:57:25 + --> $DIR/lint-ctypes.rs:59:25 | LL | pub fn u128_type(p: u128); | ^^^^ not FFI-safe @@ -93,7 +102,7 @@ LL | pub fn u128_type(p: u128); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `dyn Bar`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:58:26 + --> $DIR/lint-ctypes.rs:60:26 | LL | pub fn trait_type(p: &dyn Bar); | ^^^^^^^^ not FFI-safe @@ -101,7 +110,7 @@ LL | pub fn trait_type(p: &dyn Bar); = note: trait objects have no C equivalent error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:59:26 + --> $DIR/lint-ctypes.rs:61:26 | LL | pub fn tuple_type(p: (i32, i32)); | ^^^^^^^^^^ not FFI-safe @@ -110,7 +119,7 @@ LL | pub fn tuple_type(p: (i32, i32)); = note: tuples have unspecified layout error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:60:27 + --> $DIR/lint-ctypes.rs:62:27 | LL | pub fn tuple_type2(p: I32Pair); | ^^^^^^^ not FFI-safe @@ -119,7 +128,7 @@ LL | pub fn tuple_type2(p: I32Pair); = note: tuples have unspecified layout error: `extern` block uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:61:25 + --> $DIR/lint-ctypes.rs:63:25 | LL | pub fn zero_size(p: ZeroSize); | ^^^^^^^^ not FFI-safe @@ -133,7 +142,7 @@ LL | pub struct ZeroSize; | ^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:62:33 + --> $DIR/lint-ctypes.rs:64:33 | LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -146,7 +155,7 @@ LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `PhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:65:12 + --> $DIR/lint-ctypes.rs:67:12 | LL | -> ::std::marker::PhantomData; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -154,7 +163,7 @@ LL | -> ::std::marker::PhantomData; = note: composed only of `PhantomData` error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:66:23 + --> $DIR/lint-ctypes.rs:68:23 | LL | pub fn fn_type(p: RustFn); | ^^^^^^ not FFI-safe @@ -163,7 +172,7 @@ LL | pub fn fn_type(p: RustFn); = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:67:24 + --> $DIR/lint-ctypes.rs:69:24 | LL | pub fn fn_type2(p: fn()); | ^^^^ not FFI-safe @@ -172,7 +181,7 @@ LL | pub fn fn_type2(p: fn()); = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:68:28 + --> $DIR/lint-ctypes.rs:70:28 | LL | pub fn fn_contained(p: RustBadRet); | ^^^^^^^^^^ not FFI-safe @@ -181,7 +190,7 @@ LL | pub fn fn_contained(p: RustBadRet); = note: this struct has unspecified layout error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:69:32 + --> $DIR/lint-ctypes.rs:71:32 | LL | pub fn transparent_i128(p: TransparentI128); | ^^^^^^^^^^^^^^^ not FFI-safe @@ -189,7 +198,7 @@ LL | pub fn transparent_i128(p: TransparentI128); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:70:31 + --> $DIR/lint-ctypes.rs:72:31 | LL | pub fn transparent_str(p: TransparentStr); | ^^^^^^^^^^^^^^ not FFI-safe @@ -198,7 +207,7 @@ LL | pub fn transparent_str(p: TransparentStr); = note: string slices have no C equivalent error: `extern` block uses type `Box`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:71:30 + --> $DIR/lint-ctypes.rs:73:30 | LL | pub fn transparent_fn(p: TransparentBadFn); | ^^^^^^^^^^^^^^^^ not FFI-safe @@ -207,7 +216,7 @@ LL | pub fn transparent_fn(p: TransparentBadFn); = note: this struct has unspecified layout error: `extern` block uses type `[u8; 8]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:72:27 + --> $DIR/lint-ctypes.rs:74:27 | LL | pub fn raw_array(arr: [u8; 8]); | ^^^^^^^ not FFI-safe @@ -216,7 +225,7 @@ LL | pub fn raw_array(arr: [u8; 8]); = note: passing raw arrays by value is not FFI-safe error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:74:26 + --> $DIR/lint-ctypes.rs:76:26 | LL | pub fn no_niche_a(a: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -225,7 +234,7 @@ LL | pub fn no_niche_a(a: Option>); = note: enum has no representation hint error: `extern` block uses type `Option>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:76:26 + --> $DIR/lint-ctypes.rs:78:26 | LL | pub fn no_niche_b(b: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -234,7 +243,7 @@ LL | pub fn no_niche_b(b: Option>); = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:79:34 + --> $DIR/lint-ctypes.rs:81:34 | LL | pub static static_u128_type: u128; | ^^^^ not FFI-safe @@ -242,12 +251,12 @@ LL | pub static static_u128_type: u128; = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:80:40 + --> $DIR/lint-ctypes.rs:82:40 | LL | pub static static_u128_array_type: [u128; 16]; | ^^^^^^^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI -error: aborting due to 26 previous errors +error: aborting due to 27 previous errors diff --git a/src/test/ui/lint/lint-malformed.stderr b/src/test/ui/lint/lint-malformed.stderr index b3a41a786c1f0..91b4e509b269e 100644 --- a/src/test/ui/lint/lint-malformed.stderr +++ b/src/test/ui/lint/lint-malformed.stderr @@ -14,7 +14,7 @@ error: malformed `deny` attribute input --> $DIR/lint-malformed.rs:1:1 | LL | #![deny = "foo"] - | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]` + | ^^^^^^^^^^^^^^^^ help: must be of the form: `#![deny(lint1, lint2, ..., /*opt*/ reason = "...")]` error[E0452]: malformed lint attribute input --> $DIR/lint-malformed.rs:2:10 diff --git a/src/test/ui/lint/lint-owned-heap-memory.rs b/src/test/ui/lint/lint-owned-heap-memory.rs index 7ef18c28c1ab7..af47d5c072005 100644 --- a/src/test/ui/lint/lint-owned-heap-memory.rs +++ b/src/test/ui/lint/lint-owned-heap-memory.rs @@ -1,12 +1,12 @@ #![allow(dead_code)] #![forbid(box_pointers)] -#![feature(box_syntax)] + struct Foo { x: Box //~ ERROR type uses owned } fn main() { - let _x : Foo = Foo {x : box 10}; + let _x: Foo = Foo { x : Box::new(10) }; //~^ ERROR type uses owned } diff --git a/src/test/ui/lint/lint-owned-heap-memory.stderr b/src/test/ui/lint/lint-owned-heap-memory.stderr index 40310f9387455..5ba3969707571 100644 --- a/src/test/ui/lint/lint-owned-heap-memory.stderr +++ b/src/test/ui/lint/lint-owned-heap-memory.stderr @@ -13,8 +13,8 @@ LL | #![forbid(box_pointers)] error: type uses owned (Box type) pointers: Box --> $DIR/lint-owned-heap-memory.rs:10:29 | -LL | let _x : Foo = Foo {x : box 10}; - | ^^^^^^ +LL | let _x: Foo = Foo { x : Box::new(10) }; + | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/lint/must_not_suspend/mutex.rs b/src/test/ui/lint/must_not_suspend/mutex.rs new file mode 100644 index 0000000000000..596249b2e4e4f --- /dev/null +++ b/src/test/ui/lint/must_not_suspend/mutex.rs @@ -0,0 +1,12 @@ +// edition:2018 +#![deny(must_not_suspend)] + +async fn other() {} + +pub async fn uhoh(m: std::sync::Mutex<()>) { + let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across + other().await; +} + +fn main() { +} diff --git a/src/test/ui/lint/must_not_suspend/mutex.stderr b/src/test/ui/lint/must_not_suspend/mutex.stderr new file mode 100644 index 0000000000000..093f581264f36 --- /dev/null +++ b/src/test/ui/lint/must_not_suspend/mutex.stderr @@ -0,0 +1,26 @@ +error: `MutexGuard` held across a suspend point, but should not be + --> $DIR/mutex.rs:7:9 + | +LL | let _guard = m.lock().unwrap(); + | ^^^^^^ +LL | other().await; + | ------------- the value is held across this suspend point + | +note: the lint level is defined here + --> $DIR/mutex.rs:2:9 + | +LL | #![deny(must_not_suspend)] + | ^^^^^^^^^^^^^^^^ +note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send` + --> $DIR/mutex.rs:7:9 + | +LL | let _guard = m.lock().unwrap(); + | ^^^^^^ +help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point + --> $DIR/mutex.rs:7:9 + | +LL | let _guard = m.lock().unwrap(); + | ^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs index 7ee9c41f6a091..9d837d41f101f 100644 --- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.rs @@ -1,14 +1,14 @@ #![deny(mixed_script_confusables)] struct ΑctuallyNotLatin; -//~^ ERROR The usage of Script Group `Greek` in this crate consists solely of +//~^ ERROR the usage of Script Group `Greek` in this crate consists solely of fn main() { let v = ΑctuallyNotLatin; } mod роре { -//~^ ERROR The usage of Script Group `Cyrillic` in this crate consists solely of +//~^ ERROR the usage of Script Group `Cyrillic` in this crate consists solely of const エ: &'static str = "アイウ"; - //~^ ERROR The usage of Script Group `Japanese, Katakana` in this crate consists solely of + //~^ ERROR the usage of Script Group `Japanese, Katakana` in this crate consists solely of } diff --git a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr index 4018b381fb8c5..9ca034b71b2a7 100644 --- a/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr +++ b/src/test/ui/lint/rfc-2457-non-ascii-idents/lint-mixed-script-confusables.stderr @@ -1,4 +1,4 @@ -error: The usage of Script Group `Greek` in this crate consists solely of mixed script confusables +error: the usage of Script Group `Greek` in this crate consists solely of mixed script confusables --> $DIR/lint-mixed-script-confusables.rs:3:8 | LL | struct ΑctuallyNotLatin; @@ -9,26 +9,26 @@ note: the lint level is defined here | LL | #![deny(mixed_script_confusables)] | ^^^^^^^^^^^^^^^^^^^^^^^^ - = note: The usage includes 'Α' (U+0391). - = note: Please recheck to make sure their usages are indeed what you want. + = note: the usage includes 'Α' (U+0391) + = note: please recheck to make sure their usages are indeed what you want -error: The usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables +error: the usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables --> $DIR/lint-mixed-script-confusables.rs:10:5 | LL | mod роре { | ^^^^ | - = note: The usage includes 'е' (U+0435), 'о' (U+043E), 'р' (U+0440). - = note: Please recheck to make sure their usages are indeed what you want. + = note: the usage includes 'е' (U+0435), 'о' (U+043E), 'р' (U+0440) + = note: please recheck to make sure their usages are indeed what you want -error: The usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables +error: the usage of Script Group `Japanese, Katakana` in this crate consists solely of mixed script confusables --> $DIR/lint-mixed-script-confusables.rs:12:11 | LL | const エ: &'static str = "アイウ"; | ^^ | - = note: The usage includes 'エ' (U+30A8). - = note: Please recheck to make sure their usages are indeed what you want. + = note: the usage includes 'エ' (U+30A8) + = note: please recheck to make sure their usages are indeed what you want error: aborting due to 3 previous errors diff --git a/src/test/ui/lint/unaligned_references.stderr b/src/test/ui/lint/unaligned_references.stderr index b4cce3cfea217..6a5cc91963da0 100644 --- a/src/test/ui/lint/unaligned_references.stderr +++ b/src/test/ui/lint/unaligned_references.stderr @@ -47,7 +47,7 @@ error: reference to packed field is unaligned --> $DIR/unaligned_references.rs:32:17 | LL | let _ = good.data.clone(); - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ | = 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 diff --git a/src/test/ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs b/src/test/ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs index 0ad014e3361b7..4822a9b2c7ff8 100644 --- a/src/test/ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs +++ b/src/test/ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs @@ -1,7 +1,7 @@ // check-pass -#![feature(box_syntax)] #![feature(box_patterns)] + #![warn(unused)] // UI tests pass `-A unused` (#43896) struct SoulHistory { @@ -67,7 +67,7 @@ fn main() { }; // Boxed struct - match box bag { + match Box::new(bag) { box Large::Suit { case } => {} //~ WARNING unused variable: `case` }; diff --git a/src/test/ui/list.rs b/src/test/ui/list.rs index 2ac5733b4199b..cb83d4103dced 100644 --- a/src/test/ui/list.rs +++ b/src/test/ui/list.rs @@ -3,8 +3,8 @@ #![allow(non_camel_case_types)] // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - enum list { cons(isize, Box), nil, } -pub fn main() { list::cons(10, box list::cons(11, box list::cons(12, box list::nil))); } +pub fn main() { + list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil)))))); +} diff --git a/src/test/ui/liveness/liveness-move-call-arg.rs b/src/test/ui/liveness/liveness-move-call-arg.rs index 98d12f5747aae..1bc2ea6b9fef6 100644 --- a/src/test/ui/liveness/liveness-move-call-arg.rs +++ b/src/test/ui/liveness/liveness-move-call-arg.rs @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - fn take(_x: Box) {} + fn main() { - let x: Box = box 25; + let x: Box = Box::new(25); + loop { take(x); //~ ERROR use of moved value: `x` } diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr index 5ea5c40f2ac97..7c0e916eddcaa 100644 --- a/src/test/ui/liveness/liveness-move-call-arg.stderr +++ b/src/test/ui/liveness/liveness-move-call-arg.stderr @@ -1,9 +1,9 @@ error[E0382]: use of moved value: `x` --> $DIR/liveness-move-call-arg.rs:9:14 | -LL | let x: Box = box 25; +LL | let x: Box = Box::new(25); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait -LL | loop { +... LL | take(x); | ^ value moved here, in previous iteration of loop diff --git a/src/test/ui/liveness/liveness-move-in-loop.rs b/src/test/ui/liveness/liveness-move-in-loop.rs index eb3288a28e2bc..064be14d6d28c 100644 --- a/src/test/ui/liveness/liveness-move-in-loop.rs +++ b/src/test/ui/liveness/liveness-move-in-loop.rs @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn main() { - let y: Box = box 42; + + let y: Box = 42.into(); let mut x: Box; + loop { println!("{}", y); loop { diff --git a/src/test/ui/liveness/liveness-move-in-loop.stderr b/src/test/ui/liveness/liveness-move-in-loop.stderr index 66b6373e45055..832d4f8fa030f 100644 --- a/src/test/ui/liveness/liveness-move-in-loop.stderr +++ b/src/test/ui/liveness/liveness-move-in-loop.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `y` --> $DIR/liveness-move-in-loop.rs:11:25 | -LL | let y: Box = box 42; +LL | let y: Box = 42.into(); | - move occurs because `y` has type `Box`, which does not implement the `Copy` trait ... LL | x = y; diff --git a/src/test/ui/liveness/liveness-move-in-while.rs b/src/test/ui/liveness/liveness-move-in-while.rs index 9f3ebf1362b82..7c0cd282c97e0 100644 --- a/src/test/ui/liveness/liveness-move-in-while.rs +++ b/src/test/ui/liveness/liveness-move-in-while.rs @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn main() { - let y: Box = box 42; + + let y: Box = 42.into(); let mut x: Box; + loop { println!("{}", y); //~ ERROR borrow of moved value: `y` while true { while true { while true { x = y; x.clone(); } } } diff --git a/src/test/ui/liveness/liveness-move-in-while.stderr b/src/test/ui/liveness/liveness-move-in-while.stderr index 92e0f37252158..6a8f239bd09a8 100644 --- a/src/test/ui/liveness/liveness-move-in-while.stderr +++ b/src/test/ui/liveness/liveness-move-in-while.stderr @@ -21,7 +21,7 @@ LL | while true { while true { while true { x = y; x.clone(); } } } error[E0382]: borrow of moved value: `y` --> $DIR/liveness-move-in-while.rs:7:24 | -LL | let y: Box = box 42; +LL | let y: Box = 42.into(); | - move occurs because `y` has type `Box`, which does not implement the `Copy` trait ... LL | println!("{}", y); diff --git a/src/test/ui/liveness/liveness-use-after-move.rs b/src/test/ui/liveness/liveness-use-after-move.rs index 5263e293603cd..46102ca1eb11e 100644 --- a/src/test/ui/liveness/liveness-use-after-move.rs +++ b/src/test/ui/liveness/liveness-use-after-move.rs @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn main() { - let x: Box<_> = box 5; + + let x: Box<_> = 5.into(); let y = x; + println!("{}", *x); //~ ERROR borrow of moved value: `x` y.clone(); } diff --git a/src/test/ui/liveness/liveness-use-after-move.stderr b/src/test/ui/liveness/liveness-use-after-move.stderr index 3977a3f4136d2..292ce013dcc76 100644 --- a/src/test/ui/liveness/liveness-use-after-move.stderr +++ b/src/test/ui/liveness/liveness-use-after-move.stderr @@ -1,10 +1,11 @@ error[E0382]: borrow of moved value: `x` --> $DIR/liveness-use-after-move.rs:6:20 | -LL | let x: Box<_> = box 5; +LL | let x: Box<_> = 5.into(); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | let y = x; | - value moved here +LL | LL | println!("{}", *x); | ^^ value borrowed here after move diff --git a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr index 3fdc2da9f1e2e..5ac392914e57b 100644 --- a/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-hr-noteq1.nll.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | _ => y, | ^ one type is more general than the other | - = note: expected fn pointer `for<'r, 's> fn(&'r u8, &'s u8) -> &'r u8` - found fn pointer `for<'r> fn(&'r u8, &'r u8) -> &'r u8` + = note: expected fn pointer `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` + found fn pointer `for<'a> fn(&'a u8, &'a u8) -> &'a u8` error: aborting due to previous error diff --git a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr index ad14d6b7521bc..355f0754ab1b8 100644 --- a/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr +++ b/src/test/ui/lub-glb/old-lub-glb-object.nll.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | _ => y, | ^ one type is more general than the other | - = note: expected trait object `dyn for<'r, 's> Foo<&'r u8, &'s u8>` - found trait object `dyn for<'r> Foo<&'r u8, &'r u8>` + = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` + found trait object `dyn for<'a> Foo<&'a u8, &'a u8>` error[E0308]: mismatched types --> $DIR/old-lub-glb-object.rs:10:14 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | _ => y, | ^ one type is more general than the other | - = note: expected trait object `dyn for<'r, 's> Foo<&'r u8, &'s u8>` - found trait object `dyn for<'r> Foo<&'r u8, &'r u8>` + = note: expected trait object `dyn for<'a, 'b> Foo<&'a u8, &'b u8>` + found trait object `dyn for<'a> Foo<&'a u8, &'a u8>` error: aborting due to 2 previous errors diff --git a/src/test/ui/lub-if.nll.stderr b/src/test/ui/lub-if.nll.stderr index 1ef479fcd4bc0..832688f5162b3 100644 --- a/src/test/ui/lub-if.nll.stderr +++ b/src/test/ui/lub-if.nll.stderr @@ -6,8 +6,6 @@ LL | pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { ... LL | s | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/lub-if.rs:35:9 @@ -17,8 +15,6 @@ LL | pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { ... LL | s | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/lub-match.nll.stderr b/src/test/ui/lub-match.nll.stderr index ed551da54f55e..3a344a77d2c2d 100644 --- a/src/test/ui/lub-match.nll.stderr +++ b/src/test/ui/lub-match.nll.stderr @@ -6,8 +6,6 @@ LL | pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { ... LL | s | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/lub-match.rs:39:13 @@ -17,8 +15,6 @@ LL | pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { ... LL | s | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/macros/auxiliary/macro-def-site-super.rs b/src/test/ui/macros/auxiliary/macro-def-site-super.rs new file mode 100644 index 0000000000000..cab747c2c0591 --- /dev/null +++ b/src/test/ui/macros/auxiliary/macro-def-site-super.rs @@ -0,0 +1,13 @@ +#![feature(decl_macro)] + +mod inner1 { + pub struct Struct {} + + pub mod inner2 { + pub macro mac() { + super::Struct + } + } +} + +pub use inner1::inner2 as public; diff --git a/src/test/ui/macros/bang-after-name.fixed b/src/test/ui/macros/bang-after-name.fixed new file mode 100644 index 0000000000000..c107ddd5d03bd --- /dev/null +++ b/src/test/ui/macros/bang-after-name.fixed @@ -0,0 +1,8 @@ +// run-rustfix +#[allow(unused_macros)] + +macro_rules! foo { //~ ERROR macro names aren't followed by a `!` + () => {}; +} + +fn main() {} diff --git a/src/test/ui/macros/bang-after-name.rs b/src/test/ui/macros/bang-after-name.rs new file mode 100644 index 0000000000000..7654d8c440390 --- /dev/null +++ b/src/test/ui/macros/bang-after-name.rs @@ -0,0 +1,8 @@ +// run-rustfix +#[allow(unused_macros)] + +macro_rules! foo! { //~ ERROR macro names aren't followed by a `!` + () => {}; +} + +fn main() {} diff --git a/src/test/ui/macros/bang-after-name.stderr b/src/test/ui/macros/bang-after-name.stderr new file mode 100644 index 0000000000000..f609c4943ef21 --- /dev/null +++ b/src/test/ui/macros/bang-after-name.stderr @@ -0,0 +1,8 @@ +error: macro names aren't followed by a `!` + --> $DIR/bang-after-name.rs:4:17 + | +LL | macro_rules! foo! { + | ^ help: remove the `!` + +error: aborting due to previous error + diff --git a/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.rs b/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.rs index 9139775c805a2..7a1e62d49d35e 100644 --- a/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.rs +++ b/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.rs @@ -7,7 +7,7 @@ macro_rules! a { (A) => (concat!("", a!())); (A, $($A:ident),*) => (concat!("", a!($($A),*))) //~^ ERROR recursion limit reached - //~| HELP consider adding + //~| HELP consider increasing the recursion limit } fn main() { diff --git a/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr b/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr index e6067e3334988..aa7d33cfd11a0 100644 --- a/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr +++ b/src/test/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr @@ -7,7 +7,7 @@ LL | (A, $($A:ident),*) => (concat!("", a!($($A),*))) LL | a!(A, A, A, A, A, A, A, A, A, A, A); | ------------------------------------ in this macro invocation | - = help: consider adding a `#![recursion_limit="30"]` attribute to your crate (`issue_84632_eager_expansion_recursion_limit`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "30"]` attribute to your crate (`issue_84632_eager_expansion_recursion_limit`) = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/macros/macro-def-site-super.rs b/src/test/ui/macros/macro-def-site-super.rs new file mode 100644 index 0000000000000..716a8ced5bb74 --- /dev/null +++ b/src/test/ui/macros/macro-def-site-super.rs @@ -0,0 +1,10 @@ +// `super` in a `macro` refers to the parent module of the macro itself and not its reexport. + +// check-pass +// aux-build:macro-def-site-super.rs + +extern crate macro_def_site_super; + +type A = macro_def_site_super::public::mac!(); + +fn main() {} diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr index 00c23d501a1c5..a52f415dcac51 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.stderr +++ b/src/test/ui/macros/macros-nonfatal-errors.stderr @@ -138,7 +138,7 @@ error: inline assembly must be a string literal LL | llvm_asm!(invalid); | ^^^^^^^ -error: concat_idents! requires ident args. +error: concat_idents! requires ident args --> $DIR/macros-nonfatal-errors.rs:102:5 | LL | concat_idents!("not", "idents"); diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index 38affde5f6c33..dc38972d1d09e 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -31,7 +31,7 @@ LL | my_recursive_macro!(); LL | my_recursive_macro!(); | ---------------------- in this macro invocation | - = help: consider adding a `#![recursion_limit="8"]` attribute to your crate (`trace_faulty_macros`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "8"]` attribute to your crate (`trace_faulty_macros`) = note: this error originates in the macro `my_recursive_macro` (in Nightly builds, run with -Z macro-backtrace for more info) note: trace_macro diff --git a/src/test/ui/malformed/malformed-plugin-1.stderr b/src/test/ui/malformed/malformed-plugin-1.stderr index 98744434d4f8c..505f6b6f140ba 100644 --- a/src/test/ui/malformed/malformed-plugin-1.stderr +++ b/src/test/ui/malformed/malformed-plugin-1.stderr @@ -2,7 +2,7 @@ error: malformed `plugin` attribute input --> $DIR/malformed-plugin-1.rs:2:1 | LL | #![plugin] - | ^^^^^^^^^^ help: must be of the form: `#[plugin(name)]` + | ^^^^^^^^^^ help: must be of the form: `#![plugin(name)]` warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 --> $DIR/malformed-plugin-1.rs:2:1 diff --git a/src/test/ui/malformed/malformed-plugin-2.stderr b/src/test/ui/malformed/malformed-plugin-2.stderr index 9bf0bf9345c6c..52bbd82a3892b 100644 --- a/src/test/ui/malformed/malformed-plugin-2.stderr +++ b/src/test/ui/malformed/malformed-plugin-2.stderr @@ -2,7 +2,7 @@ error: malformed `plugin` attribute input --> $DIR/malformed-plugin-2.rs:2:1 | LL | #![plugin="bleh"] - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[plugin(name)]` + | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![plugin(name)]` warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 --> $DIR/malformed-plugin-2.rs:2:1 diff --git a/src/test/ui/map-types.rs b/src/test/ui/map-types.rs index 89b57087507c8..dc33b961800ea 100644 --- a/src/test/ui/map-types.rs +++ b/src/test/ui/map-types.rs @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - use std::collections::HashMap; + + trait Map { fn get(&self, k: K) -> V { panic!() } @@ -12,7 +12,7 @@ impl Map for HashMap {} // Test that trait types printed in error msgs include the type arguments. fn main() { - let x: Box> = box HashMap::new(); + let x: Box> = HashMap::new().into(); let x: Box> = x; let y: Box> = Box::new(x); //~^ ERROR `Box>: Map` is not satisfied diff --git a/src/test/ui/match/issue-74050-end-span.stderr b/src/test/ui/match/issue-74050-end-span.stderr index d636a11a91cec..59c091e44eb87 100644 --- a/src/test/ui/match/issue-74050-end-span.stderr +++ b/src/test/ui/match/issue-74050-end-span.stderr @@ -5,7 +5,7 @@ LL | let _arg = match args.next() { | ---- borrow later stored here LL | Some(arg) => { LL | match arg.to_str() { - | ^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^ borrowed value does not live long enough ... LL | } | - `arg` dropped here while still borrowed diff --git a/src/test/ui/maybe-bounds-where.stderr b/src/test/ui/maybe-bounds-where.stderr index 2aa6a8a38223d..39bc1b88e56d7 100644 --- a/src/test/ui/maybe-bounds-where.stderr +++ b/src/test/ui/maybe-bounds-where.stderr @@ -1,32 +1,32 @@ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:1:23 + --> $DIR/maybe-bounds-where.rs:1:28 | LL | struct S1(T) where (T): ?Sized; - | ^^^ + | ^^^^^^ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:4:23 + --> $DIR/maybe-bounds-where.rs:4:27 | LL | struct S2(T) where u8: ?Sized; - | ^^ + | ^^^^^^ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:7:23 + --> $DIR/maybe-bounds-where.rs:7:35 | LL | struct S3(T) where &'static T: ?Sized; - | ^^^^^^^^^^ + | ^^^^^^ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:12:31 + --> $DIR/maybe-bounds-where.rs:12:34 | LL | struct S4(T) where for<'a> T: ?Trait<'a>; - | ^ + | ^^^^^^^^^^ error: `?Trait` bounds are only permitted at the point where a type parameter is declared - --> $DIR/maybe-bounds-where.rs:21:18 + --> $DIR/maybe-bounds-where.rs:21:21 | LL | fn f() where T: ?Sized {} - | ^ + | ^^^^^^ warning: default bound relaxed for a type parameter, but this does nothing because the given bound is not a default; only `?Sized` is supported --> $DIR/maybe-bounds-where.rs:12:11 diff --git a/src/test/ui/methods/auxiliary/method_self_arg1.rs b/src/test/ui/methods/auxiliary/method_self_arg1.rs index 8258fdd9ab93a..f89019fe5859f 100644 --- a/src/test/ui/methods/auxiliary/method_self_arg1.rs +++ b/src/test/ui/methods/auxiliary/method_self_arg1.rs @@ -1,7 +1,5 @@ #![crate_type = "lib"] -#![feature(box_syntax)] - static mut COUNT: u64 = 1; pub fn get_count() -> u64 { unsafe { COUNT } } @@ -19,8 +17,8 @@ impl Foo { Foo::baz(self); Foo::baz(*x); - Foo::qux(box self); - Foo::qux(box *x); + Foo::qux(Box::new(self)); + Foo::qux(Box::new(*x)); } pub fn bar(&self) { diff --git a/src/test/ui/methods/auxiliary/method_self_arg2.rs b/src/test/ui/methods/auxiliary/method_self_arg2.rs index 94a4a016c3eca..96725456291ea 100644 --- a/src/test/ui/methods/auxiliary/method_self_arg2.rs +++ b/src/test/ui/methods/auxiliary/method_self_arg2.rs @@ -1,7 +1,5 @@ #![crate_type = "lib"] -#![feature(box_syntax)] - static mut COUNT: u64 = 1; pub fn get_count() -> u64 { unsafe { COUNT } } @@ -15,11 +13,11 @@ impl Foo { // Test internal call. Bar::foo1(&self); Bar::foo2(self); - Bar::foo3(box self); + Bar::foo3(Box::new(self)); Bar::bar1(&self); Bar::bar2(self); - Bar::bar3(box self); + Bar::bar3(Box::new(self)); } } diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr index e0a58aed8f447..4ba778e0ef725 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -16,12 +16,12 @@ LL | fn foo() {} | ^^^^^^^^ help: disambiguate the associated function for candidate #1 | -LL | A::foo(); - | ~~~ +LL | ::foo(); + | ~~~~~~~~~~~ help: disambiguate the associated function for candidate #2 | -LL | B::foo(); - | ~~~ +LL | ::foo(); + | ~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index ffeacfe15dd06..c1183e053eb43 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -55,6 +55,17 @@ LL | .take() = note: the following trait bounds were not satisfied: `Foo: Iterator` which is required by `&mut Foo: Iterator` +note: the following trait must be implemented + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + | +LL | / pub trait Iterator { +LL | | /// The type of the elements being iterated over. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Item; +... | +LL | | } +LL | | } + | |_^ = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `take`, perhaps you need to implement it: candidate #1: `Iterator` diff --git a/src/test/ui/methods/method-self-arg-2.stderr b/src/test/ui/methods/method-self-arg-2.stderr index 946e71ee5b9c0..b98f7a786612f 100644 --- a/src/test/ui/methods/method-self-arg-2.stderr +++ b/src/test/ui/methods/method-self-arg-2.stderr @@ -6,7 +6,7 @@ LL | let y = &mut x; LL | Foo::bar(&x); | ^^ immutable borrow occurs here LL | y.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/method-self-arg-2.rs:20:14 @@ -16,7 +16,7 @@ LL | let y = &mut x; LL | Foo::baz(&mut x); | ^^^^^^ second mutable borrow occurs here LL | y.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error: aborting due to 2 previous errors diff --git a/src/test/ui/methods/method-self-arg-aux1.rs b/src/test/ui/methods/method-self-arg-aux1.rs index 9e38ff7de3424..79b70a17ca187 100644 --- a/src/test/ui/methods/method-self-arg-aux1.rs +++ b/src/test/ui/methods/method-self-arg-aux1.rs @@ -1,8 +1,6 @@ // run-pass // Test method calls with self as an argument (cross-crate) -#![feature(box_syntax)] - // aux-build:method_self_arg1.rs extern crate method_self_arg1; use method_self_arg1::Foo; @@ -12,7 +10,7 @@ fn main() { // Test external call. Foo::bar(&x); Foo::baz(x); - Foo::qux(box x); + Foo::qux(Box::new(x)); x.foo(&x); diff --git a/src/test/ui/methods/method-self-arg-aux2.rs b/src/test/ui/methods/method-self-arg-aux2.rs index 8e70399d047cd..16487b54f174f 100644 --- a/src/test/ui/methods/method-self-arg-aux2.rs +++ b/src/test/ui/methods/method-self-arg-aux2.rs @@ -1,8 +1,6 @@ // run-pass // Test method calls with self as an argument (cross-crate) -#![feature(box_syntax)] - // aux-build:method_self_arg2.rs extern crate method_self_arg2; use method_self_arg2::{Foo, Bar}; @@ -12,11 +10,11 @@ fn main() { // Test external call. Bar::foo1(&x); Bar::foo2(x); - Bar::foo3(box x); + Bar::foo3(Box::new(x)); Bar::bar1(&x); Bar::bar2(x); - Bar::bar3(box x); + Bar::bar3(Box::new(x)); x.run_trait(); diff --git a/src/test/ui/methods/method-self-arg-trait.rs b/src/test/ui/methods/method-self-arg-trait.rs index 227b1eab25de2..ffa7a552b25a3 100644 --- a/src/test/ui/methods/method-self-arg-trait.rs +++ b/src/test/ui/methods/method-self-arg-trait.rs @@ -1,8 +1,6 @@ // run-pass // Test method calls with self as an argument -#![feature(box_syntax)] - static mut COUNT: u64 = 1; #[derive(Copy, Clone)] @@ -44,11 +42,11 @@ impl Foo { // Test internal call. Bar::foo1(&self); Bar::foo2(self); - Bar::foo3(box self); + Bar::foo3(Box::new(self)); Bar::bar1(&self); Bar::bar2(self); - Bar::bar3(box self); + Bar::bar3(Box::new(self)); } } @@ -57,11 +55,11 @@ fn main() { // Test external call. Bar::foo1(&x); Bar::foo2(x); - Bar::foo3(box x); + Bar::foo3(Box::new(x)); Bar::bar1(&x); Bar::bar2(x); - Bar::bar3(box x); + Bar::bar3(Box::new(x)); x.baz(); diff --git a/src/test/ui/methods/method-self-arg.rs b/src/test/ui/methods/method-self-arg.rs index 2d25b0dbad196..f738fa19c852a 100644 --- a/src/test/ui/methods/method-self-arg.rs +++ b/src/test/ui/methods/method-self-arg.rs @@ -1,8 +1,6 @@ // run-pass // Test method calls with self as an argument -#![feature(box_syntax)] - static mut COUNT: usize = 1; #[derive(Copy, Clone)] @@ -18,8 +16,8 @@ impl Foo { Foo::baz(self); Foo::baz(*x); - Foo::qux(box self); - Foo::qux(box *x); + Foo::qux(Box::new(self)); + Foo::qux(Box::new(*x)); } fn bar(&self) { @@ -40,7 +38,7 @@ fn main() { // Test external call. Foo::bar(&x); Foo::baz(x); - Foo::qux(box x); + Foo::qux(Box::new(x)); x.foo(&x); diff --git a/src/test/ui/methods/method-two-trait-defer-resolution-2.rs b/src/test/ui/methods/method-two-trait-defer-resolution-2.rs index 8af3dcf5c3db0..fc5766da9714b 100644 --- a/src/test/ui/methods/method-two-trait-defer-resolution-2.rs +++ b/src/test/ui/methods/method-two-trait-defer-resolution-2.rs @@ -10,8 +10,6 @@ // codegen the call as `Foo::foo(&x)` and let the specific impl get // chosen later. -#![feature(box_syntax)] - trait Foo { fn foo(&self) -> isize; } @@ -37,7 +35,7 @@ fn call_foo_copy() -> isize { fn call_foo_other() -> isize { let mut x: Vec<_> = Vec::new(); let y = x.foo(); - let z: Box = box 0; + let z: Box = Box::new(0); x.push(z); y } diff --git a/src/test/ui/mir-dataflow/liveness-enum.rs b/src/test/ui/mir-dataflow/liveness-enum.rs new file mode 100644 index 0000000000000..5eb04ae8c8d37 --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-enum.rs @@ -0,0 +1,22 @@ +#![feature(core_intrinsics, rustc_attrs)] + +use std::intrinsics::rustc_peek; + +#[rustc_mir(rustc_peek_liveness, stop_after_dataflow)] +fn foo() -> Option { + let mut x = None; + + // `x` is live here since it is used in the next statement... + rustc_peek(x); + + dbg!(x); + + // But not here, since it is overwritten below + rustc_peek(x); //~ ERROR rustc_peek: bit not set + + x = Some(4); + + x +} + +fn main() {} diff --git a/src/test/ui/mir-dataflow/liveness-enum.stderr b/src/test/ui/mir-dataflow/liveness-enum.stderr new file mode 100644 index 0000000000000..483944d731aed --- /dev/null +++ b/src/test/ui/mir-dataflow/liveness-enum.stderr @@ -0,0 +1,10 @@ +error: rustc_peek: bit not set + --> $DIR/liveness-enum.rs:15:5 + | +LL | rustc_peek(x); + | ^^^^^^^^^^^^^ + +error: stop_after_dataflow ended compilation + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/mir/issue-89485.rs b/src/test/ui/mir/issue-89485.rs new file mode 100644 index 0000000000000..cb507eefebbe5 --- /dev/null +++ b/src/test/ui/mir/issue-89485.rs @@ -0,0 +1,18 @@ +// Regression test for issue #89485. + +// run-pass + +#[derive(Debug, Eq, PartialEq)] +pub enum Type { + A = 1, + B = 2, +} +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/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index a47eb87cff06c..7f91d5ed42ce4 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -28,8 +28,9 @@ LL | let _ = v as &u8; | help: consider borrowing the value | -LL | let _ = &*v as &u8; - | ++ +LL - let _ = v as &u8; +LL + let _ = &*v; + | error[E0605]: non-primitive cast: `*const u8` as `E` --> $DIR/cast-rfc0401.rs:30:13 diff --git a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr index f29126e6afc76..bd36fab92886d 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.nll.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.nll.stderr @@ -20,6 +20,11 @@ note: this closure does not fulfill the lifetime requirements | LL | baz(|_| ()); | ^^^^^^ +note: the lifetime requirement is introduced here + --> $DIR/closure-mismatch.rs:5:11 + | +LL | fn baz(_: T) {} + | ^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/missing/missing-alloc_error_handler.stderr b/src/test/ui/missing/missing-alloc_error_handler.stderr index 511d0788b40a7..ed84493deb563 100644 --- a/src/test/ui/missing/missing-alloc_error_handler.stderr +++ b/src/test/ui/missing/missing-alloc_error_handler.stderr @@ -1,6 +1,6 @@ -error: `#[alloc_error_handler]` function required, but not found. +error: `#[alloc_error_handler]` function required, but not found -note: Use `#![feature(default_alloc_error_handler)]` for a default error handler. +note: Use `#![feature(default_alloc_error_handler)]` for a default error handler error: aborting due to previous error diff --git a/src/test/ui/missing/missing-allocator.stderr b/src/test/ui/missing/missing-allocator.stderr index 59648c42a5f31..0da5651c18cb1 100644 --- a/src/test/ui/missing/missing-allocator.stderr +++ b/src/test/ui/missing/missing-allocator.stderr @@ -1,4 +1,4 @@ -error: no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait. +error: no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait error: aborting due to previous error diff --git a/src/test/ui/modules/path-invalid-form.rs b/src/test/ui/modules/path-invalid-form.rs new file mode 100644 index 0000000000000..713ef4a795d88 --- /dev/null +++ b/src/test/ui/modules/path-invalid-form.rs @@ -0,0 +1,4 @@ +#[path = 123] //~ ERROR malformed `path` attribute +mod foo; + +fn main() {} diff --git a/src/test/ui/modules/path-invalid-form.stderr b/src/test/ui/modules/path-invalid-form.stderr new file mode 100644 index 0000000000000..7e8aa44ef8be6 --- /dev/null +++ b/src/test/ui/modules/path-invalid-form.stderr @@ -0,0 +1,8 @@ +error: malformed `path` attribute input + --> $DIR/path-invalid-form.rs:1:1 + | +LL | #[path = 123] + | ^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]` + +error: aborting due to previous error + diff --git a/src/test/ui/modules/path-macro.rs b/src/test/ui/modules/path-macro.rs new file mode 100644 index 0000000000000..ce2d1e2da2659 --- /dev/null +++ b/src/test/ui/modules/path-macro.rs @@ -0,0 +1,8 @@ +macro_rules! foo { + () => {"bar.rs"}; +} + +#[path = foo!()] //~ ERROR malformed `path` attribute +mod abc; + +fn main() {} diff --git a/src/test/ui/modules/path-macro.stderr b/src/test/ui/modules/path-macro.stderr new file mode 100644 index 0000000000000..9a2e01ea26451 --- /dev/null +++ b/src/test/ui/modules/path-macro.stderr @@ -0,0 +1,8 @@ +error: malformed `path` attribute input + --> $DIR/path-macro.rs:5:1 + | +LL | #[path = foo!()] + | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]` + +error: aborting due to previous error + diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.rs b/src/test/ui/moves/issue-72649-uninit-in-loop.rs new file mode 100644 index 0000000000000..e6bc4e22ec22c --- /dev/null +++ b/src/test/ui/moves/issue-72649-uninit-in-loop.rs @@ -0,0 +1,74 @@ +// Regression test for issue #72649 +// Tests that we don't emit spurious +// 'value moved in previous iteration of loop' message + +struct NonCopy; + +fn good() { + loop { + let value = NonCopy{}; + let _used = value; + } +} + +fn moved_here_1() { + loop { + let value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + let _used = value; + //~^ NOTE value moved here + let _used2 = value; //~ ERROR use of moved value: `value` + //~^ NOTE value used here after move + } +} + +fn moved_here_2() { + let value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + loop { + let _used = value; + //~^ NOTE value moved here + loop { + let _used2 = value; //~ ERROR use of moved value: `value` + //~^ NOTE value used here after move + } + } +} + +fn moved_loop_1() { + let value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + loop { + let _used = value; //~ ERROR use of moved value: `value` + //~^ NOTE value moved here, in previous iteration of loop + } +} + +fn moved_loop_2() { + let mut value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + let _used = value; + value = NonCopy{}; + loop { + let _used2 = value; //~ ERROR use of moved value: `value` + //~^ NOTE value moved here, in previous iteration of loop + } +} + +fn uninit_1() { + loop { + let value: NonCopy; + let _used = value; //~ ERROR use of possibly-uninitialized variable: `value` + //~^ NOTE use of possibly-uninitialized `value` + } +} + +fn uninit_2() { + let mut value: NonCopy; + loop { + let _used = value; //~ ERROR use of possibly-uninitialized variable: `value` + //~^ NOTE use of possibly-uninitialized `value` + } +} + +fn main() {} diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr new file mode 100644 index 0000000000000..076d3dff14086 --- /dev/null +++ b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr @@ -0,0 +1,58 @@ +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:20:22 + | +LL | let value = NonCopy{}; + | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +LL | +LL | let _used = value; + | ----- value moved here +LL | +LL | let _used2 = value; + | ^^^^^ value used here after move + +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:32:26 + | +LL | let value = NonCopy{}; + | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +... +LL | let _used = value; + | ----- value moved here +... +LL | let _used2 = value; + | ^^^^^ value used here after move + +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:42:21 + | +LL | let value = NonCopy{}; + | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +... +LL | let _used = value; + | ^^^^^ value moved here, in previous iteration of loop + +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:53:22 + | +LL | let mut value = NonCopy{}; + | --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +... +LL | let _used2 = value; + | ^^^^^ value moved here, in previous iteration of loop + +error[E0381]: use of possibly-uninitialized variable: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:61:21 + | +LL | let _used = value; + | ^^^^^ use of possibly-uninitialized `value` + +error[E0381]: use of possibly-uninitialized variable: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:69:21 + | +LL | let _used = value; + | ^^^^^ use of possibly-uninitialized `value` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0381, E0382. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/moves/move-1-unique.rs b/src/test/ui/moves/move-1-unique.rs index 7d3987f656087..f98d075d18bba 100644 --- a/src/test/ui/moves/move-1-unique.rs +++ b/src/test/ui/moves/move-1-unique.rs @@ -1,7 +1,6 @@ // run-pass #![allow(unused_mut)] #![allow(dead_code)] -#![feature(box_syntax)] #[derive(Clone)] struct Triple { @@ -13,12 +12,12 @@ struct Triple { fn test(x: bool, foo: Box) -> isize { let bar = foo; let mut y: Box; - if x { y = bar; } else { y = box Triple{x: 4, y: 5, z: 6}; } + if x { y = bar; } else { y = Box::new(Triple{x: 4, y: 5, z: 6}); } return y.y; } pub fn main() { - let x: Box<_> = box Triple{x: 1, y: 2, z: 3}; + let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3}); assert_eq!(test(true, x.clone()), 2); assert_eq!(test(true, x.clone()), 2); assert_eq!(test(true, x.clone()), 2); diff --git a/src/test/ui/moves/move-2-unique.rs b/src/test/ui/moves/move-2-unique.rs index 910a88c102f0f..8fda3c1c86c60 100644 --- a/src/test/ui/moves/move-2-unique.rs +++ b/src/test/ui/moves/move-2-unique.rs @@ -1,11 +1,10 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct X { x: isize, y: isize, z: isize } pub fn main() { - let x: Box<_> = box X{x: 1, y: 2, z: 3}; + let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); let y = x; assert_eq!(y.y, 2); } diff --git a/src/test/ui/moves/move-2.rs b/src/test/ui/moves/move-2.rs index 4ad53e96e50f2..5e010087465d9 100644 --- a/src/test/ui/moves/move-2.rs +++ b/src/test/ui/moves/move-2.rs @@ -1,7 +1,6 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct X { x: isize, y: isize, z: isize } -pub fn main() { let x: Box<_> = box X {x: 1, y: 2, z: 3}; let y = x; assert_eq!(y.y, 2); } +pub fn main() { let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); let y = x; assert_eq!(y.y, 2); } diff --git a/src/test/ui/moves/move-3-unique.rs b/src/test/ui/moves/move-3-unique.rs index d23a852433f4f..8e5df2c3ff9fd 100644 --- a/src/test/ui/moves/move-3-unique.rs +++ b/src/test/ui/moves/move-3-unique.rs @@ -1,7 +1,6 @@ // run-pass #![allow(unused_mut)] #![allow(dead_code)] -#![feature(box_syntax)] #[derive(Clone)] struct Triple { @@ -13,12 +12,12 @@ struct Triple { fn test(x: bool, foo: Box) -> isize { let bar = foo; let mut y: Box; - if x { y = bar; } else { y = box Triple {x: 4, y: 5, z: 6}; } + if x { y = bar; } else { y = Box::new(Triple {x: 4, y: 5, z: 6}); } return y.y; } pub fn main() { - let x: Box<_> = box Triple{x: 1, y: 2, z: 3}; + let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3}); for _ in 0_usize..10000_usize { assert_eq!(test(true, x.clone()), 2); } diff --git a/src/test/ui/moves/move-4-unique.rs b/src/test/ui/moves/move-4-unique.rs index 1787caadb7ab0..24aec7ea62c8b 100644 --- a/src/test/ui/moves/move-4-unique.rs +++ b/src/test/ui/moves/move-4-unique.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct Triple {a: isize, b: isize, c: isize} @@ -13,7 +12,7 @@ fn test(foo: Box) -> Box { } pub fn main() { - let x = box Triple{a: 1, b: 2, c: 3}; + let x = Box::new(Triple{a: 1, b: 2, c: 3}); let y = test(x); assert_eq!(y.c, 3); } diff --git a/src/test/ui/moves/move-4.rs b/src/test/ui/moves/move-4.rs index c87c605df7730..63aa031a66e60 100644 --- a/src/test/ui/moves/move-4.rs +++ b/src/test/ui/moves/move-4.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct Triple { a: isize, b: isize, c: isize } @@ -13,7 +12,7 @@ fn test(foo: Box) -> Box { } pub fn main() { - let x = box Triple{a: 1, b: 2, c: 3}; + let x = Box::new(Triple{ a: 1, b: 2, c: 3 }); let y = test(x); assert_eq!(y.c, 3); } diff --git a/src/test/ui/moves/move-arg-2-unique.rs b/src/test/ui/moves/move-arg-2-unique.rs index fcfd5e14765f5..9622c83750d3e 100644 --- a/src/test/ui/moves/move-arg-2-unique.rs +++ b/src/test/ui/moves/move-arg-2-unique.rs @@ -1,13 +1,12 @@ // run-pass -#![feature(box_syntax)] fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } pub fn main() { - let x = box vec![10]; + let x = Box::new(vec![10]); // Test forgetting a local by move-in test(x); // Test forgetting a temporary by move-in. - test(box vec![10]); + test(Box::new(vec![10])); } diff --git a/src/test/ui/moves/move-arg-2.rs b/src/test/ui/moves/move-arg-2.rs index 4cd1f6fe8105e..77ee06e192e73 100644 --- a/src/test/ui/moves/move-arg-2.rs +++ b/src/test/ui/moves/move-arg-2.rs @@ -1,13 +1,12 @@ // run-pass -#![feature(box_syntax)] fn test(foo: Box>) { assert_eq!((*foo)[0], 10); } pub fn main() { - let x = box vec![10]; + let x = Box::new(vec![10]); // Test forgetting a local by move-in test(x); // Test forgetting a temporary by move-in. - test(box vec![10]); + test(Box::new(vec![10])); } diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr index eca6bb9296ddc..57be5fb4d8a59 100644 --- a/src/test/ui/moves/move-fn-self-receiver.stderr +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -75,7 +75,7 @@ error[E0505]: cannot move out of `mut_foo` because it is borrowed --> $DIR/move-fn-self-receiver.rs:50:5 | LL | let ret = mut_foo.use_mut_self(); - | ------- borrow of `mut_foo` occurs here + | ---------------------- borrow of `mut_foo` occurs here LL | mut_foo; | ^^^^^^^ move out of `mut_foo` occurs here LL | ret; diff --git a/src/test/ui/moves/move-guard-same-consts.rs b/src/test/ui/moves/move-guard-same-consts.rs index da436b89f538e..b96ef8e19eb51 100644 --- a/src/test/ui/moves/move-guard-same-consts.rs +++ b/src/test/ui/moves/move-guard-same-consts.rs @@ -8,10 +8,10 @@ // that assumption did not hold, at least not in the long run (namely, // overlapping patterns were turned into warnings rather than errors). -#![feature(box_syntax)] + fn main() { - let x: Box<_> = box 1; + let x: Box<_> = Box::new(1); let v = (1, 2); diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr index 5fc8a5499326e..2048fefefa31b 100644 --- a/src/test/ui/moves/move-guard-same-consts.stderr +++ b/src/test/ui/moves/move-guard-same-consts.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-guard-same-consts.rs:20:24 | -LL | let x: Box<_> = box 1; +LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (1, 2) if take(x) => (), diff --git a/src/test/ui/moves/move-in-guard-1.rs b/src/test/ui/moves/move-in-guard-1.rs index 9c50782e6406c..36e39fea6af3b 100644 --- a/src/test/ui/moves/move-in-guard-1.rs +++ b/src/test/ui/moves/move-in-guard-1.rs @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - pub fn main() { - let x: Box<_> = box 1; + + + let x: Box<_> = Box::new(1); let v = (1, 2); diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr index d894209f51764..5e9aa66b90dae 100644 --- a/src/test/ui/moves/move-in-guard-1.stderr +++ b/src/test/ui/moves/move-in-guard-1.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-in-guard-1.rs:10:24 | -LL | let x: Box<_> = box 1; +LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (1, _) if take(x) => (), diff --git a/src/test/ui/moves/move-in-guard-2.rs b/src/test/ui/moves/move-in-guard-2.rs index f478625a83b3e..085b7ec6e0ccc 100644 --- a/src/test/ui/moves/move-in-guard-2.rs +++ b/src/test/ui/moves/move-in-guard-2.rs @@ -1,7 +1,5 @@ -#![feature(box_syntax)] - pub fn main() { - let x: Box<_> = box 1; + let x: Box<_> = Box::new(1); let v = (1, 2); diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr index a067d43389378..ea350926b1519 100644 --- a/src/test/ui/moves/move-in-guard-2.stderr +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -1,7 +1,7 @@ error[E0382]: use of moved value: `x` - --> $DIR/move-in-guard-2.rs:10:24 + --> $DIR/move-in-guard-2.rs:8:24 | -LL | let x: Box<_> = box 1; +LL | let x: Box<_> = Box::new(1); | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (_, 2) if take(x) => (), diff --git a/src/test/ui/moves/move-out-of-tuple-field.rs b/src/test/ui/moves/move-out-of-tuple-field.rs index e5a505bb88d32..66912fa4d0998 100644 --- a/src/test/ui/moves/move-out-of-tuple-field.rs +++ b/src/test/ui/moves/move-out-of-tuple-field.rs @@ -1,13 +1,13 @@ -#![feature(box_syntax)] - struct Foo(Box); + + fn main() { - let x: (Box<_>,) = (box 1,); + let x: (Box<_>,) = (Box::new(1),); let y = x.0; let z = x.0; //~ ERROR use of moved value: `x.0` - let x = Foo(box 1); + let x = Foo(Box::new(1)); let y = x.0; let z = x.0; //~ ERROR use of moved value: `x.0` } diff --git a/src/test/ui/moves/moves-based-on-type-block-bad.rs b/src/test/ui/moves/moves-based-on-type-block-bad.rs index 085e249c0fb07..eca33167f454a 100644 --- a/src/test/ui/moves/moves-based-on-type-block-bad.rs +++ b/src/test/ui/moves/moves-based-on-type-block-bad.rs @@ -1,5 +1,5 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + struct S { x: Box @@ -16,7 +16,7 @@ fn f(s: &S, g: G) where G: FnOnce(&S) { } fn main() { - let s = S { x: box E::Bar(box 42) }; + let s = S { x: Box::new(E::Bar(Box::new(42))) }; loop { f(&s, |hellothere| { match hellothere.x { //~ ERROR cannot move out diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs index 52a5103865123..76b7aab542de8 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs @@ -1,10 +1,10 @@ -#![feature(box_syntax, unboxed_closures)] +#![feature(unboxed_closures)] fn to_fn>(f: F) -> F { f } fn test(_x: Box) {} fn main() { - let i = box 3; + let i = Box::new(3); let _f = to_fn(|| test(i)); //~ ERROR cannot move out } diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr index e12af2d452743..ce930eee2e919 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -1,7 +1,7 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:9:28 | -LL | let i = box 3; +LL | let i = Box::new(3); | - captured outer variable LL | let _f = to_fn(|| test(i)); | --------^- diff --git a/src/test/ui/moves/moves-based-on-type-tuple.rs b/src/test/ui/moves/moves-based-on-type-tuple.rs index 828d90cd7ac7f..2e67d8f8a6913 100644 --- a/src/test/ui/moves/moves-based-on-type-tuple.rs +++ b/src/test/ui/moves/moves-based-on-type-tuple.rs @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - fn dup(x: Box) -> Box<(Box,Box)> { - box (x, x) + + + Box::new((x, x)) //~^ use of moved value: `x` [E0382] } fn main() { - dup(box 3); + dup(Box::new(3)); } diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr index a52c023e20293..eef8ce61fa9d8 100644 --- a/src/test/ui/moves/moves-based-on-type-tuple.stderr +++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr @@ -1,12 +1,13 @@ error[E0382]: use of moved value: `x` - --> $DIR/moves-based-on-type-tuple.rs:4:13 + --> $DIR/moves-based-on-type-tuple.rs:4:18 | LL | fn dup(x: Box) -> Box<(Box,Box)> { | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait -LL | box (x, x) - | - ^ value used here after move - | | - | value moved here +... +LL | Box::new((x, x)) + | - ^ value used here after move + | | + | value moved here error: aborting due to previous error diff --git a/src/test/ui/moves/moves-sru-moved-field.rs b/src/test/ui/moves/moves-sru-moved-field.rs index e620e5de92320..72957c49fc8ae 100644 --- a/src/test/ui/moves/moves-sru-moved-field.rs +++ b/src/test/ui/moves/moves-sru-moved-field.rs @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - type Noncopyable = Box; + + struct Foo { copied: isize, moved: Box, @@ -10,8 +10,8 @@ struct Foo { fn test0(f: Foo, g: Noncopyable, h: Noncopyable) { // just copy implicitly copyable fields from `f`, no moves: - let _b = Foo {moved: box 1, noncopyable: g, ..f}; - let _c = Foo {moved: box 2, noncopyable: h, ..f}; + let _b = Foo {moved: Box::new(1), noncopyable: g, ..f}; + let _c = Foo {moved: Box::new(2), noncopyable: h, ..f}; } fn test1(f: Foo, g: Noncopyable, h: Noncopyable) { diff --git a/src/test/ui/mut-function-arguments.rs b/src/test/ui/mut-function-arguments.rs index 620d00edbbce3..1e682fc4b66c4 100644 --- a/src/test/ui/mut-function-arguments.rs +++ b/src/test/ui/mut-function-arguments.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(box_syntax)] - fn f(mut y: Box) { *y = 5; assert_eq!(*y, 5); @@ -9,13 +7,13 @@ fn f(mut y: Box) { fn g() { let frob = |mut q: Box| { *q = 2; assert_eq!(*q, 2); }; - let w = box 37; + let w = Box::new(37); frob(w); } pub fn main() { - let z = box 17; + let z = Box::new(17); f(z); g(); } diff --git a/src/test/ui/mut/mut-cant-alias.stderr b/src/test/ui/mut/mut-cant-alias.stderr index d56e45db13d0e..6046c076f2e53 100644 --- a/src/test/ui/mut/mut-cant-alias.stderr +++ b/src/test/ui/mut/mut-cant-alias.stderr @@ -6,7 +6,7 @@ LL | let b1 = &mut *b; LL | let b2 = &mut *b; | ^ second mutable borrow occurs here LL | b1.use_mut(); - | -- first borrow later used here + | ------------ first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/mut/mut-cross-borrowing.rs b/src/test/ui/mut/mut-cross-borrowing.rs index 63e49c292eac7..080faab732619 100644 --- a/src/test/ui/mut/mut-cross-borrowing.rs +++ b/src/test/ui/mut/mut-cross-borrowing.rs @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn f(_: &mut isize) {} fn main() { - let mut x: Box<_> = box 3; + + let mut x: Box<_> = Box::new(3); + f(x) //~ ERROR mismatched types } diff --git a/src/test/ui/mut/mut-suggestion.stderr b/src/test/ui/mut/mut-suggestion.stderr index 245eaff4bb4ec..cba284550b95a 100644 --- a/src/test/ui/mut/mut-suggestion.stderr +++ b/src/test/ui/mut/mut-suggestion.stderr @@ -5,7 +5,7 @@ LL | fn func(arg: S) { | --- help: consider changing this to be mutable: `mut arg` ... LL | arg.mutate(); - | ^^^ cannot borrow as mutable + | ^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `local` as mutable, as it is not declared as mutable --> $DIR/mut-suggestion.rs:20:5 @@ -14,7 +14,7 @@ LL | let local = S; | ----- help: consider changing this to be mutable: `mut local` ... LL | local.mutate(); - | ^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to 2 previous errors diff --git a/src/test/ui/never_type/defaulted-never-note.stderr b/src/test/ui/never_type/defaulted-never-note.fallback.stderr similarity index 78% rename from src/test/ui/never_type/defaulted-never-note.stderr rename to src/test/ui/never_type/defaulted-never-note.fallback.stderr index 109a81a5ca047..b105f03f81cdd 100644 --- a/src/test/ui/never_type/defaulted-never-note.stderr +++ b/src/test/ui/never_type/defaulted-never-note.fallback.stderr @@ -1,14 +1,14 @@ error[E0277]: the trait bound `!: ImplementedForUnitButNotNever` is not satisfied - --> $DIR/defaulted-never-note.rs:26:5 + --> $DIR/defaulted-never-note.rs:30:5 | LL | foo(_x); | ^^^ the trait `ImplementedForUnitButNotNever` is not implemented for `!` | - = note: this trait is implemented for `()`. - = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information). + = note: this trait is implemented for `()` + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) = help: did you intend to use the type `()` here instead? note: required by a bound in `foo` - --> $DIR/defaulted-never-note.rs:21:11 + --> $DIR/defaulted-never-note.rs:25:11 | LL | fn foo(_t: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` diff --git a/src/test/ui/never_type/defaulted-never-note.rs b/src/test/ui/never_type/defaulted-never-note.rs index 70333c5f324f7..54f551759cb39 100644 --- a/src/test/ui/never_type/defaulted-never-note.rs +++ b/src/test/ui/never_type/defaulted-never-note.rs @@ -1,6 +1,10 @@ +// revisions: nofallback fallback +//[nofallback] run-pass +//[fallback] check-fail + // We need to opt into the `never_type_fallback` feature // to trigger the requirement that this is testing. -#![feature(never_type, never_type_fallback)] +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] #![allow(unused)] @@ -19,16 +23,16 @@ trait ImplementedForUnitButNotNever {} impl ImplementedForUnitButNotNever for () {} fn foo(_t: T) {} -//~^ NOTE required by this bound in `foo` -//~| NOTE required by a bound in `foo` +//[fallback]~^ NOTE required by this bound in `foo` +//[fallback]~| NOTE required by a bound in `foo` fn smeg() { let _x = return; foo(_x); - //~^ ERROR the trait bound - //~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented - //~| NOTE this trait is implemented for `()` - //~| NOTE this error might have been caused - //~| HELP did you intend + //[fallback]~^ ERROR the trait bound + //[fallback]~| NOTE the trait `ImplementedForUnitButNotNever` is not implemented + //[fallback]~| NOTE this trait is implemented for `()` + //[fallback]~| NOTE this error might have been caused + //[fallback]~| HELP did you intend } fn main() { diff --git a/src/test/ui/never_type/diverging-fallback-control-flow.rs b/src/test/ui/never_type/diverging-fallback-control-flow.rs index ea4881049d792..45a3362fa6d8e 100644 --- a/src/test/ui/never_type/diverging-fallback-control-flow.rs +++ b/src/test/ui/never_type/diverging-fallback-control-flow.rs @@ -1,30 +1,28 @@ +// revisions: nofallback fallback // run-pass #![allow(dead_code)] #![allow(unused_assignments)] #![allow(unused_variables)] #![allow(unreachable_code)] - // Test various cases where we permit an unconstrained variable -// to fallback based on control-flow. -// -// These represent current behavior, but are pretty dubious. I would -// like to revisit these and potentially change them. --nmatsakis - -#![feature(never_type, never_type_fallback)] +// to fallback based on control-flow. In all of these cases, +// the type variable winds up being the target of both a `!` coercion +// and a coercion from a non-`!` variable, and hence falls back to `()`. +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] -trait BadDefault { +trait UnitDefault { fn default() -> Self; } -impl BadDefault for u32 { +impl UnitDefault for u32 { fn default() -> Self { 0 } } -impl BadDefault for ! { - fn default() -> ! { +impl UnitDefault for () { + fn default() -> () { panic!() } } @@ -33,7 +31,7 @@ fn assignment() { let x; if true { - x = BadDefault::default(); + x = UnitDefault::default(); } else { x = return; } @@ -45,13 +43,13 @@ fn assignment_rev() { if true { x = return; } else { - x = BadDefault::default(); + x = UnitDefault::default(); } } fn if_then_else() { let _x = if true { - BadDefault::default() + UnitDefault::default() } else { return; }; @@ -61,19 +59,19 @@ fn if_then_else_rev() { let _x = if true { return; } else { - BadDefault::default() + UnitDefault::default() }; } fn match_arm() { - let _x = match Ok(BadDefault::default()) { + let _x = match Ok(UnitDefault::default()) { Ok(v) => v, Err(()) => return, }; } fn match_arm_rev() { - let _x = match Ok(BadDefault::default()) { + let _x = match Ok(UnitDefault::default()) { Err(()) => return, Ok(v) => v, }; @@ -84,7 +82,7 @@ fn loop_break() { if false { break return; } else { - break BadDefault::default(); + break UnitDefault::default(); } }; } @@ -94,9 +92,9 @@ fn loop_break_rev() { if false { break return; } else { - break BadDefault::default(); + break UnitDefault::default(); } }; } -fn main() { } +fn main() {} diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr b/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr new file mode 100644 index 0000000000000..72cd69380573e --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-no-leak.fallback.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `!: Test` is not satisfied + --> $DIR/diverging-fallback-no-leak.rs:17:5 + | +LL | unconstrained_arg(return); + | ^^^^^^^^^^^^^^^^^ the trait `Test` is not implemented for `!` + | + = note: this trait is implemented for `()` + = note: this error might have been caused by changes to Rust's type-inference algorithm (see issue #48950 for more information) + = help: did you intend to use the type `()` here instead? +note: required by a bound in `unconstrained_arg` + --> $DIR/diverging-fallback-no-leak.rs:12:25 + | +LL | fn unconstrained_arg(_: T) {} + | ^^^^ required by this bound in `unconstrained_arg` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/diverging-fallback-no-leak.rs b/src/test/ui/never_type/diverging-fallback-no-leak.rs new file mode 100644 index 0000000000000..03478e19ddcdd --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-no-leak.rs @@ -0,0 +1,19 @@ +// revisions: nofallback fallback +//[nofallback] check-pass + +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] + +fn make_unit() {} + +trait Test {} +impl Test for i32 {} +impl Test for () {} + +fn unconstrained_arg(_: T) {} + +fn main() { + // Here the type variable falls back to `!`, + // and hence we get a type error. + unconstrained_arg(return); + //[fallback]~^ ERROR trait bound `!: Test` is not satisfied +} diff --git a/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs new file mode 100644 index 0000000000000..7ea97126f89c9 --- /dev/null +++ b/src/test/ui/never_type/diverging-fallback-unconstrained-return.rs @@ -0,0 +1,37 @@ +// Variant of diverging-falllback-control-flow that tests +// the specific case of a free function with an unconstrained +// return type. This captures the pattern we saw in the wild +// in the objc crate, where changing the fallback from `!` to `()` +// resulted in unsoundness. +// +// check-pass + +// revisions: nofallback fallback + +#![cfg_attr(fallback, feature(never_type, never_type_fallback))] + + +fn make_unit() {} + +trait UnitReturn {} +impl UnitReturn for i32 {} +impl UnitReturn for () {} + +fn unconstrained_return() -> T { + unsafe { + let make_unit_fn: fn() = make_unit; + let ffi: fn() -> T = std::mem::transmute(make_unit_fn); + ffi() + } +} + +fn main() { + // In Ye Olde Days, the `T` parameter of `unconstrained_return` + // winds up "entangled" with the `!` type that results from + // `panic!`, and hence falls back to `()`. This is kind of unfortunate + // and unexpected. When we introduced the `!` type, the original + // idea was to change that fallback to `!`, but that would have resulted + // in this code no longer compiling (or worse, in some cases it injected + // unsound results). + let _ = if true { unconstrained_return() } else { panic!() }; +} diff --git a/src/test/ui/never_type/fallback-closure-ret.rs b/src/test/ui/never_type/fallback-closure-ret.rs new file mode 100644 index 0000000000000..5c8ce48cbb0b6 --- /dev/null +++ b/src/test/ui/never_type/fallback-closure-ret.rs @@ -0,0 +1,23 @@ +// This test verifies that never type fallback preserves the following code in a +// compiling state. This pattern is fairly common in the wild, notably seen in +// wasmtime v0.16. Typically this is some closure wrapper that expects a +// collection of 'known' signatures, and -> ! is not included in that set. +// +// This test is specifically targeted by the unit type fallback when +// encountering a set of obligations like `?T: Foo` and `Trait::Projection = +// ?T`. In the code below, these are `R: Bar` and `Fn::Output = R`. +// +// revisions: nofallback fallback +// check-pass + +#![cfg_attr(fallback, feature(never_type_fallback))] + +trait Bar { } +impl Bar for () { } +impl Bar for u32 { } + +fn foo(_: impl Fn() -> R) {} + +fn main() { + foo(|| panic!()); +} diff --git a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr new file mode 100644 index 0000000000000..78d1a3caf4a30 --- /dev/null +++ b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -0,0 +1,17 @@ +error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 21:6] as FnOnce<()>>::Output == ()` + --> $DIR/fallback-closure-wrap.rs:18:31 + | +LL | let error = Closure::wrap(Box::new(move || { + | _______________________________^ +LL | | +LL | | panic!("Can't connect to server."); +LL | | }) as Box); + | |______^ expected `()`, found `!` + | + = note: expected unit type `()` + found type `!` + = note: required for the cast to the object type `dyn FnMut()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/never_type/fallback-closure-wrap.rs b/src/test/ui/never_type/fallback-closure-wrap.rs new file mode 100644 index 0000000000000..af0577ac0609f --- /dev/null +++ b/src/test/ui/never_type/fallback-closure-wrap.rs @@ -0,0 +1,30 @@ +// This is a minified example from Crater breakage observed when attempting to +// stabilize never type, nstoddard/webgl-gui @ 22f0169f. +// +// This particular test case currently fails as the inference to `()` rather +// than `!` happens as a result of an `as` cast, which is not currently tracked. +// Crater did not find many cases of this occuring, but it is included for +// awareness. +// +// revisions: nofallback fallback +//[nofallback] check-pass +//[fallback] check-fail + +#![cfg_attr(fallback, feature(never_type_fallback))] + +use std::marker::PhantomData; + +fn main() { + let error = Closure::wrap(Box::new(move || { + //[fallback]~^ ERROR type mismatch resolving + panic!("Can't connect to server."); + }) as Box); +} + +struct Closure(PhantomData); + +impl Closure { + fn wrap(data: Box) -> Closure { + todo!() + } +} diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr b/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr new file mode 100644 index 0000000000000..f374266626bcc --- /dev/null +++ b/src/test/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `E: From<()>` is not satisfied + --> $DIR/never-value-fallback-issue-66757.rs:27:5 + | +LL | >::from(never); + | ^^^^^^^^^^^^^^^^^^^^ the trait `From<()>` is not implemented for `E` + | + = help: the following implementations were found: + > +note: required by `from` + --> $SRC_DIR/core/src/convert/mod.rs:LL:COL + | +LL | fn from(_: T) -> Self; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/never_type/never-value-fallback-issue-66757.rs b/src/test/ui/never_type/never-value-fallback-issue-66757.rs index f2e9e087307db..6dc7e6ad2d93d 100644 --- a/src/test/ui/never_type/never-value-fallback-issue-66757.rs +++ b/src/test/ui/never_type/never-value-fallback-issue-66757.rs @@ -4,12 +4,13 @@ // never) and an uninferred variable (here the argument to `From`) it // doesn't fallback to `()` but rather `!`. // -// run-pass +// revisions: nofallback fallback +//[fallback] run-pass +//[nofallback] check-fail #![feature(never_type)] -// FIXME(#67225) -- this should be true even without the fallback gate. -#![feature(never_type_fallback)] +#![cfg_attr(fallback, feature(never_type_fallback))] struct E; @@ -23,7 +24,7 @@ impl From for E { #[allow(dead_code)] fn foo(never: !) { >::from(never); // Ok - >::from(never); // Inference fails here + >::from(never); //[nofallback]~ ERROR trait bound `E: From<()>` is not satisfied } fn main() { } diff --git a/src/test/ui/new-box-syntax.rs b/src/test/ui/new-box-syntax.rs index 418cf554b49be..c56e1dd46254f 100644 --- a/src/test/ui/new-box-syntax.rs +++ b/src/test/ui/new-box-syntax.rs @@ -5,7 +5,6 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ #![allow(dead_code, unused_variables)] -#![feature(box_syntax)] // Tests that the new `box` syntax works with unique pointers. @@ -17,12 +16,12 @@ struct Structure { } pub fn main() { - let y: Box = box 2; - let b: Box = box (1 + 2); - let c = box (3 + 4); + let y: Box = Box::new(2); + let b: Box = Box::new(1 + 2); + let c = Box::new(3 + 4); - let s: Box = box Structure { + let s: Box = Box::new(Structure { x: 3, y: 4, - }; + }); } diff --git a/src/test/ui/new-box.rs b/src/test/ui/new-box.rs index d11f0d045a7e4..96a3b197f461c 100644 --- a/src/test/ui/new-box.rs +++ b/src/test/ui/new-box.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(box_syntax)] - fn f(x: Box) { let y: &isize = &*x; println!("{}", *x); @@ -27,6 +25,6 @@ fn g(x: Box) { } fn main() { - f(box 1234); - g(box Struct as Box); + f(Box::new(1234)); + g(Box::new(Struct) as Box); } diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr index 8eded8f28572e..e9d7ca953d65b 100644 --- a/src/test/ui/nll/closure-access-spans.stderr +++ b/src/test/ui/nll/closure-access-spans.stderr @@ -8,7 +8,7 @@ LL | || x; | | | immutable borrow occurs here LL | r.use_mut(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/closure-access-spans.rs:11:5 @@ -20,7 +20,7 @@ LL | || x = 2; | | | second mutable borrow occurs here LL | r.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error[E0500]: closure requires unique access to `x` but it is already borrowed --> $DIR/closure-access-spans.rs:17:5 @@ -32,7 +32,7 @@ LL | || *x = 2; | | | closure construction occurs here LL | r.use_mut(); - | - first borrow later used here + | ----------- first borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/closure-access-spans.rs:23:13 @@ -42,7 +42,7 @@ LL | let r = &mut x; LL | move || x; | ^ use of borrowed `x` LL | r.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/closure-access-spans.rs:29:5 @@ -54,7 +54,7 @@ LL | || x; | | | move out of `x` occurs here LL | r.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:35:5 diff --git a/src/test/ui/nll/closure-borrow-spans.stderr b/src/test/ui/nll/closure-borrow-spans.stderr index fffbee4d4a8e1..bada4e1b84b52 100644 --- a/src/test/ui/nll/closure-borrow-spans.stderr +++ b/src/test/ui/nll/closure-borrow-spans.stderr @@ -8,7 +8,7 @@ LL | let f = || x.len(); LL | let y = x; | ^ move out of `x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable --> $DIR/closure-borrow-spans.rs:11:13 @@ -20,7 +20,7 @@ LL | let f = || x; LL | let y = &mut x; | ^^^^^^ mutable borrow occurs here LL | f.use_ref(); - | - immutable borrow later used here + | ----------- immutable borrow later used here error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:19:16 @@ -32,7 +32,7 @@ LL | f = || x; LL | } | - `x` dropped here while still borrowed LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-borrow-spans.rs:26:5 @@ -44,7 +44,7 @@ LL | let f = || x; LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/closure-borrow-spans.rs:32:13 @@ -56,7 +56,7 @@ LL | let f = || x = 0; LL | let y = x; | ^ use of borrowed `x` LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable --> $DIR/closure-borrow-spans.rs:38:13 @@ -68,7 +68,7 @@ LL | let f = || x = 0; LL | let y = &x; | ^^ immutable borrow occurs here LL | f.use_ref(); - | - mutable borrow later used here + | ----------- mutable borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time --> $DIR/closure-borrow-spans.rs:44:13 @@ -80,7 +80,7 @@ LL | let f = || x = 0; LL | let y = &mut x; | ^^^^^^ second mutable borrow occurs here LL | f.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:52:16 @@ -92,7 +92,7 @@ LL | f = || x = 0; LL | } | - `x` dropped here while still borrowed LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `x` because it is borrowed --> $DIR/closure-borrow-spans.rs:59:5 @@ -104,7 +104,7 @@ LL | let f = || x = 0; LL | x = 1; | ^^^^^ assignment to borrowed `x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/closure-borrow-spans.rs:65:13 @@ -116,7 +116,7 @@ LL | let f = || *x = 0; LL | let y = x; | ^ move out of `x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access --> $DIR/closure-borrow-spans.rs:71:13 @@ -128,7 +128,7 @@ LL | let f = || *x = 0; LL | let y = &x; | ^^ second borrow occurs here LL | f.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error[E0501]: cannot borrow `x` as mutable because previous closure requires unique access --> $DIR/closure-borrow-spans.rs:77:13 @@ -140,7 +140,7 @@ LL | let f = || *x = 0; LL | let y = &mut x; | ^^^^^^ second borrow occurs here LL | f.use_ref(); - | - first borrow later used here + | ----------- first borrow later used here error[E0597]: `x` does not live long enough --> $DIR/closure-borrow-spans.rs:86:16 @@ -152,7 +152,7 @@ LL | f = || *x = 0; LL | } | - `x` dropped here while still borrowed LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/closure-borrow-spans.rs:93:5 @@ -164,7 +164,7 @@ LL | let f = || *x = 0; LL | *x = 1; | ^^^^^^ assignment to borrowed `*x` occurs here LL | f.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to 14 previous errors diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index 29993b129c71a..d77793291c5c5 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -38,16 +38,19 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5 | LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | ------ `cell_a` is a reference that is only valid in the function body + | -- ------ `cell_a` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | / establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | }); - | |______^ `cell_a` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | | ^ + | | | + | |______`cell_a` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index cb505d8b1eceb..cc67270ad20c1 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -38,16 +38,19 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5 | LL | fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) { - | ------ `cell_a` is a reference that is only valid in the function body + | -- ------ `cell_a` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | / establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { LL | | LL | | LL | | // Only works if 'x: 'y: LL | | demand_y(x, y, x.get()) LL | | }); - | |______^ `cell_a` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | | ^ + | | | + | |______`cell_a` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr index 1fa3d01017af5..d0a24a267fd4f 100644 --- a/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr +++ b/src/test/ui/nll/closure-requirements/region-lbr-named-does-not-outlive-static.stderr @@ -5,8 +5,6 @@ LL | fn foo<'a>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here LL | &*x | ^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/get_default.nll.stderr b/src/test/ui/nll/get_default.nll.stderr deleted file mode 100644 index 279123069877f..0000000000000 --- a/src/test/ui/nll/get_default.nll.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable - --> $DIR/get_default.rs:21:17 - | -LL | fn ok(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` -... -LL | map.set(String::new()); // Ideally, this would not error. - | ^^^ mutable borrow occurs here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable - --> $DIR/get_default.rs:32:17 - | -LL | fn err(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | map.set(String::new()); // Both AST and MIR error here - | ^^^ mutable borrow occurs here -LL | -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable - --> $DIR/get_default.rs:37:17 - | -LL | fn err(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` -... -LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^ mutable borrow occurs here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/get_default.stderr b/src/test/ui/nll/get_default.stderr index af79771e7e1b9..6998c04336e50 100644 --- a/src/test/ui/nll/get_default.stderr +++ b/src/test/ui/nll/get_default.stderr @@ -5,7 +5,7 @@ LL | fn ok(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` LL | loop { LL | match map.get() { - | --- immutable borrow occurs here + | --------- immutable borrow occurs here LL | Some(v) => { LL | return v; | - returning this value requires that `*map` is borrowed for `'1` @@ -20,7 +20,7 @@ LL | fn err(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` LL | loop { LL | match map.get() { - | --- immutable borrow occurs here + | --------- immutable borrow occurs here LL | Some(v) => { LL | map.set(String::new()); // Both AST and MIR error here | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here @@ -35,7 +35,7 @@ LL | fn err(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` LL | loop { LL | match map.get() { - | --- immutable borrow occurs here + | --------- immutable borrow occurs here ... LL | return v; | - returning this value requires that `*map` is borrowed for `'1` diff --git a/src/test/ui/nll/issue-46589.stderr b/src/test/ui/nll/issue-46589.stderr index 82cd364eeffd0..60ef3f7b85ec4 100644 --- a/src/test/ui/nll/issue-46589.stderr +++ b/src/test/ui/nll/issue-46589.stderr @@ -2,10 +2,10 @@ error[E0499]: cannot borrow `**other` as mutable more than once at a time --> $DIR/issue-46589.rs:23:21 | LL | *other = match (*other).get_self() { - | -------- first mutable borrow occurs here + | ------------------- first mutable borrow occurs here LL | Some(s) => s, LL | None => (*other).new_self() - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | | | second mutable borrow occurs here | first borrow later used here diff --git a/src/test/ui/nll/issue-50716.nll.stderr b/src/test/ui/nll/issue-50716.nll.stderr index 7b83e4beaf387..38dd1b5f6fe73 100644 --- a/src/test/ui/nll/issue-50716.nll.stderr +++ b/src/test/ui/nll/issue-50716.nll.stderr @@ -6,8 +6,6 @@ LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) ... LL | let _x = *s; | ^^ proving this value is `Sized` requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/issue-51191.stderr b/src/test/ui/nll/issue-51191.stderr index 18696f57c44ae..9f4e971f90957 100644 --- a/src/test/ui/nll/issue-51191.stderr +++ b/src/test/ui/nll/issue-51191.stderr @@ -45,7 +45,7 @@ error[E0596]: cannot borrow data in a `&` reference as mutable --> $DIR/issue-51191.rs:22:9 | LL | (&mut self).bar(); - | ^^^^^^^^^^^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable --> $DIR/issue-51191.rs:28:9 diff --git a/src/test/ui/nll/issue-52663-trait-object.rs b/src/test/ui/nll/issue-52663-trait-object.rs index a7be365bde4bd..f6bbb2d14b003 100644 --- a/src/test/ui/nll/issue-52663-trait-object.rs +++ b/src/test/ui/nll/issue-52663-trait-object.rs @@ -1,16 +1,16 @@ -#![feature(box_syntax)] - trait Foo { fn get(&self); } impl Foo for A { fn get(&self) { } } + + fn main() { let _ = { let tmp0 = 3; let tmp1 = &tmp0; - box tmp1 as Box + Box::new(tmp1) as Box }; //~^^^ ERROR `tmp0` does not live long enough } diff --git a/src/test/ui/nll/issue-52663-trait-object.stderr b/src/test/ui/nll/issue-52663-trait-object.stderr index b71893de7f8bd..5cedea6e66520 100644 --- a/src/test/ui/nll/issue-52663-trait-object.stderr +++ b/src/test/ui/nll/issue-52663-trait-object.stderr @@ -3,8 +3,8 @@ error[E0597]: `tmp0` does not live long enough | LL | let tmp1 = &tmp0; | ^^^^^ borrowed value does not live long enough -LL | box tmp1 as Box - | ----------------------------- borrow later captured here by trait object +LL | Box::new(tmp1) as Box + | ----------------------------------- borrow later captured here by trait object LL | }; | - `tmp0` dropped here while still borrowed diff --git a/src/test/ui/nll/issue-52669.stderr b/src/test/ui/nll/issue-52669.stderr index db53e444b9e4a..807b95f7e1384 100644 --- a/src/test/ui/nll/issue-52669.stderr +++ b/src/test/ui/nll/issue-52669.stderr @@ -7,7 +7,7 @@ LL | a.b = B; LL | foo(a); | - value moved here LL | a.b.clone() - | ^^^ value borrowed here after move + | ^^^^^^^^^^^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/nll/issue-53773.stderr b/src/test/ui/nll/issue-53773.stderr index 45831460e5238..11cd423295aae 100644 --- a/src/test/ui/nll/issue-53773.stderr +++ b/src/test/ui/nll/issue-53773.stderr @@ -7,7 +7,7 @@ LL | LL | } | - here, drop of `child` needs exclusive access to `*child.raw`, because the type `C<'_>` implements the `Drop` trait LL | members.len(); - | ------- borrow later used here + | ------------- borrow later used here | = note: consider using a `let` binding to create a longer lived value diff --git a/src/test/ui/nll/issue-54556-niconii.stderr b/src/test/ui/nll/issue-54556-niconii.stderr index 70f063ca0e833..a8e1edc549742 100644 --- a/src/test/ui/nll/issue-54556-niconii.stderr +++ b/src/test/ui/nll/issue-54556-niconii.stderr @@ -2,7 +2,7 @@ error[E0597]: `counter` does not live long enough --> $DIR/issue-54556-niconii.rs:22:20 | LL | if let Ok(_) = counter.lock() { } - | ^^^^^^^------- + | ^^^^^^^^^^^^^^ | | | borrowed value does not live long enough | a temporary with access to the borrow is created here ... diff --git a/src/test/ui/nll/issue-55401.nll.stderr b/src/test/ui/nll/issue-55401.nll.stderr index df320aa0844ad..4f797f26a1a7c 100644 --- a/src/test/ui/nll/issue-55401.nll.stderr +++ b/src/test/ui/nll/issue-55401.nll.stderr @@ -6,8 +6,6 @@ LL | fn static_to_a_to_static_through_ref_in_tuple<'a>(x: &'a u32) -> &'static u LL | let (ref y, _z): (&'a u32, u32) = (&22, 44); LL | *y | ^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/issue-55825-const-fn.rs b/src/test/ui/nll/issue-55825-const-fn.rs new file mode 100644 index 0000000000000..c9efccd15b7c5 --- /dev/null +++ b/src/test/ui/nll/issue-55825-const-fn.rs @@ -0,0 +1,8 @@ +// Regression test for issue #55825 +// Tests that we don't emit a spurious warning in NLL mode + +#![feature(nll)] + +const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~ ERROR const + +fn main() { } diff --git a/src/test/ui/nll/issue-55825-const-fn.stderr b/src/test/ui/nll/issue-55825-const-fn.stderr new file mode 100644 index 0000000000000..9af5180343bf2 --- /dev/null +++ b/src/test/ui/nll/issue-55825-const-fn.stderr @@ -0,0 +1,12 @@ +error[E0658]: trait objects in const fn are unstable + --> $DIR/issue-55825-const-fn.rs:6:32 + | +LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/nll/issue-58299.stderr b/src/test/ui/nll/issue-58299.stderr index 5be4e56171c52..aba07542d026e 100644 --- a/src/test/ui/nll/issue-58299.stderr +++ b/src/test/ui/nll/issue-58299.stderr @@ -6,8 +6,6 @@ LL | fn foo<'a>(x: i32) { ... LL | A::<'a>::X..=A::<'static>::X => (), | ^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-58299.rs:24:27 @@ -17,8 +15,6 @@ LL | fn bar<'a>(x: i32) { ... LL | A::<'static>::X..=A::<'a>::X => (), | ^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/issue-62007-assign-const-index.stderr b/src/test/ui/nll/issue-62007-assign-const-index.stderr index 0db9fe62c3869..12e28aa3fba0e 100644 --- a/src/test/ui/nll/issue-62007-assign-const-index.stderr +++ b/src/test/ui/nll/issue-62007-assign-const-index.stderr @@ -17,7 +17,7 @@ LL | fn to_refs(mut list: [&mut List; 2]) -> Vec<&mut T> { | - let's call the lifetime of this reference `'1` ... LL | if let Some(n) = list[0].next.as_mut() { - | ^^^^^^^^^^^^--------- + | ^^^^^^^^^^^^^^^^^^^^^ | | | `list[_].next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list[_].next` is borrowed for `'1` diff --git a/src/test/ui/nll/issue-62007-assign-differing-fields.stderr b/src/test/ui/nll/issue-62007-assign-differing-fields.stderr index f1af2e855afe6..4488431fc5737 100644 --- a/src/test/ui/nll/issue-62007-assign-differing-fields.stderr +++ b/src/test/ui/nll/issue-62007-assign-differing-fields.stderr @@ -17,7 +17,7 @@ LL | fn to_refs<'a, T>(mut list: (&'a mut List, &'a mut List)) -> Vec<&'a | -- lifetime `'a` defined here ... LL | if let Some(n) = (list.0).next.as_mut() { - | ^^^^^^^^^^^^^--------- + | ^^^^^^^^^^^^^^^^^^^^^^ | | | `list.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.next` is borrowed for `'a` diff --git a/src/test/ui/nll/issue-67007-escaping-data.rs b/src/test/ui/nll/issue-67007-escaping-data.rs new file mode 100644 index 0000000000000..8c21737e05fe8 --- /dev/null +++ b/src/test/ui/nll/issue-67007-escaping-data.rs @@ -0,0 +1,26 @@ +// Regression test for issue #67007 +// Ensures that we show information about the specific regions involved + +#![feature(nll)] + +// Covariant over 'a, invariant over 'tcx +struct FnCtxt<'a, 'tcx: 'a>(&'a (), *mut &'tcx ()); + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + fn use_it(&self, _: &'tcx ()) {} +} + +struct Consumer<'tcx>(&'tcx ()); + +impl<'tcx> Consumer<'tcx> { + fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { + let other = self.use_fcx(fcx); //~ ERROR borrowed data + fcx.use_it(other); + } + + fn use_fcx<'a>(&self, _: &FnCtxt<'a, 'tcx>) -> &'a () { + &() + } +} + +fn main() {} diff --git a/src/test/ui/nll/issue-67007-escaping-data.stderr b/src/test/ui/nll/issue-67007-escaping-data.stderr new file mode 100644 index 0000000000000..2834d6fb0d214 --- /dev/null +++ b/src/test/ui/nll/issue-67007-escaping-data.stderr @@ -0,0 +1,21 @@ +error[E0521]: borrowed data escapes outside of associated function + --> $DIR/issue-67007-escaping-data.rs:17:21 + | +LL | impl<'tcx> Consumer<'tcx> { + | ---- lifetime `'tcx` defined here +LL | fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) { + | -- ----- --- `fcx` is a reference that is only valid in the associated function body + | | | + | | `self` declared here, outside of the associated function body + | lifetime `'a` defined here +LL | let other = self.use_fcx(fcx); + | ^^^^^^^^^^^^^^^^^ + | | + | `fcx` escapes the associated function body here + | argument requires that `'a` must outlive `'tcx` + | + = help: consider adding the following bound: `'a: 'tcx` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/nll/issue-73159-rpit-static.rs b/src/test/ui/nll/issue-73159-rpit-static.rs new file mode 100644 index 0000000000000..a5455a3f9eb7b --- /dev/null +++ b/src/test/ui/nll/issue-73159-rpit-static.rs @@ -0,0 +1,14 @@ +// Regression test for issue #73159 +// Tests thar we don't suggest replacing 'a with 'static' + +#![feature(nll)] + +struct Foo<'a>(&'a [u8]); + +impl<'a> Foo<'a> { + fn make_it(&self) -> impl Iterator { //~ ERROR lifetime may not live + self.0.iter().copied() + } +} + +fn main() {} diff --git a/src/test/ui/nll/issue-73159-rpit-static.stderr b/src/test/ui/nll/issue-73159-rpit-static.stderr new file mode 100644 index 0000000000000..60b1552701af9 --- /dev/null +++ b/src/test/ui/nll/issue-73159-rpit-static.stderr @@ -0,0 +1,10 @@ +error: lifetime may not live long enough + --> $DIR/issue-73159-rpit-static.rs:9:26 + | +LL | impl<'a> Foo<'a> { + | -- lifetime `'a` defined here +LL | fn make_it(&self) -> impl Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static` + +error: aborting due to previous error + diff --git a/src/test/ui/nll/loan_ends_mid_block_vec.stderr b/src/test/ui/nll/loan_ends_mid_block_vec.stderr index c0b97bea348c4..22c72af61d625 100644 --- a/src/test/ui/nll/loan_ends_mid_block_vec.stderr +++ b/src/test/ui/nll/loan_ends_mid_block_vec.stderr @@ -5,7 +5,7 @@ LL | let slice = &mut data; | --------- first mutable borrow occurs here LL | capitalize(slice); LL | data.push('d'); - | ^^^^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^ second mutable borrow occurs here ... LL | capitalize(slice); | ----- first borrow later used here @@ -17,7 +17,7 @@ LL | let slice = &mut data; | --------- first mutable borrow occurs here ... LL | data.push('e'); - | ^^^^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^ second mutable borrow occurs here ... LL | capitalize(slice); | ----- first borrow later used here @@ -29,7 +29,7 @@ LL | let slice = &mut data; | --------- first mutable borrow occurs here ... LL | data.push('f'); - | ^^^^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^ second mutable borrow occurs here LL | LL | capitalize(slice); | ----- first borrow later used here diff --git a/src/test/ui/nll/mir_check_cast_reify.stderr b/src/test/ui/nll/mir_check_cast_reify.stderr index 1722da8f343de..4e8eec330a579 100644 --- a/src/test/ui/nll/mir_check_cast_reify.stderr +++ b/src/test/ui/nll/mir_check_cast_reify.stderr @@ -6,8 +6,6 @@ LL | fn bar<'a>(x: &'a u32) -> &'static u32 { ... LL | f(x) | ^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr b/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr index c87425ecfc0fa..52959850a3332 100644 --- a/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr +++ b/src/test/ui/nll/mir_check_cast_unsafe_fn.stderr @@ -6,8 +6,6 @@ LL | fn bar<'a>(input: &'a u32, f: fn(&'a u32) -> &'a u32) -> &'static u32 { ... LL | unsafe { g(input) } | ^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/mir_check_cast_unsize.stderr b/src/test/ui/nll/mir_check_cast_unsize.stderr index cb7328d117984..364d6c17ea7f6 100644 --- a/src/test/ui/nll/mir_check_cast_unsize.stderr +++ b/src/test/ui/nll/mir_check_cast_unsize.stderr @@ -5,8 +5,6 @@ LL | fn bar<'a>(x: &'a u32) -> &'static dyn Debug { | -- lifetime `'a` defined here LL | x | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/outlives-suggestion-more.stderr b/src/test/ui/nll/outlives-suggestion-more.stderr index 2ebcbf5cbafda..a80e59d4822fb 100644 --- a/src/test/ui/nll/outlives-suggestion-more.stderr +++ b/src/test/ui/nll/outlives-suggestion-more.stderr @@ -46,8 +46,6 @@ LL | fn foo2<'a, 'b, 'c>(x: &'a usize, y: &'b usize) -> (&'c usize, &'static usi | -- lifetime `'b` defined here LL | (x, y) | ^^^^^^ returning this value requires that `'b` must outlive `'static` - | - = help: consider replacing `'b` with `'static` help: the following changes may resolve your lifetime errors | @@ -88,8 +86,6 @@ LL | fn foo3<'a, 'b, 'c, 'd, 'e>( ... LL | (x, y, z) | ^^^^^^^^^ returning this value requires that `'c` must outlive `'static` - | - = help: consider replacing `'c` with `'static` help: the following changes may resolve your lifetime errors | diff --git a/src/test/ui/nll/outlives-suggestion-simple.stderr b/src/test/ui/nll/outlives-suggestion-simple.stderr index bfe98a71a99b1..3b2017d2d03a1 100644 --- a/src/test/ui/nll/outlives-suggestion-simple.stderr +++ b/src/test/ui/nll/outlives-suggestion-simple.stderr @@ -17,8 +17,6 @@ LL | fn foo2<'a>(x: &'a usize) -> &'static usize { | -- lifetime `'a` defined here LL | x | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/outlives-suggestion-simple.rs:14:5 @@ -66,8 +64,6 @@ LL | pub fn foo<'a>(x: &'a usize) -> Self { | -- lifetime `'a` defined here LL | Foo { x } | ^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/outlives-suggestion-simple.rs:41:9 @@ -96,13 +92,20 @@ LL | self.x error[E0521]: borrowed data escapes outside of associated function --> $DIR/outlives-suggestion-simple.rs:73:9 | +LL | impl<'a> Foo2<'a> { + | -- lifetime `'a` defined here +LL | // should not produce outlives suggestions to name 'self LL | fn get_bar(&self) -> Bar2 { | ----- | | | `self` declared here, outside of the associated function body | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` LL | Bar2::new(&self) - | ^^^^^^^^^^^^^^^^ `self` escapes the associated function body here + | ^^^^^^^^^^^^^^^^ + | | + | `self` escapes the associated function body here + | argument requires that `'1` must outlive `'a` error: aborting due to 9 previous errors diff --git a/src/test/ui/nll/polonius/assignment-to-differing-field.stderr b/src/test/ui/nll/polonius/assignment-to-differing-field.stderr index 2fe6a53a49aef..fd5e4531b2e67 100644 --- a/src/test/ui/nll/polonius/assignment-to-differing-field.stderr +++ b/src/test/ui/nll/polonius/assignment-to-differing-field.stderr @@ -17,7 +17,7 @@ LL | fn assignment_to_field_projection<'a, T>( | -- lifetime `'a` defined here ... LL | if let Some(n) = (list.0).next.as_mut() { - | ^^^^^^^^^^^^^--------- + | ^^^^^^^^^^^^^^^^^^^^^^ | | | `list.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.next` is borrowed for `'a` @@ -41,7 +41,7 @@ LL | fn assignment_through_projection_chain<'a, T>( | -- lifetime `'a` defined here ... LL | if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^--------- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop | argument requires that `list.0.0.0.0.0.next` is borrowed for `'a` diff --git a/src/test/ui/nll/region-ends-after-if-condition.nll.stderr b/src/test/ui/nll/region-ends-after-if-condition.nll.stderr deleted file mode 100644 index 322930984a545..0000000000000 --- a/src/test/ui/nll/region-ends-after-if-condition.nll.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable - --> $DIR/region-ends-after-if-condition.rs:26:9 - | -LL | let value = &my_struct.field; - | ---------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | drop(value); - | ----- immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/relate_tys/fn-subtype.stderr b/src/test/ui/nll/relate_tys/fn-subtype.stderr index 94def69008677..6256c4a01d386 100644 --- a/src/test/ui/nll/relate_tys/fn-subtype.stderr +++ b/src/test/ui/nll/relate_tys/fn-subtype.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let y: for<'a> fn(&'a ()) = x; | ^ one type is more general than the other | - = note: expected fn pointer `for<'r> fn(&'r ())` + = note: expected fn pointer `for<'a> fn(&'a ())` found fn pointer `fn(&())` error: aborting due to previous error diff --git a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr index 8c1eaeb6aa7b9..b839015f97f61 100644 --- a/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr +++ b/src/test/ui/nll/relate_tys/hr-fn-aaa-as-aba.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let a: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it(); | ^^^^^^^^^ one type is more general than the other | - = note: expected fn pointer `for<'r, 's> fn(&'r u32, &'s u32) -> &'r u32` + = note: expected fn pointer `for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32` found fn pointer `for<'a> fn(&'a u32, &'a u32) -> &'a u32` error[E0308]: mismatched types @@ -14,7 +14,7 @@ LL | let _: for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 = make_it(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | = note: expected fn pointer `for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32` - found fn pointer `for<'r> fn(&'r u32, &'r u32) -> &'r u32` + found fn pointer `for<'a> fn(&'a u32, &'a u32) -> &'a u32` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/relate_tys/trait-hrtb.stderr b/src/test/ui/nll/relate_tys/trait-hrtb.stderr index 60a7f20444680..6d144a4be6ed3 100644 --- a/src/test/ui/nll/relate_tys/trait-hrtb.stderr +++ b/src/test/ui/nll/relate_tys/trait-hrtb.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let y: Box Foo<'a>> = x; | ^ one type is more general than the other | - = note: expected trait object `dyn for<'r> Foo<'r>` + = note: expected trait object `dyn for<'a> Foo<'a>` found trait object `dyn Foo<'_>` error: aborting due to previous error diff --git a/src/test/ui/nll/return_from_loop.stderr b/src/test/ui/nll/return_from_loop.stderr index efd56ea2dd542..bd2b8b158598a 100644 --- a/src/test/ui/nll/return_from_loop.stderr +++ b/src/test/ui/nll/return_from_loop.stderr @@ -5,10 +5,10 @@ LL | let value = &mut my_struct.field; | -------------------- first mutable borrow occurs here LL | loop { LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ second mutable borrow occurs here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here LL | LL | value.len(); - | ----- first borrow later used here + | ----------- first borrow later used here error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr index f15c2ffd0d7eb..9128fd1647959 100644 --- a/src/test/ui/nll/ty-outlives/wf-unreachable.stderr +++ b/src/test/ui/nll/ty-outlives/wf-unreachable.stderr @@ -6,8 +6,6 @@ LL | fn uninit<'a>() { LL | return; LL | let x: &'static &'a (); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:13:12 @@ -17,8 +15,6 @@ LL | fn var_type<'a>() { LL | return; LL | let x: &'static &'a () = &&(); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:17:12 @@ -27,8 +23,6 @@ LL | fn uninit_infer<'a>() { | -- lifetime `'a` defined here LL | let x: &'static &'a _; | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:23:12 @@ -38,8 +32,6 @@ LL | fn infer<'a>() { LL | return; LL | let x: &'static &'a _ = &&(); | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:28:12 @@ -49,8 +41,6 @@ LL | fn uninit_no_var<'a>() { LL | return; LL | let _: &'static &'a (); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:33:12 @@ -60,8 +50,6 @@ LL | fn no_var<'a>() { LL | return; LL | let _: &'static &'a () = &&(); | ^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:38:12 @@ -71,8 +59,6 @@ LL | fn infer_no_var<'a>() { LL | return; LL | let _: &'static &'a _ = &&(); | ^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/wf-unreachable.rs:51:12 @@ -82,8 +68,6 @@ LL | fn required_substs<'a>() { LL | return; LL | let _: C<'static, 'a, _> = C((), &(), &()); | ^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 8 previous errors diff --git a/src/test/ui/nll/user-annotations/closure-substs.stderr b/src/test/ui/nll/user-annotations/closure-substs.stderr index 37e751aeb67b7..20002e4591d1a 100644 --- a/src/test/ui/nll/user-annotations/closure-substs.stderr +++ b/src/test/ui/nll/user-annotations/closure-substs.stderr @@ -6,8 +6,6 @@ LL | fn foo<'a>() { ... LL | return x; | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/closure-substs.rs:15:16 @@ -25,16 +23,19 @@ LL | fn bar<'a>() { ... LL | b(x); | ^^^^ argument requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error[E0521]: borrowed data escapes outside of closure --> $DIR/closure-substs.rs:29:9 | LL | |x: &i32, b: fn(&'static i32)| { - | - `x` is a reference that is only valid in the closure body + | - - let's call the lifetime of this reference `'1` + | | + | `x` is a reference that is only valid in the closure body LL | b(x); - | ^^^^ `x` escapes the closure body here + | ^^^^ + | | + | `x` escapes the closure body here + | argument requires that `'1` must outlive `'static` error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr index e9a0b8173ceaa..c39301588acfa 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.nll.stderr @@ -5,8 +5,6 @@ LL | fn foo<'a>(_: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here LL | >::C | ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr index 52ec36ef542cc..541a2cfaf299a 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-normalize.nll.stderr @@ -5,8 +5,6 @@ LL | fn foo<'a>(_: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here LL | <() as Foo<'a>>::C | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr index 5f3212eb9aa34..ea0fcb6d634cd 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-1.nll.stderr @@ -5,8 +5,6 @@ LL | fn foo<'a>(_: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here LL | <() as Foo<'a>>::C | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr index 490030d30f317..ff549f1d88bd4 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-2.nll.stderr @@ -5,8 +5,6 @@ LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { | -- lifetime `'a` defined here LL | >::C | ^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr index 5e687805c6fc3..7f160d8e398b9 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-trait-item-3.nll.stderr @@ -5,8 +5,6 @@ LL | fn foo<'a, T: Foo<'a>>() -> &'static u32 { | -- lifetime `'a` defined here LL | T::C | ^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr b/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr index 7b5646de775ab..768454698987e 100644 --- a/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr +++ b/src/test/ui/nll/user-annotations/inherent-associated-constants.stderr @@ -5,8 +5,6 @@ LL | fn non_wf_associated_const<'a>(x: i32) { | -- lifetime `'a` defined here LL | A::<'a>::IC; | ^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/nll/user-annotations/issue-54124.stderr b/src/test/ui/nll/user-annotations/issue-54124.stderr index 97653b8c199c8..6cfccf7cb69ce 100644 --- a/src/test/ui/nll/user-annotations/issue-54124.stderr +++ b/src/test/ui/nll/user-annotations/issue-54124.stderr @@ -15,8 +15,6 @@ LL | fn test<'a>() { | -- lifetime `'a` defined here LL | let _:fn(&()) = |_:&'a ()| {}; | ^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr index f23ea9fdb5c31..5929707e41e10 100644 --- a/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr +++ b/src/test/ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.stderr @@ -6,8 +6,6 @@ LL | fn coupled_regions_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-55748-pat-types-constrain-bindings.rs:49:5 @@ -17,8 +15,6 @@ LL | fn coupled_types_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-55748-pat-types-constrain-bindings.rs:62:5 @@ -28,8 +24,6 @@ LL | fn coupled_wilds_lhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 3 previous errors diff --git a/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr index 426c57ef9c4e7..c99f53c5aa4c5 100644 --- a/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr +++ b/src/test/ui/nll/user-annotations/issue-57731-ascibed-coupled-types.stderr @@ -6,8 +6,6 @@ LL | fn coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { LL | let ((y, _z),) = ((s, _x),): (PairCoupledTypes<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-57731-ascibed-coupled-types.rs:22:5 @@ -17,8 +15,6 @@ LL | fn coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 { LL | let ((y, _z),) = ((s, _x),): (PairCoupledRegions<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-57731-ascibed-coupled-types.rs:32:5 @@ -28,8 +24,6 @@ LL | fn cast_coupled_wilds_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u32 LL | let ((y, _z),) = ((s, _x),) as (PairCoupledTypes<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/issue-57731-ascibed-coupled-types.rs:37:5 @@ -39,8 +33,6 @@ LL | fn cast_coupled_regions_rhs<'a>(_x: &'a u32, s: &'static u32) -> &'static u LL | let ((y, _z),) = ((s, _x),) as (PairCoupledRegions<_>,); LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr index c2786f0e8cca2..7ebd0ae227a80 100644 --- a/src/test/ui/nll/user-annotations/patterns.stderr +++ b/src/test/ui/nll/user-annotations/patterns.stderr @@ -156,8 +156,6 @@ LL | fn static_to_a_to_static_through_variable<'a>(x: &'a u32) -> &'static u32 { ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/patterns.rs:125:5 @@ -167,8 +165,6 @@ LL | fn static_to_a_to_static_through_tuple<'a>(x: &'a u32) -> &'static u32 { ... LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/patterns.rs:130:5 @@ -178,8 +174,6 @@ LL | fn static_to_a_to_static_through_struct<'a>(_x: &'a u32) -> &'static u32 { LL | let Single { value: y }: Single<&'a u32> = Single { value: &22 }; LL | y | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/patterns.rs:134:18 @@ -188,8 +182,6 @@ LL | fn a_to_static_then_static<'a>(x: &'a u32) -> &'static u32 { | -- lifetime `'a` defined here LL | let (y, _z): (&'static u32, u32) = (x, 44); | ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 19 previous errors diff --git a/src/test/ui/no_crate_type.stderr b/src/test/ui/no_crate_type.stderr index f34df4e2dd143..93da7c3e0ddd6 100644 --- a/src/test/ui/no_crate_type.stderr +++ b/src/test/ui/no_crate_type.stderr @@ -2,7 +2,7 @@ error: malformed `crate_type` attribute input --> $DIR/no_crate_type.rs:2:1 | LL | #![crate_type] - | ^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]` + | ^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]` error: aborting due to previous error diff --git a/src/test/ui/nullable-pointer-iotareduction.rs b/src/test/ui/nullable-pointer-iotareduction.rs index 568c3e144be2c..f9edba6743499 100644 --- a/src/test/ui/nullable-pointer-iotareduction.rs +++ b/src/test/ui/nullable-pointer-iotareduction.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(box_syntax)] - // Iota-reduction is a rule in the Calculus of (Co-)Inductive Constructions, // which "says that a destructor applied to an object built from a constructor // behaves as expected". -- https://coq.inria.fr/doc/language/core/conversion.html#iota-reduction @@ -64,7 +62,7 @@ macro_rules! check_type { pub fn main() { check_type!(&17, &isize); - check_type!(box 18, Box); + check_type!(Box::new(18), Box); check_type!("foo".to_string(), String); check_type!(vec![20, 22], Vec); check_type!(main, fn(), |pthing| { diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr index defffe2b84b0d..7d6f9f39d13ed 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.nll.stderr @@ -5,8 +5,6 @@ LL | fn c<'a>(t: &'a Box, mut ss: SomeStruct<'a>) { | -- lifetime `'a` defined here LL | ss.t = t; | ^^^^^^^^ assignment requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr index 8c28a7a011aba..6df54638ce004 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-struct-error.nll.stderr @@ -5,8 +5,6 @@ LL | fn c<'a>(t: &'a MyBox, mut ss: SomeStruct<'a>) { | -- lifetime `'a` defined here LL | ss.t = t; | ^^^^^^^^ assignment requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr index 42dae7e40dbb3..af20c5e5fc0da 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr @@ -15,11 +15,14 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/object-lifetime-default-mybox.rs:31:5 | LL | fn load2<'a>(ss: &MyBox) -> MyBox { - | -- `ss` is a reference that is only valid in the function body + | -- -- `ss` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | load0(ss) - | ^^^^^^^^^ `ss` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^ + | | + | `ss` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 2 previous errors diff --git a/src/test/ui/object-safety/object-safety-by-value-self-use.stderr b/src/test/ui/object-safety/object-safety-by-value-self-use.stderr index 1497aa42082d1..7ccc0cbdd576b 100644 --- a/src/test/ui/object-safety/object-safety-by-value-self-use.stderr +++ b/src/test/ui/object-safety/object-safety-by-value-self-use.stderr @@ -2,7 +2,7 @@ error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be --> $DIR/object-safety-by-value-self-use.rs:15:5 | LL | t.bar() - | ^ + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/objects-owned-object-borrowed-method-headerless.rs b/src/test/ui/objects-owned-object-borrowed-method-headerless.rs index 9b88d8ea7bcd9..fce1341fc7415 100644 --- a/src/test/ui/objects-owned-object-borrowed-method-headerless.rs +++ b/src/test/ui/objects-owned-object-borrowed-method-headerless.rs @@ -3,9 +3,6 @@ // closed over do not contain managed values, and thus the boxes do // not have headers. -#![feature(box_syntax)] - - trait FooTrait { fn foo(&self) -> usize; } @@ -22,9 +19,9 @@ impl FooTrait for BarStruct { pub fn main() { let foos: Vec> = vec![ - box BarStruct{ x: 0 } as Box, - box BarStruct{ x: 1 } as Box, - box BarStruct{ x: 2 } as Box + Box::new(BarStruct{ x: 0 }) as Box, + Box::new(BarStruct{ x: 1 }) as Box, + Box::new(BarStruct{ x: 2 }) as Box, ]; for i in 0..foos.len() { diff --git a/src/test/ui/objects-owned-object-owned-method.rs b/src/test/ui/objects-owned-object-owned-method.rs index 4b7b68f22176f..15677a5185c2f 100644 --- a/src/test/ui/objects-owned-object-owned-method.rs +++ b/src/test/ui/objects-owned-object-owned-method.rs @@ -3,8 +3,6 @@ // closed over contain managed values. This implies that the boxes // will have headers that must be skipped over. -#![feature(box_syntax)] - trait FooTrait { fn foo(self: Box) -> usize; } @@ -20,6 +18,6 @@ impl FooTrait for BarStruct { } pub fn main() { - let foo = box BarStruct{ x: 22 } as Box; + let foo = Box::new(BarStruct{ x: 22 }) as Box; assert_eq!(22, foo.foo()); } diff --git a/src/test/ui/occurs-check-2.rs b/src/test/ui/occurs-check-2.rs index 213fd2619cee7..f36682a3dd821 100644 --- a/src/test/ui/occurs-check-2.rs +++ b/src/test/ui/occurs-check-2.rs @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - fn main() { + let f; let g; + g = f; - f = box g; + f = Box::new(g); //~^ ERROR mismatched types //~| cyclic type of infinite size } diff --git a/src/test/ui/occurs-check-2.stderr b/src/test/ui/occurs-check-2.stderr index c004043307899..dcbfc81b4d519 100644 --- a/src/test/ui/occurs-check-2.stderr +++ b/src/test/ui/occurs-check-2.stderr @@ -1,13 +1,10 @@ error[E0308]: mismatched types --> $DIR/occurs-check-2.rs:7:9 | -LL | f = box g; - | ^^^^^ cyclic type of infinite size - | -help: try using a conversion method - | -LL | f = (box g).to_string(); - | + +++++++++++++ +LL | f = Box::new(g); + | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | cyclic type of infinite size error: aborting due to previous error diff --git a/src/test/ui/occurs-check.rs b/src/test/ui/occurs-check.rs index 5f2c2362d24cd..aec52d839766a 100644 --- a/src/test/ui/occurs-check.rs +++ b/src/test/ui/occurs-check.rs @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn main() { + let f; - f = box f; + + f = Box::new(f); //~^ ERROR mismatched types //~| cyclic type of infinite size } diff --git a/src/test/ui/occurs-check.stderr b/src/test/ui/occurs-check.stderr index 452163e2fa5ee..3e1ef2e719ad5 100644 --- a/src/test/ui/occurs-check.stderr +++ b/src/test/ui/occurs-check.stderr @@ -1,13 +1,10 @@ error[E0308]: mismatched types --> $DIR/occurs-check.rs:5:9 | -LL | f = box f; - | ^^^^^ cyclic type of infinite size - | -help: try using a conversion method - | -LL | f = (box f).to_string(); - | + +++++++++++++ +LL | f = Box::new(f); + | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | cyclic type of infinite size error: aborting due to previous error diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 5406d51c644a5..c94adfe4ab38a 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -30,7 +30,22 @@ LL | let _ = |A | B: E| (); | | | E | - = note: an implementation of `std::ops::BitOr` might be missing for `E` +note: an implementation of `BitOr<_>` might be missing for `E` + --> $DIR/or-patterns-syntactic-fail.rs:6:1 + | +LL | enum E { A, B } + | ^^^^^^ must implement `BitOr<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/bit.rs:LL:COL + | +LL | / pub trait BitOr { +LL | | /// The resulting type after applying the `|` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn bitor(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error: aborting due to 5 previous errors diff --git a/src/test/ui/output-slot-variants.rs b/src/test/ui/output-slot-variants.rs index af4caf7566996..7c20a2b2f94e8 100644 --- a/src/test/ui/output-slot-variants.rs +++ b/src/test/ui/output-slot-variants.rs @@ -7,22 +7,21 @@ #![allow(dead_assignment)] #![allow(unused_variables)] -#![feature(box_syntax)] struct A { a: isize, b: isize } struct Abox { a: Box, b: Box } fn ret_int_i() -> isize { 10 } -fn ret_ext_i() -> Box { box 10 } +fn ret_ext_i() -> Box { Box::new(10) } fn ret_int_rec() -> A { A {a: 10, b: 10} } -fn ret_ext_rec() -> Box { box A {a: 10, b: 10} } +fn ret_ext_rec() -> Box { Box::new(A {a: 10, b: 10}) } -fn ret_ext_mem() -> Abox { Abox {a: box 10, b: box 10} } +fn ret_ext_mem() -> Abox { Abox {a: Box::new(10), b: Box::new(10) } } -fn ret_ext_ext_mem() -> Box { box Abox{a: box 10, b: box 10} } +fn ret_ext_ext_mem() -> Box { Box::new(Abox{a: Box::new(10), b: Box::new(10) }) } pub fn main() { let mut int_i: isize; diff --git a/src/test/ui/overloaded/overloaded-autoderef.rs b/src/test/ui/overloaded/overloaded-autoderef.rs index e850633e34fee..cae3ec906211e 100644 --- a/src/test/ui/overloaded/overloaded-autoderef.rs +++ b/src/test/ui/overloaded/overloaded-autoderef.rs @@ -2,8 +2,6 @@ #![allow(unused_variables)] #![allow(stable_features)] -#![feature(box_syntax, core)] - use std::cell::RefCell; use std::rc::Rc; @@ -14,7 +12,7 @@ struct Point { } pub fn main() { - let box_5: Box<_> = box 5_usize; + let box_5: Box<_> = Box::new(5_usize); let point = Rc::new(Point {x: 2, y: 4}); assert_eq!(point.x, 2); assert_eq!(point.y, 4); diff --git a/src/test/ui/overloaded/overloaded-index-autoderef.rs b/src/test/ui/overloaded/overloaded-index-autoderef.rs index 6996ee32933c0..41f9efa8c1619 100644 --- a/src/test/ui/overloaded/overloaded-index-autoderef.rs +++ b/src/test/ui/overloaded/overloaded-index-autoderef.rs @@ -3,8 +3,6 @@ // Test overloaded indexing combined with autoderef. -#![feature(box_syntax, core)] - use std::ops::{Index, IndexMut}; struct Foo { @@ -47,10 +45,10 @@ impl Int for isize { } fn main() { - let mut f: Box<_> = box Foo { + let mut f: Box<_> = Box::new(Foo { x: 1, y: 2, - }; + }); assert_eq!(f[1], 2); diff --git a/src/test/ui/panics/args-panic.rs b/src/test/ui/panics/args-panic.rs index 322054caf1161..7636025c25b83 100644 --- a/src/test/ui/panics/args-panic.rs +++ b/src/test/ui/panics/args-panic.rs @@ -2,12 +2,10 @@ // error-pattern:meep // ignore-emscripten no processes -#![feature(box_syntax)] - fn f(_a: isize, _b: isize, _c: Box) { panic!("moop"); } fn main() { - f(1, panic!("meep"), box 42); + f(1, panic!("meep"), Box::new(42)); } diff --git a/src/test/ui/panics/panic-macro-any.rs b/src/test/ui/panics/panic-macro-any.rs index 08acc6e8078f9..c7df5365474e9 100644 --- a/src/test/ui/panics/panic-macro-any.rs +++ b/src/test/ui/panics/panic-macro-any.rs @@ -2,9 +2,8 @@ // error-pattern:panicked at 'Box' // ignore-emscripten no processes -#![feature(box_syntax)] #![allow(non_fmt_panics)] fn main() { - panic!(box 413 as Box); + panic!(Box::new(413) as Box); } diff --git a/src/test/ui/parser/issue-88770.rs b/src/test/ui/parser/issue-88770.rs new file mode 100644 index 0000000000000..bf89033f560e9 --- /dev/null +++ b/src/test/ui/parser/issue-88770.rs @@ -0,0 +1,11 @@ +// Regression test for the ICE described in #88770. + +// error-pattern:this file contains an unclosed delimiter +// error-pattern:expected one of +// error-pattern:missing `in` in `for` loop +// error-pattern:expected `;`, found `e` + +fn m(){print!("",(c for&g +u +e +e diff --git a/src/test/ui/parser/issue-88770.stderr b/src/test/ui/parser/issue-88770.stderr new file mode 100644 index 0000000000000..c7e24155d1692 --- /dev/null +++ b/src/test/ui/parser/issue-88770.stderr @@ -0,0 +1,66 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-88770.rs:11:3 + | +LL | fn m(){print!("",(c for&g + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +... +LL | e + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-88770.rs:11:3 + | +LL | fn m(){print!("",(c for&g + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +... +LL | e + | ^ + +error: this file contains an unclosed delimiter + --> $DIR/issue-88770.rs:11:3 + | +LL | fn m(){print!("",(c for&g + | - - - unclosed delimiter + | | | + | | unclosed delimiter + | unclosed delimiter +... +LL | e + | ^ + +error: missing `in` in `for` loop + --> $DIR/issue-88770.rs:8:26 + | +LL | fn m(){print!("",(c for&g + | __________________________^ +LL | | u + | |_ help: try adding `in` here + +error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found keyword `for` + --> $DIR/issue-88770.rs:8:21 + | +LL | fn m(){print!("",(c for&g + | ^^^ expected one of 8 possible tokens + +error: expected `;`, found `e` + --> $DIR/issue-88770.rs:10:2 + | +LL | e + | ^ help: add `;` here +LL | e + | - unexpected token + +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `)` + --> $DIR/issue-88770.rs:11:3 + | +LL | e + | ^ expected one of 7 possible tokens + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/parser/issue-89388.rs b/src/test/ui/parser/issue-89388.rs new file mode 100644 index 0000000000000..9153c071e8e1a --- /dev/null +++ b/src/test/ui/parser/issue-89388.rs @@ -0,0 +1,7 @@ +// Regression test for #89388. + +fn main() { + let option: Option<&[u8]> = Some(b"..."); + let _ = option.map([_]::to_vec); + //~^ ERROR: missing angle brackets in associated item path +} diff --git a/src/test/ui/parser/issue-89388.stderr b/src/test/ui/parser/issue-89388.stderr new file mode 100644 index 0000000000000..cf28bef0f4ab0 --- /dev/null +++ b/src/test/ui/parser/issue-89388.stderr @@ -0,0 +1,8 @@ +error: missing angle brackets in associated item path + --> $DIR/issue-89388.rs:5:24 + | +LL | let _ = option.map([_]::to_vec); + | ^^^^^^^^^^^ help: try: `<[_]>::to_vec` + +error: aborting due to previous error + diff --git a/src/test/ui/parser/issue-89396.fixed b/src/test/ui/parser/issue-89396.fixed new file mode 100644 index 0000000000000..823ad8cd1f8df --- /dev/null +++ b/src/test/ui/parser/issue-89396.fixed @@ -0,0 +1,16 @@ +// Regression test for issue #89396: Try to recover from a +// `=>` -> `=` or `->` typo in a match arm. + +// run-rustfix + +fn main() { + let opt = Some(42); + let _ = match opt { + Some(_) => true, + //~^ ERROR: expected one of + //~| HELP: try using a fat arrow here + None => false, + //~^ ERROR: expected one of + //~| HELP: try using a fat arrow here + }; +} diff --git a/src/test/ui/parser/issue-89396.rs b/src/test/ui/parser/issue-89396.rs new file mode 100644 index 0000000000000..f1d9efa524f46 --- /dev/null +++ b/src/test/ui/parser/issue-89396.rs @@ -0,0 +1,16 @@ +// Regression test for issue #89396: Try to recover from a +// `=>` -> `=` or `->` typo in a match arm. + +// run-rustfix + +fn main() { + let opt = Some(42); + let _ = match opt { + Some(_) = true, + //~^ ERROR: expected one of + //~| HELP: try using a fat arrow here + None -> false, + //~^ ERROR: expected one of + //~| HELP: try using a fat arrow here + }; +} diff --git a/src/test/ui/parser/issue-89396.stderr b/src/test/ui/parser/issue-89396.stderr new file mode 100644 index 0000000000000..504420574e249 --- /dev/null +++ b/src/test/ui/parser/issue-89396.stderr @@ -0,0 +1,20 @@ +error: expected one of `=>`, `if`, or `|`, found `=` + --> $DIR/issue-89396.rs:9:17 + | +LL | Some(_) = true, + | ^ + | | + | expected one of `=>`, `if`, or `|` + | help: try using a fat arrow here: `=>` + +error: expected one of `=>`, `@`, `if`, or `|`, found `->` + --> $DIR/issue-89396.rs:12:14 + | +LL | None -> false, + | ^^ + | | + | expected one of `=>`, `@`, `if`, or `|` + | help: try using a fat arrow here: `=>` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/issue-89574.rs b/src/test/ui/parser/issue-89574.rs new file mode 100644 index 0000000000000..0a477f1aa5fb6 --- /dev/null +++ b/src/test/ui/parser/issue-89574.rs @@ -0,0 +1,4 @@ +fn main() { + const EMPTY_ARRAY = []; + //~^ missing type for `const` item +} diff --git a/src/test/ui/parser/issue-89574.stderr b/src/test/ui/parser/issue-89574.stderr new file mode 100644 index 0000000000000..cbee3d35155c7 --- /dev/null +++ b/src/test/ui/parser/issue-89574.stderr @@ -0,0 +1,8 @@ +error: missing type for `const` item + --> $DIR/issue-89574.rs:2:11 + | +LL | const EMPTY_ARRAY = []; + | ^^^^^^^^^^^ help: provide a type for the item: `EMPTY_ARRAY: ` + +error: aborting due to previous error + diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs index 15a15a207b1ca..613b3c9856171 100644 --- a/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs @@ -4,3 +4,4 @@ fn main() {} const A: u8; //~ ERROR free constant item without body const B; //~ ERROR free constant item without body +//~^ ERROR missing type for `const` item diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr index aa75e5cee01d4..c340e958ee585 100644 --- a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr @@ -14,5 +14,11 @@ LL | const B; | | | help: provide a definition for the constant: `= ;` -error: aborting due to 2 previous errors +error: missing type for `const` item + --> $DIR/item-free-const-no-body-semantic-fail.rs:6:7 + | +LL | const B; + | ^ help: provide a type for the item: `B: ` + +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs index 61d3eab24d8c7..780479e3d26ac 100644 --- a/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs @@ -4,6 +4,8 @@ fn main() {} static A: u8; //~ ERROR free static item without body static B; //~ ERROR free static item without body +//~^ ERROR missing type for `static` item static mut C: u8; //~ ERROR free static item without body static mut D; //~ ERROR free static item without body +//~^ ERROR missing type for `static mut` item diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr index 7b408323674de..4d542b79861fd 100644 --- a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr @@ -15,7 +15,7 @@ LL | static B; | help: provide a definition for the static: `= ;` error: free static item without body - --> $DIR/item-free-static-no-body-semantic-fail.rs:8:1 + --> $DIR/item-free-static-no-body-semantic-fail.rs:9:1 | LL | static mut C: u8; | ^^^^^^^^^^^^^^^^- @@ -23,12 +23,24 @@ LL | static mut C: u8; | help: provide a definition for the static: `= ;` error: free static item without body - --> $DIR/item-free-static-no-body-semantic-fail.rs:9:1 + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:1 | LL | static mut D; | ^^^^^^^^^^^^- | | | help: provide a definition for the static: `= ;` -error: aborting due to 4 previous errors +error: missing type for `static` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:6:8 + | +LL | static B; + | ^ help: provide a type for the item: `B: ` + +error: missing type for `static mut` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:12 + | +LL | static mut D; + | ^ help: provide a type for the item: `D: ` + +error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/trailing-plus-in-bounds.rs b/src/test/ui/parser/trailing-plus-in-bounds.rs index 33c30d7310877..61819cabdf178 100644 --- a/src/test/ui/parser/trailing-plus-in-bounds.rs +++ b/src/test/ui/parser/trailing-plus-in-bounds.rs @@ -1,10 +1,9 @@ // build-pass (FIXME(62277): could be check-pass?) -#![feature(box_syntax)] #![allow(bare_trait_objects)] use std::fmt::Debug; fn main() { - let x: Box = box 3 as Box; // Trailing `+` is OK + let x: Box = Box::new(3) as Box; // Trailing `+` is OK } diff --git a/src/test/ui/parser/trait-object-delimiters.stderr b/src/test/ui/parser/trait-object-delimiters.stderr index ee638d8a4f5ec..75eeeda864607 100644 --- a/src/test/ui/parser/trait-object-delimiters.stderr +++ b/src/test/ui/parser/trait-object-delimiters.stderr @@ -52,7 +52,7 @@ LL | fn foo1(_: &dyn Drop + AsRef) {} | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0224]: at least one trait is required for an object type @@ -69,7 +69,7 @@ LL | fn foo5(_: &(dyn Drop + dyn AsRef)) {} | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Drop + AsRef {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 9 previous errors diff --git a/src/test/ui/parser/trait-object-trait-parens.stderr b/src/test/ui/parser/trait-object-trait-parens.stderr index b39fe4646a3cc..657288c70f387 100644 --- a/src/test/ui/parser/trait-object-trait-parens.stderr +++ b/src/test/ui/parser/trait-object-trait-parens.stderr @@ -52,7 +52,7 @@ LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + for<'a> Trait<'a> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + for<'a> Trait<'a> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -63,7 +63,7 @@ LL | let _: Box Trait<'a>) + (Obj)>; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -74,7 +74,7 @@ LL | let _: Box Trait<'a> + (Obj) + (?Sized)>; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> Trait<'a> + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 6 previous errors; 3 warnings emitted diff --git a/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs new file mode 100644 index 0000000000000..16df272df6bd9 --- /dev/null +++ b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.rs @@ -0,0 +1,28 @@ +trait Zero { + const ZERO: Self; +} + +impl Zero for String { + const ZERO: Self = String::new(); +} + +fn foo() { + match String::new() { + Zero::ZERO ..= Zero::ZERO => {}, + //~^ ERROR only `char` and numeric types are allowed in range patterns + _ => {}, + } +} + +fn bar() { + match Zero::ZERO { + Zero::ZERO ..= Zero::ZERO => {}, + //~^ ERROR type annotations needed [E0282] + _ => {}, + } +} + +fn main() { + foo(); + bar(); +} diff --git a/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr new file mode 100644 index 0000000000000..06a279925edbc --- /dev/null +++ b/src/test/ui/pattern/issue-88074-pat-range-type-inference-err.stderr @@ -0,0 +1,21 @@ +error[E0029]: only `char` and numeric types are allowed in range patterns + --> $DIR/issue-88074-pat-range-type-inference-err.rs:11:9 + | +LL | Zero::ZERO ..= Zero::ZERO => {}, + | ----------^^^^^---------- + | | | + | | this is of type `String` but it should be `char` or numeric + | this is of type `String` but it should be `char` or numeric + +error[E0282]: type annotations needed + --> $DIR/issue-88074-pat-range-type-inference-err.rs:19:9 + | +LL | Zero::ZERO ..= Zero::ZERO => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + | + = note: type must be known at this point + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0029, E0282. +For more information about an error, try `rustc --explain E0029`. diff --git a/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs b/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs new file mode 100644 index 0000000000000..27db7d8c7ab9d --- /dev/null +++ b/src/test/ui/pattern/issue-88074-pat-range-type-inference.rs @@ -0,0 +1,16 @@ +// check-pass + +trait Zero { + const ZERO: Self; +} + +impl Zero for i32 { + const ZERO: Self = 0; +} + +fn main() { + match 1 { + Zero::ZERO ..= 1 => {}, + _ => {}, + } +} diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.rs b/src/test/ui/pattern/patkind-litrange-no-expr.rs index 9464f277fb088..7ef541cb58528 100644 --- a/src/test/ui/pattern/patkind-litrange-no-expr.rs +++ b/src/test/ui/pattern/patkind-litrange-no-expr.rs @@ -19,7 +19,6 @@ enum_number!(Change { Neg = -1, Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns //~| ERROR arbitrary expressions aren't allowed in patterns - //~| ERROR only `char` and numeric types are allowed in range patterns }); fn main() {} diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.stderr b/src/test/ui/pattern/patkind-litrange-no-expr.stderr index 51af167a7c1d1..eb1ee7e45673d 100644 --- a/src/test/ui/pattern/patkind-litrange-no-expr.stderr +++ b/src/test/ui/pattern/patkind-litrange-no-expr.stderr @@ -10,15 +10,5 @@ error: arbitrary expressions aren't allowed in patterns LL | Arith = 1 + 1, | ^^^^^ -error[E0029]: only `char` and numeric types are allowed in range patterns - --> $DIR/patkind-litrange-no-expr.rs:20:13 - | -LL | $( $value ..= 42 => Some($name::$variant), )* // PatKind::Range - | -- this is of type `{integer}` -... -LL | Arith = 1 + 1, - | ^^^^^ this is of type `_` but it should be `char` or numeric - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0029`. diff --git a/src/test/ui/pattern/usefulness/const-private-fields.rs b/src/test/ui/pattern/usefulness/const-private-fields.rs new file mode 100644 index 0000000000000..06c832ca46a6b --- /dev/null +++ b/src/test/ui/pattern/usefulness/const-private-fields.rs @@ -0,0 +1,30 @@ +// check-pass +// +// Check that we don't ignore private fields in usefulness checking +#![deny(unreachable_patterns)] + +mod inner { + #[derive(PartialEq, Eq)] + pub struct PrivateField { + pub x: bool, + y: bool, + } + + pub const FOO: PrivateField = PrivateField { x: true, y: true }; + pub const BAR: PrivateField = PrivateField { x: true, y: false }; +} +use inner::*; + +fn main() { + match FOO { + FOO => {} + BAR => {} + _ => {} + } + + match FOO { + FOO => {} + PrivateField { x: true, .. } => {} + _ => {} + } +} diff --git a/src/test/ui/pattern/usefulness/consts-opaque.stderr b/src/test/ui/pattern/usefulness/consts-opaque.stderr index 68451043cf540..05c009a6f3fe1 100644 --- a/src/test/ui/pattern/usefulness/consts-opaque.stderr +++ b/src/test/ui/pattern/usefulness/consts-opaque.stderr @@ -7,8 +7,11 @@ LL | FOO => {} error: unreachable pattern --> $DIR/consts-opaque.rs:32:9 | +LL | FOO => {} + | --- matches any value +LL | LL | _ => {} // should not be emitting unreachable warning - | ^ + | ^ unreachable pattern | note: the lint level is defined here --> $DIR/consts-opaque.rs:6:9 @@ -25,8 +28,11 @@ LL | FOO_REF => {} error: unreachable pattern --> $DIR/consts-opaque.rs:39:9 | +LL | FOO_REF => {} + | ------- matches any value +LL | LL | Foo(_) => {} // should not be emitting unreachable warning - | ^^^^^^ + | ^^^^^^ unreachable pattern warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:45:9 @@ -70,15 +76,18 @@ LL | BAR => {} error: unreachable pattern --> $DIR/consts-opaque.rs:63:9 | +LL | BAR => {} + | --- matches any value +LL | LL | Bar => {} // should not be emitting unreachable warning - | ^^^ + | ^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:65:9 | -LL | Bar => {} // should not be emitting unreachable warning +LL | BAR => {} | --- matches any value -LL | +... LL | _ => {} | ^ unreachable pattern @@ -97,14 +106,20 @@ LL | BAR => {} // should not be emitting unreachable warning error: unreachable pattern --> $DIR/consts-opaque.rs:72:9 | +LL | BAR => {} + | --- matches any value +LL | LL | BAR => {} // should not be emitting unreachable warning - | ^^^ + | ^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:75:9 | +LL | BAR => {} + | --- matches any value +... LL | _ => {} // should not be emitting unreachable warning - | ^ + | ^ unreachable pattern error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:80:9 @@ -115,14 +130,20 @@ LL | BAZ => {} error: unreachable pattern --> $DIR/consts-opaque.rs:82:9 | +LL | BAZ => {} + | --- matches any value +LL | LL | Baz::Baz1 => {} // should not be emitting unreachable warning - | ^^^^^^^^^ + | ^^^^^^^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:84:9 | +LL | BAZ => {} + | --- matches any value +... LL | _ => {} - | ^ + | ^ unreachable pattern error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:90:9 @@ -133,8 +154,11 @@ LL | BAZ => {} error: unreachable pattern --> $DIR/consts-opaque.rs:92:9 | +LL | BAZ => {} + | --- matches any value +LL | LL | _ => {} - | ^ + | ^ unreachable pattern error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/consts-opaque.rs:97:9 @@ -145,20 +169,28 @@ LL | BAZ => {} error: unreachable pattern --> $DIR/consts-opaque.rs:99:9 | +LL | BAZ => {} + | --- matches any value +LL | LL | Baz::Baz2 => {} // should not be emitting unreachable warning - | ^^^^^^^^^ + | ^^^^^^^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:101:9 | +LL | BAZ => {} + | --- matches any value +... LL | _ => {} // should not be emitting unreachable warning - | ^ + | ^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:127:9 | +LL | Wrap(_) => {} + | ------- matches any value LL | WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer - | ^^^^^^^^ + | ^^^^^^^^ unreachable pattern error: unreachable pattern --> $DIR/consts-opaque.rs:141:9 diff --git a/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr index 9a02fac6a75dd..0ffb0ffd82aa0 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/reachability.stderr @@ -133,8 +133,10 @@ LL | 5..15 => {}, error: unreachable pattern --> $DIR/reachability.rs:83:9 | +LL | _ => {}, + | - matches any value LL | '\u{D7FF}'..='\u{E000}' => {}, - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern error: unreachable pattern --> $DIR/reachability.rs:104:9 diff --git a/src/test/ui/pattern/usefulness/issue-12116.rs b/src/test/ui/pattern/usefulness/issue-12116.rs index 8b391cd95d7f7..3cb92a54029dc 100644 --- a/src/test/ui/pattern/usefulness/issue-12116.rs +++ b/src/test/ui/pattern/usefulness/issue-12116.rs @@ -1,9 +1,9 @@ #![feature(box_patterns)] -#![feature(box_syntax)] #![allow(dead_code)] #![allow(unused_variables)] #![deny(unreachable_patterns)] + enum IntList { Cons(isize, Box), Nil @@ -12,9 +12,9 @@ enum IntList { fn tail(source_list: &IntList) -> IntList { match source_list { &IntList::Cons(val, box ref next_list) => tail(next_list), - &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil), -//~^ ERROR unreachable pattern - _ => panic!() + &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)), + //~^ ERROR unreachable pattern + _ => panic!(), } } diff --git a/src/test/ui/pattern/usefulness/issue-12116.stderr b/src/test/ui/pattern/usefulness/issue-12116.stderr index 4d162eb77e725..7f15c4703a31c 100644 --- a/src/test/ui/pattern/usefulness/issue-12116.stderr +++ b/src/test/ui/pattern/usefulness/issue-12116.stderr @@ -1,11 +1,11 @@ error: unreachable pattern --> $DIR/issue-12116.rs:15:9 | -LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, box IntList::Nil), +LL | &IntList::Cons(val, box IntList::Nil) => IntList::Cons(val, Box::new(IntList::Nil)), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/issue-12116.rs:5:9 + --> $DIR/issue-12116.rs:4:9 | LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/pattern/usefulness/issue-3601.rs b/src/test/ui/pattern/usefulness/issue-3601.rs index e33359beccdef..6215a23980d6d 100644 --- a/src/test/ui/pattern/usefulness/issue-3601.rs +++ b/src/test/ui/pattern/usefulness/issue-3601.rs @@ -1,5 +1,4 @@ #![feature(box_patterns)] -#![feature(box_syntax)] struct HTMLImageData { image: Option @@ -23,8 +22,9 @@ struct NodeData { fn main() { let mut id = HTMLImageData { image: None }; - let ed = ElementData { kind: box ElementKind::HTMLImageElement(id) }; - let n = NodeData {kind : box NodeKind::Element(ed)}; + let ed = ElementData { kind: Box::new(ElementKind::HTMLImageElement(id)) }; + let n = NodeData { kind: Box::new(NodeKind::Element(ed)) }; + // n.b. span could be better match n.kind { box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns diff --git a/src/test/ui/pattern/usefulness/issue-3601.stderr b/src/test/ui/pattern/usefulness/issue-3601.stderr index c873c20cca81b..48ed14915084a 100644 --- a/src/test/ui/pattern/usefulness/issue-3601.stderr +++ b/src/test/ui/pattern/usefulness/issue-3601.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `Box(_, _)` not covered +error[E0004]: non-exhaustive patterns: `box _` not covered --> $DIR/issue-3601.rs:30:44 | LL | box NodeKind::Element(ed) => match ed.kind { - | ^^^^^^^ pattern `Box(_, _)` not covered + | ^^^^^^^ pattern `box _` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `Box` diff --git a/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs b/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs new file mode 100644 index 0000000000000..058f419679847 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs @@ -0,0 +1,56 @@ +// check-pass + +// From https://github.com/rust-lang/rust/issues/72476 +// and https://github.com/rust-lang/rust/issues/89393 + +trait Trait { + type Projection; +} + +struct A; +impl Trait for A { + type Projection = bool; +} + +struct B; +impl Trait for B { + type Projection = (u32, u32); +} + +struct Next(T::Projection); + +fn foo1(item: Next) { + match item { + Next(true) => {} + Next(false) => {} + } +} + +fn foo2(x: ::Projection) { + match x { + true => {} + false => {} + } +} + +fn foo3(x: Next) { + let Next((_, _)) = x; + match x { + Next((_, _)) => {} + } +} + +fn foo4(x: ::Projection) { + let (_, _) = x; + match x { + (_, _) => {} + } +} + +fn foo5(x: ::Projection) { + match x { + _ => {} + } +} + +fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs b/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs deleted file mode 100644 index 1e1d21433b79c..0000000000000 --- a/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs +++ /dev/null @@ -1,22 +0,0 @@ -// check-pass - -// From https://github.com/rust-lang/rust/issues/72476 - -trait A { - type Projection; -} - -impl A for () { - type Projection = bool; -} - -struct Next(T::Projection); - -fn f(item: Next<()>) { - match item { - Next(true) => {} - Next(false) => {} - } -} - -fn main() {} diff --git a/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs b/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs new file mode 100644 index 0000000000000..c1bfcc73402ce --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.rs @@ -0,0 +1,6 @@ +// This used to ICE in exhaustiveness checking. Explanation here: +// https://github.com/rust-lang/rust/issues/82772#issuecomment-905946768 +fn main() { + let Box { 1: _, .. }: Box<()>; //~ ERROR field `1` of + let Box { .. }: Box<()>; +} diff --git a/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr b/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr new file mode 100644 index 0000000000000..2c8c85bb1e005 --- /dev/null +++ b/src/test/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr @@ -0,0 +1,9 @@ +error[E0451]: field `1` of struct `Box` is private + --> $DIR/issue-82772-match-box-as-struct.rs:4:15 + | +LL | let Box { 1: _, .. }: Box<()>; + | ^^^^ private field + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0451`. diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index c234547bd14b1..06a62db4ebb0f 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -11,5 +11,5 @@ fn start(_: isize, _: *const *const u8) -> isize { let _x: Option = None; let _y: Result = Ok(42); - 0 + let _z: Result = loop {}; } diff --git a/src/test/ui/print_type_sizes/uninhabited.stdout b/src/test/ui/print_type_sizes/uninhabited.stdout index 2a8706f7ac551..5eb5384bce340 100644 --- a/src/test/ui/print_type_sizes/uninhabited.stdout +++ b/src/test/ui/print_type_sizes/uninhabited.stdout @@ -3,3 +3,4 @@ print-type-size variant `Ok`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `std::option::Option`: 0 bytes, alignment: 1 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `std::result::Result`: 0 bytes, alignment: 1 bytes diff --git a/src/test/ui/privacy/privacy2.stderr b/src/test/ui/privacy/privacy2.stderr index c2a33ce1f59b3..882f314655d83 100644 --- a/src/test/ui/privacy/privacy2.stderr +++ b/src/test/ui/privacy/privacy2.stderr @@ -23,7 +23,13 @@ LL | pub fn foo() {} error: requires `sized` lang_item -error: aborting due to 3 previous errors +error: requires `sized` lang_item + +error: requires `sized` lang_item + +error: requires `sized` lang_item + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0432, E0603. For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/privacy/privacy3.stderr b/src/test/ui/privacy/privacy3.stderr index 22c1e48b07d94..42ce456d962a1 100644 --- a/src/test/ui/privacy/privacy3.stderr +++ b/src/test/ui/privacy/privacy3.stderr @@ -6,6 +6,12 @@ LL | use bar::gpriv; error: requires `sized` lang_item -error: aborting due to 2 previous errors +error: requires `sized` lang_item + +error: requires `sized` lang_item + +error: requires `sized` lang_item + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs b/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs deleted file mode 100644 index f0fec6782423e..0000000000000 --- a/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs +++ /dev/null @@ -1,37 +0,0 @@ -// gate-test-macro_attributes_in_derive_output -// aux-build: test-macros.rs - -#![feature(proc_macro_hygiene)] -#![feature(stmt_expr_attributes)] - -#[macro_use] -extern crate test_macros; - -#[derive(Empty)] -#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable -struct S1 { - field: [u8; 10], -} - -#[derive(Empty)] -#[empty_helper] -#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable -struct S2 { - field: [u8; 10], -} - -#[derive(Empty)] -struct S3 { - field: [u8; #[identity_attr] 10], //~ ERROR macro attributes in `#[derive]` output are unstable -} - -#[derive(Empty)] -struct S4 { - field: [u8; { - #[derive(Empty)] // OK, not gated - struct Inner; - 10 - }] -} - -fn main() {} diff --git a/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr b/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr deleted file mode 100644 index 74cace628b94c..0000000000000 --- a/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0658]: macro attributes in `#[derive]` output are unstable - --> $DIR/attribute-after-derive-feature-gate.rs:11:3 - | -LL | #[empty_attr] - | ^^^^^^^^^^ - | - = note: see issue #81119 for more information - = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable - -error[E0658]: macro attributes in `#[derive]` output are unstable - --> $DIR/attribute-after-derive-feature-gate.rs:18:3 - | -LL | #[empty_attr] - | ^^^^^^^^^^ - | - = note: see issue #81119 for more information - = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable - -error[E0658]: macro attributes in `#[derive]` output are unstable - --> $DIR/attribute-after-derive-feature-gate.rs:25:19 - | -LL | field: [u8; #[identity_attr] 10], - | ^^^^^^^^^^^^^ - | - = note: see issue #81119 for more information - = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/proc-macro/attribute-after-derive.rs b/src/test/ui/proc-macro/attribute-after-derive.rs index ac3f28b6ef3ea..0f0f27bff97be 100644 --- a/src/test/ui/proc-macro/attribute-after-derive.rs +++ b/src/test/ui/proc-macro/attribute-after-derive.rs @@ -5,8 +5,6 @@ // compile-flags: -Z span-debug // aux-build: test-macros.rs -#![feature(macro_attributes_in_derive_output)] - #![no_std] // Don't load unnecessary hygiene information from std extern crate std; diff --git a/src/test/ui/proc-macro/attribute-after-derive.stdout b/src/test/ui/proc-macro/attribute-after-derive.stdout index 4c48e41ff338b..c5b84b0367c8f 100644 --- a/src/test/ui/proc-macro/attribute-after-derive.stdout +++ b/src/test/ui/proc-macro/attribute-after-derive.stdout @@ -3,35 +3,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/attribute-after-derive.rs:17:1: 17:2 (#0), + span: $DIR/attribute-after-derive.rs:15:1: 15:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "derive", - span: $DIR/attribute-after-derive.rs:17:3: 17:9 (#0), + span: $DIR/attribute-after-derive.rs:15:3: 15:9 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "Print", - span: $DIR/attribute-after-derive.rs:17:10: 17:15 (#0), + span: $DIR/attribute-after-derive.rs:15:10: 15:15 (#0), }, ], - span: $DIR/attribute-after-derive.rs:17:9: 17:16 (#0), + span: $DIR/attribute-after-derive.rs:15:9: 15:16 (#0), }, ], - span: $DIR/attribute-after-derive.rs:17:2: 17:17 (#0), + span: $DIR/attribute-after-derive.rs:15:2: 15:17 (#0), }, Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0), + span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0), }, Ident { ident: "AttributeDerive", - span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0), + span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0), }, Group { delimiter: Brace, @@ -39,64 +39,64 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/attribute-after-derive.rs:19:5: 19:6 (#0), + span: $DIR/attribute-after-derive.rs:17:5: 17:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/attribute-after-derive.rs:19:7: 19:10 (#0), + span: $DIR/attribute-after-derive.rs:17:7: 17:10 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/attribute-after-derive.rs:19:11: 19:16 (#0), + span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0), }, ], - span: $DIR/attribute-after-derive.rs:19:10: 19:17 (#0), + span: $DIR/attribute-after-derive.rs:17:10: 17:17 (#0), }, ], - span: $DIR/attribute-after-derive.rs:19:6: 19:18 (#0), + span: $DIR/attribute-after-derive.rs:17:6: 17:18 (#0), }, Ident { ident: "field", - span: $DIR/attribute-after-derive.rs:20:5: 20:10 (#0), + span: $DIR/attribute-after-derive.rs:18:5: 18:10 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/attribute-after-derive.rs:20:10: 20:11 (#0), + span: $DIR/attribute-after-derive.rs:18:10: 18:11 (#0), }, Ident { ident: "u8", - span: $DIR/attribute-after-derive.rs:20:12: 20:14 (#0), + span: $DIR/attribute-after-derive.rs:18:12: 18:14 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/attribute-after-derive.rs:20:14: 20:15 (#0), + span: $DIR/attribute-after-derive.rs:18:14: 18:15 (#0), }, ], - span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0), + span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0), + span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0), }, Ident { ident: "AttributeDerive", - span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0), + span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0), + span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { } @@ -104,45 +104,89 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/attribute-after-derive.rs:24:1: 24:2 (#0), + span: $DIR/attribute-after-derive.rs:22:1: 22:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_attr", - span: $DIR/attribute-after-derive.rs:24:3: 24:13 (#0), + span: $DIR/attribute-after-derive.rs:22:3: 22:13 (#0), }, ], - span: $DIR/attribute-after-derive.rs:24:2: 24:14 (#0), + span: $DIR/attribute-after-derive.rs:22:2: 22:14 (#0), }, Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0), + span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0), }, Ident { ident: "DeriveAttribute", - span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0), + span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0), + span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { } +PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field : u8, } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0), + span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0), }, Ident { ident: "DeriveAttribute", - span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0), + span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0), }, Group { delimiter: Brace, - stream: TokenStream [], - span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0), + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/attribute-after-derive.rs:24:5: 24:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/attribute-after-derive.rs:24:7: 24:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/attribute-after-derive.rs:24:11: 24:16 (#0), + }, + ], + span: $DIR/attribute-after-derive.rs:24:10: 24:17 (#0), + }, + ], + span: $DIR/attribute-after-derive.rs:24:6: 24:18 (#0), + }, + Ident { + ident: "field", + span: $DIR/attribute-after-derive.rs:25:5: 25:10 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/attribute-after-derive.rs:25:10: 25:11 (#0), + }, + Ident { + ident: "u8", + span: $DIR/attribute-after-derive.rs:25:12: 25:14 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/attribute-after-derive.rs:25:14: 25:15 (#0), + }, + ], + span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0), }, ] diff --git a/src/test/ui/proc-macro/generate-mod.stderr b/src/test/ui/proc-macro/generate-mod.stderr index 285876aadb293..d6fd4baeb5ece 100644 --- a/src/test/ui/proc-macro/generate-mod.stderr +++ b/src/test/ui/proc-macro/generate-mod.stderr @@ -82,3 +82,75 @@ LL | #[derive(generate_mod::CheckDerive)] error: aborting due to 4 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0412`. +Future incompatibility report: Future breakage diagnostic: +warning: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:16:10 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default + = 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 #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `OuterDerive` in this scope + --> $DIR/generate-mod.rs:16:10 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = 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 #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:23:14 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = 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 #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `OuterDerive` in this scope + --> $DIR/generate-mod.rs:23:14 + | +LL | #[derive(generate_mod::CheckDerive)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = 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 #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | +note: the lint level is defined here + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) + +Future breakage diagnostic: +warning: cannot find type `OuterDeriveLint` in this scope + --> $DIR/generate-mod.rs:30:10 + | +LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = 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 #83583 + = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info) + diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.rs b/src/test/ui/proc-macro/meta-macro-hygiene.rs index 2536b2fa9021f..62968ea54e0aa 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.rs +++ b/src/test/ui/proc-macro/meta-macro-hygiene.rs @@ -4,6 +4,7 @@ // compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene -Z trim-diagnostic-paths=no // check-pass // normalize-stdout-test "\d+#" -> "0#" +// normalize-stdout-test "expn\d{3,}" -> "expnNNN" // // We don't care about symbol ids, so we set them all to 0 // in the stdout diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout index 2524d8273b705..7f7a1009c909a 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -1,5 +1,5 @@ Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) -Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:23:37: 23:43 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#4) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:23:45: 23:50 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:50: 23:51 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:23:51: 23:53 (#4) }] +Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:24:37: 24:43 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:43: 24:45 (#4) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:24:45: 24:50 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:24:50: 24:51 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:24:51: 24:53 (#4) }] Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) }] #![feature /* 0#0 */(prelude_import)] // aux-build:make-macro.rs @@ -8,6 +8,7 @@ Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro // compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene -Z trim-diagnostic-paths=no // check-pass // normalize-stdout-test "\d+#" -> "0#" +// normalize-stdout-test "expn\d{3,}" -> "expnNNN" // // We don't care about symbol ids, so we set them all to 0 // in the stdout @@ -48,6 +49,7 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) SyntaxContexts: diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.rs b/src/test/ui/proc-macro/nonterminal-token-hygiene.rs index 98fd4306004e8..fa52a975bca85 100644 --- a/src/test/ui/proc-macro/nonterminal-token-hygiene.rs +++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.rs @@ -4,6 +4,7 @@ // compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene // compile-flags: -Z trim-diagnostic-paths=no // normalize-stdout-test "\d+#" -> "0#" +// normalize-stdout-test "expn\d{3,}" -> "expnNNN" // aux-build:test-macros.rs #![feature(decl_macro)] diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout index b5ab82737e9b6..0780386381373 100644 --- a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -6,19 +6,19 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "struct", - span: $DIR/nonterminal-token-hygiene.rs:30:5: 30:11 (#5), + span: $DIR/nonterminal-token-hygiene.rs:31:5: 31:11 (#5), }, Ident { ident: "S", - span: $DIR/nonterminal-token-hygiene.rs:30:12: 30:13 (#5), + span: $DIR/nonterminal-token-hygiene.rs:31:12: 31:13 (#5), }, Punct { ch: ';', spacing: Alone, - span: $DIR/nonterminal-token-hygiene.rs:30:13: 30:14 (#5), + span: $DIR/nonterminal-token-hygiene.rs:31:13: 31:14 (#5), }, ], - span: $DIR/nonterminal-token-hygiene.rs:20:27: 20:32 (#6), + span: $DIR/nonterminal-token-hygiene.rs:21:27: 21:32 (#6), }, ] #![feature /* 0#0 */(prelude_import)] @@ -29,6 +29,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ // compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene // compile-flags: -Z trim-diagnostic-paths=no // normalize-stdout-test "\d+#" -> "0#" +// normalize-stdout-test "expn\d{3,}" -> "expnNNN" // aux-build:test-macros.rs #![feature /* 0#0 */(decl_macro)] @@ -72,6 +73,7 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") +crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) SyntaxContexts: diff --git a/src/test/ui/pure-sum.rs b/src/test/ui/pure-sum.rs index 2ff6f935a03c1..2f2ece75ebeeb 100644 --- a/src/test/ui/pure-sum.rs +++ b/src/test/ui/pure-sum.rs @@ -5,8 +5,6 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn sums_to(v: Vec , sum: isize) -> bool { let mut i = 0; let mut sum0 = 0; @@ -19,7 +17,7 @@ fn sums_to(v: Vec , sum: isize) -> bool { fn sums_to_using_uniq(v: Vec , sum: isize) -> bool { let mut i = 0; - let mut sum0: Box<_> = box 0; + let mut sum0: Box<_> = 0.into(); while i < v.len() { *sum0 += v[i]; i += 1; @@ -41,7 +39,7 @@ struct F { f: T } fn sums_to_using_uniq_rec(v: Vec , sum: isize) -> bool { let mut i = 0; - let mut sum0 = F::> {f: box 0}; + let mut sum0 = F::> {f: 0.into() }; while i < v.len() { *sum0.f += v[i]; i += 1; diff --git a/src/test/ui/rcvr-borrowed-to-region.rs b/src/test/ui/rcvr-borrowed-to-region.rs index 37113bc0a050b..7f32b8b91a6f0 100644 --- a/src/test/ui/rcvr-borrowed-to-region.rs +++ b/src/test/ui/rcvr-borrowed-to-region.rs @@ -1,7 +1,6 @@ // run-pass #![allow(non_camel_case_types)] -#![feature(box_syntax)] trait get { fn get(self) -> isize; @@ -17,7 +16,7 @@ impl<'a> get for &'a isize { } pub fn main() { - let x: Box<_> = box 6; + let x: Box<_> = 6.into(); let y = x.get(); println!("y={}", y); assert_eq!(y, 6); diff --git a/src/test/ui/reachable/expr_again.rs b/src/test/ui/reachable/expr_again.rs index 243fed0c8ce52..6049321337c75 100644 --- a/src/test/ui/reachable/expr_again.rs +++ b/src/test/ui/reachable/expr_again.rs @@ -1,5 +1,5 @@ -#![feature(box_syntax)] #![allow(unused_variables)] + #![deny(unreachable_code)] fn main() { diff --git a/src/test/ui/reachable/unreachable-arm.rs b/src/test/ui/reachable/unreachable-arm.rs index 64c3896851669..3277bf0d52b20 100644 --- a/src/test/ui/reachable/unreachable-arm.rs +++ b/src/test/ui/reachable/unreachable-arm.rs @@ -1,5 +1,5 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + #![allow(dead_code)] #![deny(unreachable_patterns)] diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs b/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs index 03cb3e24b7dbf..4fd5622b0626c 100644 --- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs +++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs @@ -1,8 +1,8 @@ //~ ERROR cycle detected when computing layout of `S` -//~| NOTE ...which requires computing layout of `std::option::Option<::It>`... -//~| NOTE ...which requires computing layout of `std::option::Option`... +//~| NOTE ...which requires computing layout of `core::option::Option<::It>`... +//~| NOTE ...which requires computing layout of `core::option::Option`... //~| NOTE ...which again requires computing layout of `S`, completing the cycle -//~| NOTE cycle used when computing layout of `std::option::Option` +//~| NOTE cycle used when computing layout of `core::option::Option` // build-fail diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr index 21c0e1e6de5f3..6042379a91887 100644 --- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr +++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr @@ -1,9 +1,9 @@ error[E0391]: cycle detected when computing layout of `S` | - = note: ...which requires computing layout of `std::option::Option<::It>`... - = note: ...which requires computing layout of `std::option::Option`... + = note: ...which requires computing layout of `core::option::Option<::It>`... + = note: ...which requires computing layout of `core::option::Option`... = note: ...which again requires computing layout of `S`, completing the cycle - = note: cycle used when computing layout of `std::option::Option` + = note: cycle used when computing layout of `core::option::Option` error: aborting due to previous error diff --git a/src/test/ui/recursion/issue-83150.stderr b/src/test/ui/recursion/issue-83150.stderr index 943d51330976a..d45bfc3ca55ea 100644 --- a/src/test/ui/recursion/issue-83150.stderr +++ b/src/test/ui/recursion/issue-83150.stderr @@ -1,6 +1,6 @@ error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>: Iterator` | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_83150`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`) = note: required because of the requirements on the impl of `Iterator` for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>` error: aborting due to previous error diff --git a/src/test/ui/recursion_limit/invalid_digit_type.rs b/src/test/ui/recursion_limit/invalid_digit_type.rs new file mode 100644 index 0000000000000..e408109b3682c --- /dev/null +++ b/src/test/ui/recursion_limit/invalid_digit_type.rs @@ -0,0 +1,3 @@ +#![recursion_limit = 123] //~ ERROR malformed `recursion_limit` attribute + +fn main() {} diff --git a/src/test/ui/recursion_limit/invalid_digit_type.stderr b/src/test/ui/recursion_limit/invalid_digit_type.stderr new file mode 100644 index 0000000000000..6d1409bb39065 --- /dev/null +++ b/src/test/ui/recursion_limit/invalid_digit_type.stderr @@ -0,0 +1,8 @@ +error: malformed `recursion_limit` attribute input + --> $DIR/invalid_digit_type.rs:1:1 + | +LL | #![recursion_limit = 123] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]` + +error: aborting due to previous error + diff --git a/src/test/ui/recursion_limit/invalid_macro.rs b/src/test/ui/recursion_limit/invalid_macro.rs new file mode 100644 index 0000000000000..7db67a8d16284 --- /dev/null +++ b/src/test/ui/recursion_limit/invalid_macro.rs @@ -0,0 +1,7 @@ +#![recursion_limit = foo!()] //~ ERROR malformed `recursion_limit` attribute + +macro_rules! foo { + () => {"128"}; +} + +fn main() {} diff --git a/src/test/ui/recursion_limit/invalid_macro.stderr b/src/test/ui/recursion_limit/invalid_macro.stderr new file mode 100644 index 0000000000000..0189e99da3714 --- /dev/null +++ b/src/test/ui/recursion_limit/invalid_macro.stderr @@ -0,0 +1,8 @@ +error: malformed `recursion_limit` attribute input + --> $DIR/invalid_macro.rs:1:1 + | +LL | #![recursion_limit = foo!()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]` + +error: aborting due to previous error + diff --git a/src/test/ui/recursion_limit/no-value.rs b/src/test/ui/recursion_limit/no-value.rs new file mode 100644 index 0000000000000..2202e5b7713ee --- /dev/null +++ b/src/test/ui/recursion_limit/no-value.rs @@ -0,0 +1,6 @@ +// Test the parse error for no value provided to recursion_limit + +#![recursion_limit] +//~^ ERROR malformed `recursion_limit` attribute input + +fn main() {} diff --git a/src/test/ui/recursion_limit/no-value.stderr b/src/test/ui/recursion_limit/no-value.stderr new file mode 100644 index 0000000000000..35ac2c4cd17b3 --- /dev/null +++ b/src/test/ui/recursion_limit/no-value.stderr @@ -0,0 +1,8 @@ +error: malformed `recursion_limit` attribute input + --> $DIR/no-value.rs:3:1 + | +LL | #![recursion_limit] + | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]` + +error: aborting due to previous error + diff --git a/src/test/ui/recursion_limit/zero-overflow.rs b/src/test/ui/recursion_limit/zero-overflow.rs new file mode 100644 index 0000000000000..77bd818567608 --- /dev/null +++ b/src/test/ui/recursion_limit/zero-overflow.rs @@ -0,0 +1,7 @@ +//~ ERROR overflow evaluating the requirement `&mut Self: DispatchFromDyn<&mut RustaceansAreAwesome> +//~| HELP consider increasing the recursion limit +// build-fail + +#![recursion_limit = "0"] + +fn main() {} diff --git a/src/test/ui/recursion_limit/zero-overflow.stderr b/src/test/ui/recursion_limit/zero-overflow.stderr new file mode 100644 index 0000000000000..9007ec0d78444 --- /dev/null +++ b/src/test/ui/recursion_limit/zero-overflow.stderr @@ -0,0 +1,7 @@ +error[E0275]: overflow evaluating the requirement `&mut Self: DispatchFromDyn<&mut RustaceansAreAwesome>` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`zero_overflow`) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/recursion_limit/zero.stderr b/src/test/ui/recursion_limit/zero.stderr index 6358805d89dee..c85cbadea7101 100644 --- a/src/test/ui/recursion_limit/zero.stderr +++ b/src/test/ui/recursion_limit/zero.stderr @@ -4,7 +4,7 @@ error: recursion limit reached while expanding `test!` LL | test!(test); | ^^^^^^^^^^^^ | - = help: consider adding a `#![recursion_limit="0"]` attribute to your crate (`zero`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`zero`) error: aborting due to previous error diff --git a/src/test/ui/regions/issue-12470.rs b/src/test/ui/regions/issue-12470.rs index 0ade359923a0e..d8f2abb0c3c21 100644 --- a/src/test/ui/regions/issue-12470.rs +++ b/src/test/ui/regions/issue-12470.rs @@ -1,10 +1,10 @@ -#![feature(box_syntax)] - trait X { fn get_i(&self) -> isize; } + + struct B { i: isize } @@ -24,7 +24,7 @@ fn make_a<'a>(p: &'a dyn X) -> A<'a> { } fn make_make_a<'a>() -> A<'a> { - let b: Box = box B {i:1}; + let b: Box = Box::new(B { i: 1 }); let bb: &B = &*b; make_a(bb) //~ ERROR cannot return value referencing local data `*b` } diff --git a/src/test/ui/regions/issue-78262.nll.stderr b/src/test/ui/regions/issue-78262.nll.stderr index a35d6fd9bf885..721dafac0be76 100644 --- a/src/test/ui/regions/issue-78262.nll.stderr +++ b/src/test/ui/regions/issue-78262.nll.stderr @@ -2,8 +2,11 @@ error[E0521]: borrowed data escapes outside of closure --> $DIR/issue-78262.rs:14:26 | LL | let f = |x: &dyn TT| x.func(); - | - ^^^^^^^^ `x` escapes the closure body here - | | + | - - ^^^^^^^^ + | | | | + | | | `x` escapes the closure body here + | | | argument requires that `'1` must outlive `'static` + | | let's call the lifetime of this reference `'1` | `x` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/regions/issue-78262.polonius.stderr b/src/test/ui/regions/issue-78262.polonius.stderr index a35d6fd9bf885..721dafac0be76 100644 --- a/src/test/ui/regions/issue-78262.polonius.stderr +++ b/src/test/ui/regions/issue-78262.polonius.stderr @@ -2,8 +2,11 @@ error[E0521]: borrowed data escapes outside of closure --> $DIR/issue-78262.rs:14:26 | LL | let f = |x: &dyn TT| x.func(); - | - ^^^^^^^^ `x` escapes the closure body here - | | + | - - ^^^^^^^^ + | | | | + | | | `x` escapes the closure body here + | | | argument requires that `'1` must outlive `'static` + | | let's call the lifetime of this reference `'1` | `x` is a reference that is only valid in the closure body error: aborting due to previous error diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr index 89a22adc8f021..e220cbf555956 100644 --- a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr +++ b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr @@ -2,12 +2,15 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/region-invariant-static-error-reporting.rs:15:9 | LL | fn unify<'a>(x: Option>, f: fn(Invariant<'a>)) { - | - `x` is a reference that is only valid in the function body + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | let bad = if x.is_some() { LL | x.unwrap() - | ^^^^^^^^^^ `x` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to previous error diff --git a/src/test/ui/regions/region-object-lifetime-5.rs b/src/test/ui/regions/region-object-lifetime-5.rs index 307bbcbd58d7a..ad35936716806 100644 --- a/src/test/ui/regions/region-object-lifetime-5.rs +++ b/src/test/ui/regions/region-object-lifetime-5.rs @@ -8,7 +8,7 @@ trait Foo { // Here, the object is bounded by an anonymous lifetime and returned // as `&'static`, so you get an error. fn owned_receiver(x: Box) -> &'static () { - x.borrowed() //~ ERROR cannot return value referencing local data `*x` + x.borrowed() //~ ERROR cannot return reference to local data `*x` } fn main() {} diff --git a/src/test/ui/regions/region-object-lifetime-5.stderr b/src/test/ui/regions/region-object-lifetime-5.stderr index b86f6e3a2a122..b82b58c7a8e0d 100644 --- a/src/test/ui/regions/region-object-lifetime-5.stderr +++ b/src/test/ui/regions/region-object-lifetime-5.stderr @@ -1,11 +1,8 @@ -error[E0515]: cannot return value referencing local data `*x` +error[E0515]: cannot return reference to local data `*x` --> $DIR/region-object-lifetime-5.rs:11:5 | LL | x.borrowed() - | -^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `*x` is borrowed here + | ^^^^^^^^^^^^ returns a reference to data owned by the current function error: aborting due to previous error diff --git a/src/test/ui/regions/regions-borrow-at.rs b/src/test/ui/regions/regions-borrow-at.rs index 355e8c914551c..152abe109bca4 100644 --- a/src/test/ui/regions/regions-borrow-at.rs +++ b/src/test/ui/regions/regions-borrow-at.rs @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] fn foo(x: &usize) -> usize { *x } pub fn main() { - let p: Box<_> = box 22; + let p: Box<_> = Box::new(22); let r = foo(&*p); println!("r={}", r); assert_eq!(r, 22); diff --git a/src/test/ui/regions/regions-borrow-uniq.rs b/src/test/ui/regions/regions-borrow-uniq.rs index 3bf049c151137..adc6b1939da7f 100644 --- a/src/test/ui/regions/regions-borrow-uniq.rs +++ b/src/test/ui/regions/regions-borrow-uniq.rs @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] fn foo(x: &usize) -> usize { *x } pub fn main() { - let p: Box<_> = box 3; + let p: Box<_> = Box::new(3); let r = foo(&*p); assert_eq!(r, 3); } diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr index ca153b9d9b1d7..86bd100538d70 100644 --- a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr +++ b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.nll.stderr @@ -5,8 +5,6 @@ LL | fn param_not_ok<'a>(x: &'a isize) { | -- lifetime `'a` defined here LL | assert_send::<&'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:26:5 @@ -15,8 +13,6 @@ LL | fn param_not_ok1<'a>(_: &'a isize) { | -- lifetime `'a` defined here LL | assert_send::<&'a str>(); | ^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:30:5 @@ -25,8 +21,6 @@ LL | fn param_not_ok2<'a>(_: &'a isize) { | -- lifetime `'a` defined here LL | assert_send::<&'a [isize]>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5 @@ -35,8 +29,6 @@ LL | fn box_with_region_not_ok<'a>() { | -- lifetime `'a` defined here LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:55:5 @@ -45,8 +37,6 @@ LL | fn unsafe_ok2<'a>(_: &'a isize) { | -- lifetime `'a` defined here LL | assert_send::<*const &'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/regions-bounded-by-trait-requiring-static.rs:59:5 @@ -55,8 +45,6 @@ LL | fn unsafe_ok3<'a>(_: &'a isize) { | -- lifetime `'a` defined here LL | assert_send::<*mut &'a isize>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to 6 previous errors diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr index ed7b17c207c30..83d6e13dc0a68 100644 --- a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr +++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr @@ -2,12 +2,17 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5 | LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) { - | - - `b` is a reference that is only valid in the function body - | | - | `a` declared here, outside of the function body + | -- -- - - `b` is a reference that is only valid in the function body + | | | | + | | | `a` declared here, outside of the function body + | | lifetime `'b` defined here + | lifetime `'a` defined here LL | // Here the value provided for 'y is 'b, and hence 'b:'a does not hold. LL | f.method(b); - | ^^^^^^^^^^^ `b` escapes the function body here + | ^^^^^^^^^^^ + | | + | `b` escapes the function body here + | argument requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr index 2076772b59df4..b6d7b8aac5f19 100644 --- a/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr +++ b/src/test/ui/regions/regions-bounded-method-type-parameters.nll.stderr @@ -5,8 +5,6 @@ LL | fn caller<'a>(x: &isize) { | -- lifetime `'a` defined here LL | Foo.some_method::<&'a isize>(); | ^^^^^^^^^^^ requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.rs b/src/test/ui/regions/regions-close-associated-type-into-object.rs index 0cbdc828c507f..428477e24899a 100644 --- a/src/test/ui/regions/regions-close-associated-type-into-object.rs +++ b/src/test/ui/regions/regions-close-associated-type-into-object.rs @@ -1,7 +1,7 @@ -#![feature(box_syntax)] - trait X {} + + trait Iter { type Item: X; @@ -18,7 +18,7 @@ fn bad1(v: T) -> Box fn bad2(v: T) -> Box where Box : X { - let item: Box<_> = box v.into_item(); + let item: Box<_> = Box::new(v.into_item()); Box::new(item) //~ ERROR associated type `::Item` may not live long enough } @@ -31,7 +31,7 @@ fn bad3<'a, T: Iter>(v: T) -> Box fn bad4<'a, T: Iter>(v: T) -> Box where Box : X { - let item: Box<_> = box v.into_item(); + let item: Box<_> = Box::new(v.into_item()); Box::new(item) //~ ERROR associated type `::Item` may not live long enough } diff --git a/src/test/ui/regions/regions-close-object-into-object-1.rs b/src/test/ui/regions/regions-close-object-into-object-1.rs index 5518c6a94b1d0..2dc33d5671ff0 100644 --- a/src/test/ui/regions/regions-close-object-into-object-1.rs +++ b/src/test/ui/regions/regions-close-object-into-object-1.rs @@ -1,7 +1,7 @@ -#![feature(box_syntax)] #![allow(warnings)] trait A { } + struct B<'a, T:'a>(&'a (A+'a)); trait X { } @@ -9,7 +9,7 @@ trait X { } impl<'a, T> X for B<'a, T> {} fn f<'a, T:'static, U>(v: Box+'static>) -> Box { - box B(&*v) as Box //~ ERROR cannot return value referencing local data `*v` + Box::new(B(&*v)) as Box //~ ERROR cannot return value referencing local data `*v` } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-1.stderr b/src/test/ui/regions/regions-close-object-into-object-1.stderr index 8e119c4f5355f..5bfaeb295c352 100644 --- a/src/test/ui/regions/regions-close-object-into-object-1.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-1.stderr @@ -1,10 +1,10 @@ error[E0515]: cannot return value referencing local data `*v` --> $DIR/regions-close-object-into-object-1.rs:12:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr index 882faf4ece316..6a0e958616101 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.nll.stderr @@ -1,20 +1,18 @@ error: lifetime may not live long enough - --> $DIR/regions-close-object-into-object-2.rs:10:5 + --> $DIR/regions-close-object-into-object-2.rs:9:5 | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | -- lifetime `'a` defined here -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error[E0515]: cannot return value referencing local data `*v` - --> $DIR/regions-close-object-into-object-2.rs:10:5 + --> $DIR/regions-close-object-into-object-2.rs:9:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-close-object-into-object-2.rs b/src/test/ui/regions/regions-close-object-into-object-2.rs index 7144ab5a24c51..9c41174e24d8d 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.rs +++ b/src/test/ui/regions/regions-close-object-into-object-2.rs @@ -1,13 +1,12 @@ -#![feature(box_syntax)] - trait A { } + struct B<'a, T:'a>(&'a (dyn A + 'a)); trait X { } impl<'a, T> X for B<'a, T> {} fn g<'a, T: 'static>(v: Box + 'a>) -> Box { - box B(&*v) as Box //~ ERROR E0759 + Box::new(B(&*v)) as Box //~ ERROR E0759 } fn main() { } diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 78d2371cf53b2..9a7df8c0188b1 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -1,10 +1,10 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/regions-close-object-into-object-2.rs:10:11 + --> $DIR/regions-close-object-into-object-2.rs:9:16 | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ------------------ this data with lifetime `'a`... -LL | box B(&*v) as Box - | ^^^ ...is captured here, requiring it to live as long as `'static` +LL | Box::new(B(&*v)) as Box + | ^^^ ...is captured here, requiring it to live as long as `'static` | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | diff --git a/src/test/ui/regions/regions-close-object-into-object-3.rs b/src/test/ui/regions/regions-close-object-into-object-3.rs index 6f6b3a170027d..78d93b0ece5b6 100644 --- a/src/test/ui/regions/regions-close-object-into-object-3.rs +++ b/src/test/ui/regions/regions-close-object-into-object-3.rs @@ -1,14 +1,14 @@ -#![feature(box_syntax)] #![allow(warnings)] trait A { } + struct B<'a, T:'a>(&'a (A+'a)); trait X { } impl<'a, T> X for B<'a, T> {} fn h<'a, T, U:'static>(v: Box+'static>) -> Box { - box B(&*v) as Box //~ ERROR cannot return value referencing local data `*v` + Box::new(B(&*v)) as Box //~ ERROR cannot return value referencing local data `*v` } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-3.stderr b/src/test/ui/regions/regions-close-object-into-object-3.stderr index 9ea13638f5cad..9f92c40e1e18d 100644 --- a/src/test/ui/regions/regions-close-object-into-object-3.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-3.stderr @@ -1,10 +1,10 @@ error[E0515]: cannot return value referencing local data `*v` --> $DIR/regions-close-object-into-object-3.rs:11:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr index 93ac17810dae2..b30626830ad6b 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr @@ -1,39 +1,53 @@ error[E0310]: the parameter type `U` may not live long enough - --> $DIR/regions-close-object-into-object-4.rs:10:5 + --> $DIR/regions-close-object-into-object-4.rs:9:5 | -LL | box B(&*v) as Box - | ^^^^^^^^^^ +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `U: 'static`... + +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:9:5 + | +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `U: 'static`... + +error[E0310]: the parameter type `U` may not live long enough + --> $DIR/regions-close-object-into-object-4.rs:9:5 + | +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `U: 'static`... error: lifetime may not live long enough - --> $DIR/regions-close-object-into-object-4.rs:10:5 + --> $DIR/regions-close-object-into-object-4.rs:9:5 | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | -- lifetime `'a` defined here -LL | box B(&*v) as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static` error[E0515]: cannot return value referencing local data `*v` - --> $DIR/regions-close-object-into-object-4.rs:10:5 + --> $DIR/regions-close-object-into-object-4.rs:9:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error[E0310]: the parameter type `U` may not live long enough - --> $DIR/regions-close-object-into-object-4.rs:10:9 + --> $DIR/regions-close-object-into-object-4.rs:9:14 | -LL | box B(&*v) as Box - | ^^^^^^ +LL | Box::new(B(&*v)) as Box + | ^^^^^^ | = help: consider adding an explicit lifetime bound `U: 'static`... -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0310, E0515. For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-close-object-into-object-4.rs b/src/test/ui/regions/regions-close-object-into-object-4.rs index 4c087f264f92b..2a06a2b7c0513 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.rs +++ b/src/test/ui/regions/regions-close-object-into-object-4.rs @@ -1,13 +1,12 @@ -#![feature(box_syntax)] - trait A { } + struct B<'a, T:'a>(&'a (dyn A + 'a)); trait X { } impl<'a, T> X for B<'a, T> {} fn i<'a, T, U>(v: Box+'a>) -> Box { - box B(&*v) as Box //~ ERROR E0759 + Box::new(B(&*v)) as Box //~ ERROR E0759 } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 8c94b44f20037..a7a9b16b08013 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -1,10 +1,10 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/regions-close-object-into-object-4.rs:10:11 + --> $DIR/regions-close-object-into-object-4.rs:9:16 | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ---------------- this data with lifetime `'a`... -LL | box B(&*v) as Box - | ^^^ ...is captured here, requiring it to live as long as `'static` +LL | Box::new(B(&*v)) as Box + | ^^^ ...is captured here, requiring it to live as long as `'static` | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | diff --git a/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr index 08ba1b17b5663..7486e73e66ab3 100644 --- a/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr @@ -1,29 +1,45 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:17:5 | -LL | box B(&*v) as Box - | ^^^^^^^^^^ +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `T: 'static`... + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... error[E0515]: cannot return value referencing local data `*v` --> $DIR/regions-close-object-into-object-5.rs:17:5 | -LL | box B(&*v) as Box - | ^^^^^^---^^^^^^^^^^^ - | | | - | | `*v` is borrowed here +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^---^^^^^^^^^^^^^^^^ + | | | + | | `*v` is borrowed here | returns a value referencing data owned by the current function error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:9 + --> $DIR/regions-close-object-into-object-5.rs:17:14 | -LL | box B(&*v) as Box - | ^^^^^^ +LL | Box::new(B(&*v)) as Box + | ^^^^^^ | = help: consider adding an explicit lifetime bound `T: 'static`... -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0310, E0515. For more information about an error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-close-object-into-object-5.rs b/src/test/ui/regions/regions-close-object-into-object-5.rs index ff35b9ada45cd..5471c375b4990 100644 --- a/src/test/ui/regions/regions-close-object-into-object-5.rs +++ b/src/test/ui/regions/regions-close-object-into-object-5.rs @@ -1,6 +1,6 @@ -#![feature(box_syntax)] #![allow(warnings)] + trait A { fn get(&self) -> T { panic!() } @@ -14,13 +14,14 @@ impl<'a, T> X for B<'a, T> {} fn f<'a, T, U>(v: Box + 'static>) -> Box { // oh dear! - box B(&*v) as Box + Box::new(B(&*v)) as Box //~^ ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough } fn main() {} diff --git a/src/test/ui/regions/regions-close-object-into-object-5.stderr b/src/test/ui/regions/regions-close-object-into-object-5.stderr index 5b692cdcc0ecc..83f8d20b9e1de 100644 --- a/src/test/ui/regions/regions-close-object-into-object-5.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-5.stderr @@ -4,26 +4,41 @@ error[E0310]: the parameter type `T` may not live long enough LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... + | +note: ...that is required by this bound + --> $DIR/regions-close-object-into-object-5.rs:9:17 + | +LL | struct B<'a, T: 'a>(&'a (A + 'a)); + | ^^ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/regions-close-object-into-object-5.rs:17:5 + | +LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { + | - help: consider adding an explicit lifetime bound...: `T: 'static` +LL | // oh dear! +LL | Box::new(B(&*v)) as Box + | ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:9 + --> $DIR/regions-close-object-into-object-5.rs:17:14 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^ ...so that the type `T` will meet its required lifetime bounds +LL | Box::new(B(&*v)) as Box + | ^ ...so that the type `T` will meet its required lifetime bounds error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:9 + --> $DIR/regions-close-object-into-object-5.rs:17:14 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds... +LL | Box::new(B(&*v)) as Box + | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds... | note: ...that is required by this bound --> $DIR/regions-close-object-into-object-5.rs:9:17 @@ -32,32 +47,32 @@ LL | struct B<'a, T: 'a>(&'a (A + 'a)); | ^^ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:11 + --> $DIR/regions-close-object-into-object-5.rs:17:16 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^ ...so that the reference type `&dyn A` does not outlive the data it points at +LL | Box::new(B(&*v)) as Box + | ^^^ ...so that the reference type `&dyn A` does not outlive the data it points at error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:11 + --> $DIR/regions-close-object-into-object-5.rs:17:16 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long +LL | Box::new(B(&*v)) as Box + | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long error[E0310]: the parameter type `T` may not live long enough - --> $DIR/regions-close-object-into-object-5.rs:17:11 + --> $DIR/regions-close-object-into-object-5.rs:17:16 | LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | // oh dear! -LL | box B(&*v) as Box - | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long +LL | Box::new(B(&*v)) as Box + | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr index 3101d815881b1..b576ae8701137 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr @@ -1,16 +1,16 @@ error[E0310]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:12:5 | -LL | box v as Box - | ^^^^^ +LL | Box::new(v) as Box + | ^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `A: 'static`... error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:21:5 | -LL | box v as Box - | ^^^^^ +LL | Box::new(v) as Box + | ^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `A: 'b`... diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.rs b/src/test/ui/regions/regions-close-over-type-parameter-1.rs index 6e708a5f70fbd..52d18c5d7a6fa 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.rs +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.rs @@ -1,24 +1,24 @@ -#![feature(box_syntax)] - // Test for what happens when a type parameter `A` is closed over into // an object. This should yield errors unless `A` (and the object) // both have suitable bounds. + trait SomeTrait { fn get(&self) -> isize; } + fn make_object1(v: A) -> Box { - box v as Box + Box::new(v) as Box //~^ ERROR the parameter type `A` may not live long enough } fn make_object2<'a, A: SomeTrait + 'a>(v: A) -> Box { - box v as Box + Box::new(v) as Box } fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { - box v as Box + Box::new(v) as Box //~^ ERROR the parameter type `A` may not live long enough } diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr index 50274b066df60..063c3b19a19cc 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.stderr @@ -3,16 +3,16 @@ error[E0310]: the parameter type `A` may not live long enough | LL | fn make_object1(v: A) -> Box { | -- help: consider adding an explicit lifetime bound...: `A: 'static +` -LL | box v as Box - | ^^^^^ ...so that the type `A` will meet its required lifetime bounds +LL | Box::new(v) as Box + | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:21:5 | LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { | -- help: consider adding an explicit lifetime bound...: `A: 'b +` -LL | box v as Box - | ^^^^^ ...so that the type `A` will meet its required lifetime bounds +LL | Box::new(v) as Box + | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr index 2fb9dcc4e9ec7..c2bd3bbf823d2 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr @@ -6,8 +6,8 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c` +LL | Box::new(v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c` | = help: consider adding the following bound: `'a: 'c` diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs b/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs index 26643e08985be..fc7696e7e0320 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.rs @@ -1,23 +1,23 @@ -#![feature(box_syntax)] - // Various tests where we over type parameters with multiple lifetime // bounds. + trait SomeTrait { fn get(&self) -> isize; } + fn make_object_good1<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b... - box v as Box // ...hence this type is safe. + Box::new(v) as Box // ...hence this type is safe. } fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b... - box v as Box // ...hence this type is safe. + Box::new(v) as Box // ...hence this type is safe. } fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR cannot infer an appropriate lifetime + Box::new(v) as Box //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr index bf29c76a0f0a8..0cb0b24f108b0 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr @@ -1,8 +1,8 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5 | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::new(v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 18:20... --> $DIR/regions-close-over-type-parameter-multiple.rs:18:20 @@ -12,8 +12,8 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box $DIR/regions-close-over-type-parameter-multiple.rs:20:5 | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::new(v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: but, the lifetime must be valid for the lifetime `'c` as defined on the function body at 18:26... --> $DIR/regions-close-over-type-parameter-multiple.rs:18:26 | @@ -22,8 +22,8 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box $DIR/regions-close-over-type-parameter-multiple.rs:20:5 | -LL | box v as Box - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::new(v) as Box + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected `Box<(dyn SomeTrait + 'c)>` found `Box` diff --git a/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs b/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs index 4b47ed8c6aeb7..48aad9481bbea 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs +++ b/src/test/ui/regions/regions-close-over-type-parameter-successfully.rs @@ -2,8 +2,6 @@ // A test where we (successfully) close over a reference into // an object. -#![feature(box_syntax)] - trait SomeTrait { fn get(&self) -> isize; } impl<'a> SomeTrait for &'a isize { @@ -13,7 +11,7 @@ impl<'a> SomeTrait for &'a isize { } fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box { - box v as Box + Box::new(v) as Box } fn main() { diff --git a/src/test/ui/regions/regions-dependent-addr-of.rs b/src/test/ui/regions/regions-dependent-addr-of.rs index 0a7e6625c7353..a6cb56e3156d4 100644 --- a/src/test/ui/regions/regions-dependent-addr-of.rs +++ b/src/test/ui/regions/regions-dependent-addr-of.rs @@ -3,7 +3,6 @@ // Issue #3148. #![feature(box_patterns)] -#![feature(box_syntax)] struct A { value: B @@ -81,7 +80,7 @@ pub fn main() { v2: [23, 24, 25], v3: vec![26, 27, 28], v4: C { f: 29 }, - v5: box C { f: 30 }, + v5: Box::new(C { f: 30 }), v6: Some(C { f: 31 })}}; let p = get_v1(&a); diff --git a/src/test/ui/regions/regions-early-bound-trait-param.rs b/src/test/ui/regions/regions-early-bound-trait-param.rs index 276a64b8e9a7b..a28bd14ba88f6 100644 --- a/src/test/ui/regions/regions-early-bound-trait-param.rs +++ b/src/test/ui/regions/regions-early-bound-trait-param.rs @@ -2,8 +2,6 @@ // Tests that you can use an early-bound lifetime parameter as // on of the generic parameters in a trait. -#![feature(box_syntax)] - trait Trait<'a> { fn long(&'a self) -> isize; fn short<'b>(&'b self) -> isize; @@ -72,7 +70,7 @@ impl<'s> Trait<'s> for (isize,isize) { impl<'t> MakerTrait for Box+'static> { fn mk() -> Box+'static> { - let tup: Box<(isize, isize)> = box (4,5); + let tup: Box<(isize, isize)> = Box::new((4,5)); tup as Box } } diff --git a/src/test/ui/regions/regions-escape-into-other-fn.rs b/src/test/ui/regions/regions-escape-into-other-fn.rs index fd4690463e666..65f4c1b6a6487 100644 --- a/src/test/ui/regions/regions-escape-into-other-fn.rs +++ b/src/test/ui/regions/regions-escape-into-other-fn.rs @@ -1,10 +1,8 @@ // run-pass -#![feature(box_syntax)] - fn foo(x: &usize) -> &usize { x } fn bar(x: &usize) -> usize { *x } pub fn main() { - let p: Box<_> = box 3; + let p: Box<_> = Box::new(3); assert_eq!(bar(foo(&*p)), 3); } diff --git a/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs b/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs index f0ecc5de54567..dca26742dacc5 100644 --- a/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs +++ b/src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] fn borrow(x: &T) -> &T {x} pub fn main() { - let x: Box<_> = box 3; + let x: Box<_> = Box::new(3); loop { let y = borrow(&*x); assert_eq!(*x, *y); diff --git a/src/test/ui/regions/regions-infer-borrow-scope.rs b/src/test/ui/regions/regions-infer-borrow-scope.rs index 453973d9c58c3..b4a050bf1ede0 100644 --- a/src/test/ui/regions/regions-infer-borrow-scope.rs +++ b/src/test/ui/regions/regions-infer-borrow-scope.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] struct Point {x: isize, y: isize} @@ -9,7 +8,7 @@ fn x_coord(p: &Point) -> &isize { } pub fn main() { - let p: Box<_> = box Point {x: 3, y: 4}; + let p: Box<_> = Box::new(Point {x: 3, y: 4}); let xc = x_coord(&*p); assert_eq!(*xc, 3); } diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr index 3256e3c0dd381..0c1e3989b234a 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr +++ b/src/test/ui/regions/regions-infer-invariance-due-to-decl.nll.stderr @@ -5,8 +5,6 @@ LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { | -- lifetime `'r` defined here LL | b_isize | ^^^^^^^ returning this value requires that `'r` must outlive `'static` - | - = help: consider replacing `'r` with `'static` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr index 991f9a287b9bf..0edeb2723998f 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-3.nll.stderr @@ -5,8 +5,6 @@ LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { | -- lifetime `'r` defined here LL | b_isize | ^^^^^^^ returning this value requires that `'r` must outlive `'static` - | - = help: consider replacing `'r` with `'static` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr index 2d62fb85b81eb..724dd7e3f6d3f 100644 --- a/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr +++ b/src/test/ui/regions/regions-infer-invariance-due-to-mutability-4.nll.stderr @@ -5,8 +5,6 @@ LL | fn to_longer_lifetime<'r>(b_isize: Invariant<'r>) -> Invariant<'static> { | -- lifetime `'r` defined here LL | b_isize | ^^^^^^^ returning this value requires that `'r` must outlive `'static` - | - = help: consider replacing `'r` with `'static` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs b/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs index c8106f32c65c2..3852a14d9f98e 100644 --- a/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs +++ b/src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs @@ -15,19 +15,17 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { fn explicit() { fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} - test(Some(box |_f: Box FnMut(&'a isize)>| {})); + test(Some(Box::new(|_f: Box FnMut(&'a isize)>| {}))); } // The code below is shorthand for the code above (and more likely // to represent what one encounters in practice). fn implicit() { fn test(_x: Option>) where F: FnMut(Box) {} - test(Some(box |_f: Box| {})); + test(Some(Box::new(|_f: Box| {}))); } explicit(); diff --git a/src/test/ui/regions/regions-nested-fns.nll.stderr b/src/test/ui/regions/regions-nested-fns.nll.stderr index 60754f4c2284c..a0cfa36247228 100644 --- a/src/test/ui/regions/regions-nested-fns.nll.stderr +++ b/src/test/ui/regions/regions-nested-fns.nll.stderr @@ -45,8 +45,6 @@ LL | fn nested<'x>(x: &'x isize) { ... LL | if false { return x; } | ^ returning this value requires that `'x` must outlive `'static` - | - = help: consider replacing `'x` with `'static` error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-ref-in-fn-arg.rs b/src/test/ui/regions/regions-ref-in-fn-arg.rs index d1cbd279b65a5..3df529c9f0dae 100644 --- a/src/test/ui/regions/regions-ref-in-fn-arg.rs +++ b/src/test/ui/regions/regions-ref-in-fn-arg.rs @@ -1,11 +1,11 @@ #![feature(box_patterns)] -#![feature(box_syntax)] + fn arg_item(box ref x: Box) -> &'static isize { x //~ ERROR cannot return value referencing function parameter } -fn with(f: F) -> R where F: FnOnce(Box) -> R { f(box 3) } +fn with(f: F) -> R where F: FnOnce(Box) -> R { f(Box::new(3)) } fn arg_closure() -> &'static isize { with(|box ref x| x) //~ ERROR cannot return value referencing function parameter diff --git a/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs b/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs index aec05161c1afb..b1bdb813ac6aa 100644 --- a/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs +++ b/src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs @@ -9,8 +9,6 @@ // changes were caught. However, those uses in the compiler could // easily get changed or refactored away in the future. -#![feature(box_syntax)] - struct Ctxt<'tcx> { x: &'tcx Vec } diff --git a/src/test/ui/regions/regions-static-bound.migrate.nll.stderr b/src/test/ui/regions/regions-static-bound.migrate.nll.stderr index a4c8e721145eb..a280c6f0a02d2 100644 --- a/src/test/ui/regions/regions-static-bound.migrate.nll.stderr +++ b/src/test/ui/regions/regions-static-bound.migrate.nll.stderr @@ -5,8 +5,6 @@ LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { | -- lifetime `'a` defined here LL | t | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error[E0621]: explicit lifetime required in the type of `u` --> $DIR/regions-static-bound.rs:14:5 diff --git a/src/test/ui/regions/regions-static-bound.nll.stderr b/src/test/ui/regions/regions-static-bound.nll.stderr index a4c8e721145eb..a280c6f0a02d2 100644 --- a/src/test/ui/regions/regions-static-bound.nll.stderr +++ b/src/test/ui/regions/regions-static-bound.nll.stderr @@ -5,8 +5,6 @@ LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { | -- lifetime `'a` defined here LL | t | ^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error[E0621]: explicit lifetime required in the type of `u` --> $DIR/regions-static-bound.rs:14:5 diff --git a/src/test/ui/regions/regions-trait-variance.rs b/src/test/ui/regions/regions-trait-variance.rs index 9169d457d4051..94ffb85c9c9c5 100644 --- a/src/test/ui/regions/regions-trait-variance.rs +++ b/src/test/ui/regions/regions-trait-variance.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - // Issue #12470. trait X { @@ -31,9 +29,11 @@ fn make_a(p: &dyn X) -> A { } fn make_make_a<'a>() -> A<'a> { - let b: Box = box B { + + let b: Box = Box::new(B { i: 1, - }; + }); + let bb: &B = &*b; make_a(bb) //~ ERROR cannot return value referencing local data `*b` } diff --git a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr index 90388a1c51b1f..15853e6ca5d69 100644 --- a/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr +++ b/src/test/ui/regions/regions-variance-invariant-use-covariant.nll.stderr @@ -6,8 +6,6 @@ LL | fn use_<'b>(c: Invariant<'b>) { ... LL | let _: Invariant<'static> = c; | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'b` must outlive `'static` - | - = help: consider replacing `'b` with `'static` error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-42944.stderr b/src/test/ui/resolve/issue-42944.stderr index 008492529d18c..cad3ccc4a0ef8 100644 --- a/src/test/ui/resolve/issue-42944.stderr +++ b/src/test/ui/resolve/issue-42944.stderr @@ -16,10 +16,11 @@ error[E0425]: cannot find function, tuple struct or tuple variant `Bx` in this s LL | Bx(()); | ^^ not found in this scope | -help: consider importing this tuple struct - | -LL | use foo::Bx; +note: tuple struct `foo::Bx` exists but is inaccessible + --> $DIR/issue-42944.rs:2:5 | +LL | pub struct Bx(()); + | ^^^^^^^^^^^^^^^^^^ not accessible error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/issue-88472.rs b/src/test/ui/resolve/issue-88472.rs new file mode 100644 index 0000000000000..6bf7caeddbfcd --- /dev/null +++ b/src/test/ui/resolve/issue-88472.rs @@ -0,0 +1,38 @@ +// Regression test for #88472, where a suggestion was issued to +// import an inaccessible struct. + +#![warn(unused_imports)] +//~^ NOTE: the lint level is defined here + +mod a { + struct Foo; + //~^ NOTE: struct `a::Foo` exists but is inaccessible + //~| NOTE: not accessible +} + +mod b { + use crate::a::*; + //~^ WARNING: unused import + type Bar = Foo; + //~^ ERROR: cannot find type `Foo` in this scope [E0412] + //~| NOTE: not found in this scope +} + +mod c { + enum Eee {} + //~^ NOTE: these enums exist but are inaccessible + //~| NOTE: `c::Eee`: not accessible + + mod d { + enum Eee {} + //~^ NOTE: `c::d::Eee`: not accessible + } +} + +mod e { + type Baz = Eee; + //~^ ERROR: cannot find type `Eee` in this scope [E0412] + //~| NOTE: not found in this scope +} + +fn main() {} diff --git a/src/test/ui/resolve/issue-88472.stderr b/src/test/ui/resolve/issue-88472.stderr new file mode 100644 index 0000000000000..8431fc97766f7 --- /dev/null +++ b/src/test/ui/resolve/issue-88472.stderr @@ -0,0 +1,42 @@ +error[E0412]: cannot find type `Foo` in this scope + --> $DIR/issue-88472.rs:16:16 + | +LL | type Bar = Foo; + | ^^^ not found in this scope + | +note: struct `a::Foo` exists but is inaccessible + --> $DIR/issue-88472.rs:8:5 + | +LL | struct Foo; + | ^^^^^^^^^^^ not accessible + +error[E0412]: cannot find type `Eee` in this scope + --> $DIR/issue-88472.rs:33:16 + | +LL | type Baz = Eee; + | ^^^ not found in this scope + | +note: these enums exist but are inaccessible + --> $DIR/issue-88472.rs:22:5 + | +LL | enum Eee {} + | ^^^^^^^^ `c::Eee`: not accessible +... +LL | enum Eee {} + | ^^^^^^^^ `c::d::Eee`: not accessible + +warning: unused import: `crate::a::*` + --> $DIR/issue-88472.rs:14:9 + | +LL | use crate::a::*; + | ^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-88472.rs:4:9 + | +LL | #![warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 192349e0fafe3..ff72b0b563ab1 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -169,16 +169,13 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z; - | ^ + | ^ help: an enum with a similar name exists: `E` | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z; - | ~ -help: consider importing this enum - | -LL | use m::Z; +note: enum `m::Z` exists but is inaccessible + --> $DIR/privacy-enum-ctor.rs:11:9 | +LL | pub(in m) enum Z { + | ^^^^^^^^^^^^^^^^ not accessible error[E0423]: expected value, found enum `m::n::Z` --> $DIR/privacy-enum-ctor.rs:57:16 @@ -215,16 +212,13 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Fn; - | ^ + | ^ help: an enum with a similar name exists: `E` | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z::Fn; - | ~ -help: consider importing this enum - | -LL | use m::Z; +note: enum `m::Z` exists but is inaccessible + --> $DIR/privacy-enum-ctor.rs:11:9 | +LL | pub(in m) enum Z { + | ^^^^^^^^^^^^^^^^ not accessible error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:64:12 @@ -233,16 +227,13 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Struct; - | ^ + | ^ help: an enum with a similar name exists: `E` | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z::Struct; - | ~ -help: consider importing this enum - | -LL | use m::Z; +note: enum `m::Z` exists but is inaccessible + --> $DIR/privacy-enum-ctor.rs:11:9 | +LL | pub(in m) enum Z { + | ^^^^^^^^^^^^^^^^ not accessible error[E0423]: expected value, found struct variant `m::n::Z::Struct` --> $DIR/privacy-enum-ctor.rs:64:16 @@ -262,16 +253,13 @@ LL | pub enum E { | ---------- similarly named enum `E` defined here ... LL | let _: Z = m::n::Z::Unit {}; - | ^ + | ^ help: an enum with a similar name exists: `E` | -help: an enum with a similar name exists - | -LL | let _: E = m::n::Z::Unit {}; - | ~ -help: consider importing this enum - | -LL | use m::Z; +note: enum `m::Z` exists but is inaccessible + --> $DIR/privacy-enum-ctor.rs:11:9 | +LL | pub(in m) enum Z { + | ^^^^^^^^^^^^^^^^ not accessible error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:57:22 diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr index e5d6f7e9e24f0..ada053014ef5e 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.stderr +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -33,10 +33,11 @@ error[E0423]: expected value, found struct `xcrate::S` LL | xcrate::S; | ^^^^^^^^^ constructor is not visible here due to private fields | -help: consider importing this tuple struct instead - | -LL | use m::S; +note: tuple struct `m::S` exists but is inaccessible + --> $DIR/privacy-struct-ctor.rs:6:5 | +LL | pub struct S(u8); + | ^^^^^^^^^^^^^^^^^ not accessible error[E0603]: tuple struct constructor `Z` is private --> $DIR/privacy-struct-ctor.rs:18:12 diff --git a/src/test/ui/resolve/suggest-path-for-tuple-struct.rs b/src/test/ui/resolve/suggest-path-for-tuple-struct.rs new file mode 100644 index 0000000000000..c8bc3e79fe2f0 --- /dev/null +++ b/src/test/ui/resolve/suggest-path-for-tuple-struct.rs @@ -0,0 +1,26 @@ +mod module { + pub struct SomeTupleStruct(u8); + pub struct SomeRegularStruct { + foo: u8 + } + + impl SomeTupleStruct { + pub fn new() -> Self { + Self(0) + } + } + impl SomeRegularStruct { + pub fn new() -> Self { + Self { foo: 0 } + } + } +} + +use module::{SomeTupleStruct, SomeRegularStruct}; + +fn main() { + let _ = SomeTupleStruct.new(); + //~^ ERROR expected value, found struct `SomeTupleStruct` + let _ = SomeRegularStruct.new(); + //~^ ERROR expected value, found struct `SomeRegularStruct` +} diff --git a/src/test/ui/resolve/suggest-path-for-tuple-struct.stderr b/src/test/ui/resolve/suggest-path-for-tuple-struct.stderr new file mode 100644 index 0000000000000..957045ca74bb2 --- /dev/null +++ b/src/test/ui/resolve/suggest-path-for-tuple-struct.stderr @@ -0,0 +1,19 @@ +error[E0423]: expected value, found struct `SomeTupleStruct` + --> $DIR/suggest-path-for-tuple-struct.rs:22:13 + | +LL | let _ = SomeTupleStruct.new(); + | ^^^^^^^^^^^^^^^---- + | | + | help: use the path separator to refer to an item: `SomeTupleStruct::new` + +error[E0423]: expected value, found struct `SomeRegularStruct` + --> $DIR/suggest-path-for-tuple-struct.rs:24:13 + | +LL | let _ = SomeRegularStruct.new(); + | ^^^^^^^^^^^^^^^^^---- + | | + | help: use the path separator to refer to an item: `SomeRegularStruct::new` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr b/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr index d836741f9eddf..d4410e147503a 100644 --- a/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr +++ b/src/test/ui/rfc-1717-dllimport/missing-link-attr.stderr @@ -1,4 +1,4 @@ -error: renaming of the library `foo` was specified, however this crate contains no `#[link(...)]` attributes referencing this library. +error: renaming of the library `foo` was specified, however this crate contains no `#[link(...)]` attributes referencing this library error: aborting due to previous error diff --git a/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr b/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr index 4e5a3647fa2d2..a6fec9c4e2b5f 100644 --- a/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr +++ b/src/test/ui/rfc-1717-dllimport/multiple-renames.stderr @@ -1,4 +1,4 @@ -error: multiple renamings were specified for library `foo` . +error: multiple renamings were specified for library `foo` error: aborting due to previous error diff --git a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr deleted file mode 100644 index c74b82dbbd828..0000000000000 --- a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-issue-49631.rs:20:9 - | -LL | while let Some(Ok(string)) = foo.get() { - | --- immutable borrow occurs here -LL | foo.mutate(); - | ^^^ mutable borrow occurs here -LL | -LL | println!("foo={:?}", *string); - | ------- immutable borrow later used here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr index 04572920ee414..b7c0b0bb6b93e 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.stderr @@ -2,7 +2,7 @@ error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immu --> $DIR/borrowck-issue-49631.rs:20:9 | LL | while let Some(Ok(string)) = foo.get() { - | --- immutable borrow occurs here + | --------- immutable borrow occurs here LL | foo.mutate(); | ^^^^^^^^^^^^ mutable borrow occurs here LL | diff --git a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs index 5b2181d2d833b..78db6b170bb13 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/auxiliary/structs.rs @@ -31,3 +31,11 @@ pub struct NestedStruct { pub foo: u16, pub bar: NormalStruct, } + +#[derive(Default)] +#[non_exhaustive] +pub struct MixedVisFields { + pub a: u16, + pub b: bool, + pub(crate) foo: bool, +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs index 115fd300fa526..c196ded404ddc 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.rs @@ -10,7 +10,7 @@ use enums::{ EmptyNonExhaustiveEnum, NestedNonExhaustive, NonExhaustiveEnum, NonExhaustiveSingleVariant, VariantNonExhaustive, }; -use structs::{FunctionalRecord, NestedStruct, NormalStruct}; +use structs::{FunctionalRecord, MixedVisFields, NestedStruct, NormalStruct}; #[non_exhaustive] #[derive(Default)] @@ -141,6 +141,10 @@ fn main() { //~^ some fields are not explicitly listed //~^^ some fields are not explicitly listed + // Ok: this tests https://github.com/rust-lang/rust/issues/89382 + #[warn(non_exhaustive_omitted_patterns)] + let MixedVisFields { a, b, .. } = MixedVisFields::default(); + // Ok: because this only has 1 variant #[deny(non_exhaustive_omitted_patterns)] match NonExhaustiveSingleVariant::A(true) { diff --git a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr index aebe2acb6ad89..e66fd8008a10b 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/reachable-patterns.stderr @@ -129,13 +129,13 @@ LL | #[deny(non_exhaustive_omitted_patterns)] = note: the matched value is of type `ErrorKind` and the `non_exhaustive_omitted_patterns` attribute was found error: some variants are not matched explicitly - --> $DIR/reachable-patterns.rs:153:9 + --> $DIR/reachable-patterns.rs:157:9 | LL | _ => {} | ^ pattern `A(_)` not covered | note: the lint level is defined here - --> $DIR/reachable-patterns.rs:151:12 + --> $DIR/reachable-patterns.rs:155:12 | LL | #[deny(non_exhaustive_omitted_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2091-track-caller/tracked-closure.rs b/src/test/ui/rfc-2091-track-caller/tracked-closure.rs new file mode 100644 index 0000000000000..670c423a7e0e2 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/tracked-closure.rs @@ -0,0 +1,154 @@ +// run-pass + +#![feature(stmt_expr_attributes)] +#![feature(closure_track_caller)] +#![feature(generator_trait)] +#![feature(generators)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; +use std::panic::Location; + +type Loc = &'static Location<'static>; + +#[track_caller] +fn mono_invoke_fn (&'static str, bool, Loc)>( + val: &F +) -> (&'static str, bool, Loc) { + val("from_mono", false) +} + +#[track_caller] +fn mono_invoke_fn_once (&'static str, bool, Loc)>( + val: F +) -> (&'static str, bool, Loc) { + val("from_mono", false) +} + +#[track_caller] +fn dyn_invoke_fn_mut( + val: &mut dyn FnMut(&'static str, bool) -> (&'static str, bool, Loc) +) -> (&'static str, bool, Loc) { + val("from_dyn", false) +} + +#[track_caller] +fn dyn_invoke_fn_once( + val: Box (&'static str, bool, Loc)> +) -> (&'static str, bool, Loc) { + val("from_dyn", false) +} + + +fn test_closure() { + let mut track_closure = #[track_caller] |first: &'static str, second: bool| { + (first, second, Location::caller()) + }; + let (first_arg, first_bool, first_loc) = track_closure("first_arg", true); + let first_line = line!() - 1; + assert_eq!(first_arg, "first_arg"); + assert_eq!(first_bool, true); + assert_eq!(first_loc.file(), file!()); + assert_eq!(first_loc.line(), first_line); + assert_eq!(first_loc.column(), 46); + + let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_mut(&mut track_closure); + assert_eq!(dyn_arg, "from_dyn"); + assert_eq!(dyn_bool, false); + // `FnMut::call_mut` does not have `#[track_caller]`, + // so this will not match + assert_ne!(dyn_loc.file(), file!()); + + let (dyn_arg, dyn_bool, dyn_loc) = dyn_invoke_fn_once(Box::new(track_closure)); + assert_eq!(dyn_arg, "from_dyn"); + assert_eq!(dyn_bool, false); + // `FnOnce::call_once` does not have `#[track_caller]` + // so this will not match + assert_ne!(dyn_loc.file(), file!()); + + + let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn(&track_closure); + let mono_line = line!() - 1; + assert_eq!(mono_arg, "from_mono"); + assert_eq!(mono_bool, false); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 43); + + let (mono_arg, mono_bool, mono_loc) = mono_invoke_fn_once(track_closure); + let mono_line = line!() - 1; + assert_eq!(mono_arg, "from_mono"); + assert_eq!(mono_bool, false); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 43); + + let non_tracked_caller = || Location::caller(); + let non_tracked_line = line!() - 1; // This is the line of the closure, not its caller + let non_tracked_loc = non_tracked_caller(); + assert_eq!(non_tracked_loc.file(), file!()); + assert_eq!(non_tracked_loc.line(), non_tracked_line); + assert_eq!(non_tracked_loc.column(), 33); +} + + +#[track_caller] +fn mono_generator>( + val: Pin<&mut F> +) -> (&'static str, String, Loc) { + match val.resume("Mono".to_string()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + } +} + +#[track_caller] +fn dyn_generator( + val: Pin<&mut dyn Generator> +) -> (&'static str, String, Loc) { + match val.resume("Dyn".to_string()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + } +} + +fn test_generator() { + let generator = #[track_caller] |arg: String| { + yield ("first", arg.clone(), Location::caller()); + yield ("second", arg.clone(), Location::caller()); + }; + + let mut pinned = Box::pin(generator); + let (dyn_ret, dyn_arg, dyn_loc) = dyn_generator(pinned.as_mut()); + assert_eq!(dyn_ret, "first"); + assert_eq!(dyn_arg, "Dyn".to_string()); + // The `Generator` trait does not have `#[track_caller]` on `resume`, so + // this will not match. + assert_ne!(dyn_loc.file(), file!()); + + + let (mono_ret, mono_arg, mono_loc) = mono_generator(pinned.as_mut()); + let mono_line = line!() - 1; + assert_eq!(mono_ret, "second"); + // The generator ignores the argument to the second `resume` call + assert_eq!(mono_arg, "Dyn".to_string()); + assert_eq!(mono_loc.file(), file!()); + assert_eq!(mono_loc.line(), mono_line); + assert_eq!(mono_loc.column(), 42); + + let non_tracked_generator = || { yield Location::caller(); }; + let non_tracked_line = line!() - 1; // This is the line of the generator, not its caller + let non_tracked_loc = match Box::pin(non_tracked_generator).as_mut().resume(()) { + GeneratorState::Yielded(val) => val, + _ => unreachable!() + }; + assert_eq!(non_tracked_loc.file(), file!()); + assert_eq!(non_tracked_loc.line(), non_tracked_line); + assert_eq!(non_tracked_loc.column(), 44); + +} + +fn main() { + test_closure(); + test_generator(); +} diff --git a/src/test/ui/rfc-2457/extern_block_nonascii_forbidden.stderr b/src/test/ui/rfc-2457/extern_block_nonascii_forbidden.stderr index ab8832e916315..ca1b8a6e7b9b2 100644 --- a/src/test/ui/rfc-2457/extern_block_nonascii_forbidden.stderr +++ b/src/test/ui/rfc-2457/extern_block_nonascii_forbidden.stderr @@ -6,7 +6,7 @@ LL | extern "C" { LL | type 一; | ^^ | - = note: This limitation may be lifted in the future; see issue #83942 for more information + = note: this limitation may be lifted in the future; see issue #83942 for more information error: items in `extern` blocks cannot use non-ascii identifiers --> $DIR/extern_block_nonascii_forbidden.rs:5:8 @@ -17,7 +17,7 @@ LL | type 一; LL | fn 二(); | ^^ | - = note: This limitation may be lifted in the future; see issue #83942 for more information + = note: this limitation may be lifted in the future; see issue #83942 for more information error: items in `extern` blocks cannot use non-ascii identifiers --> $DIR/extern_block_nonascii_forbidden.rs:6:12 @@ -28,7 +28,7 @@ LL | extern "C" { LL | static 三: usize; | ^^ | - = note: This limitation may be lifted in the future; see issue #83942 for more information + = note: this limitation may be lifted in the future; see issue #83942 for more information error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs b/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs new file mode 100644 index 0000000000000..99e608797ff65 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/const-closures.rs @@ -0,0 +1,31 @@ +// run-pass + +#![feature(const_trait_impl)] +#![feature(const_fn_trait_bound)] + +const fn answer_p1(f: &F) -> u8 + where + F: ~const FnOnce() -> u8, + F: ~const FnMut() -> u8, + F: ~const Fn() -> u8, +{ + f() * 7 +} + +const fn three() -> u8 { + 3 +} + +const fn answer_p2() -> u8 { + answer_p1(&three) +} + +const fn answer u8>(f: &F) -> u8 { + f() + f() +} + +const ANSWER: u8 = answer(&answer_p2); + +fn main() { + assert_eq!(ANSWER, 42) +} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs index 9a1b554f45f65..292017a1de24d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs @@ -3,7 +3,6 @@ #![feature(const_trait_impl)] #![feature(const_fn_trait_bound)] #![feature(const_mut_refs)] -#![feature(const_panic)] #![cfg_attr(precise, feature(const_precise_live_drops))] struct S<'a>(&'a mut u8); diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr index 86b685959a6cb..5649f688fe7c6 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr @@ -13,7 +13,7 @@ error: `::add` is not yet stable as a const fn LL | Int(1i32) + Int(2i32) | ^^^^^^^^^^^^^^^^^^^^^ | - = help: Const-stable functions can only call other const-stable functions + = help: const-stable functions can only call other const-stable functions error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr index cc247bbcb1199..7f15c1c1f5770 100644 --- a/src/test/ui/rfc1623.nll.stderr +++ b/src/test/ui/rfc1623.nll.stderr @@ -31,7 +31,7 @@ LL | | LL | | }; | |_^ one type is more general than the other | - = note: expected type `for<'r, 's> Fn<(&'r Foo<'s>,)>` + = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>` found type `Fn<(&Foo<'_>,)>` error[E0308]: mismatched types @@ -46,7 +46,7 @@ LL | | LL | | }; | |_^ one type is more general than the other | - = note: expected type `for<'r, 's> Fn<(&'r Foo<'s>,)>` + = note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>` found type `Fn<(&Foo<'_>,)>` error: implementation of `FnOnce` is not general enough @@ -61,7 +61,7 @@ LL | | LL | | }; | |_^ implementation of `FnOnce` is not general enough | - = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'_>,)>`, for any lifetime `'1`... + = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2` error: implementation of `FnOnce` is not general enough @@ -76,7 +76,7 @@ LL | | LL | | }; | |_^ implementation of `FnOnce` is not general enough | - = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&Foo<'1>,)>`, for any lifetime `'1`... + = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`... = note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2` error: aborting due to 5 previous errors diff --git a/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs b/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs index b3be41599a545..0d1cded36b62d 100644 --- a/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs +++ b/src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs @@ -1,11 +1,11 @@ // run-pass #![allow(unreachable_patterns)] -#![feature(box_syntax, box_patterns)] +#![feature(box_patterns)] struct Foo{} pub fn main() { - let b = box Foo{}; + let b = Box::new(Foo{}); let box f = &b; let _: &Foo = f; diff --git a/src/test/ui/sanitize/crt-static.stderr b/src/test/ui/sanitize/crt-static.stderr index 3a9c636d76046..9f74235fea5d2 100644 --- a/src/test/ui/sanitize/crt-static.stderr +++ b/src/test/ui/sanitize/crt-static.stderr @@ -1,4 +1,4 @@ -error: Sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` +error: sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` error: aborting due to previous error diff --git a/src/test/ui/self/explicit-self-generic.rs b/src/test/ui/self/explicit-self-generic.rs index 03f72a5513c20..8f6bed3b0cd6e 100644 --- a/src/test/ui/self/explicit-self-generic.rs +++ b/src/test/ui/self/explicit-self-generic.rs @@ -1,6 +1,5 @@ // run-pass #![allow(dead_code)] -#![feature(box_syntax)] #[derive(Copy, Clone)] struct LM { resize_at: usize, size: usize } @@ -24,6 +23,6 @@ impl HashMap { } pub fn main() { - let mut m: Box<_> = box linear_map::<(),()>(); + let mut m: Box<_> = Box::new(linear_map::<(),()>()); assert_eq!(m.len(), 0); } diff --git a/src/test/ui/self/explicit-self-objects-uniq.rs b/src/test/ui/self/explicit-self-objects-uniq.rs index 0050bc7124d71..250ea12e57c81 100644 --- a/src/test/ui/self/explicit-self-objects-uniq.rs +++ b/src/test/ui/self/explicit-self-objects-uniq.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] trait Foo { fn f(self: Box); @@ -16,7 +15,7 @@ impl Foo for S { } pub fn main() { - let x = box S { x: 3 }; + let x = Box::new(S { x: 3 }); let y = x as Box; y.f(); } diff --git a/src/test/ui/self/explicit-self.rs b/src/test/ui/self/explicit-self.rs index 6d19d33b6fee9..873c3621a3bce 100644 --- a/src/test/ui/self/explicit-self.rs +++ b/src/test/ui/self/explicit-self.rs @@ -3,8 +3,6 @@ #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] -#![feature(box_syntax)] - static tau: f64 = 2.0*3.14159265358979323; struct Point {x: f64, y: f64} @@ -64,7 +62,7 @@ trait Nus { fn f(&self); } impl Nus for thing { fn f(&self) {} } pub fn main() { - let y: Box<_> = box thing(A {a: 10}); + let y: Box<_> = Box::new(thing(A {a: 10})); assert_eq!(y.clone().bar(), 10); assert_eq!(y.quux(), 10); diff --git a/src/test/ui/self/self-impl-2.rs b/src/test/ui/self/self-impl-2.rs index 23d513e3fac07..7eed3f056a25f 100644 --- a/src/test/ui/self/self-impl-2.rs +++ b/src/test/ui/self/self-impl-2.rs @@ -5,8 +5,6 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - struct Foo; // Test uses on inherent impl. @@ -57,14 +55,14 @@ impl Bar for Box> { let _: Self::SuperQux = true; let _: ::SuperQux = true; - box Baz { f: 42 } + Box::new(Baz { f: 42 }) } } fn main() { - let _: Foo = Foo::foo(Foo, &Foo, box Foo); - let _: Box> = Bar::bar(box Baz { f: 42 }, - &box Baz { f: 42 }, - box box Baz { f: 42 }, + let _: Foo = Foo::foo(Foo, &Foo, Box::new(Foo)); + let _: Box> = Bar::bar(Box::new(Baz { f: 42 }), + &Box::new(Baz { f: 42 }), + Box::new(Box::new(Baz { f: 42 })), true); } diff --git a/src/test/ui/self/self-in-mut-slot-default-method.rs b/src/test/ui/self/self-in-mut-slot-default-method.rs index 82c5f58f0208f..45e122c8d77a0 100644 --- a/src/test/ui/self/self-in-mut-slot-default-method.rs +++ b/src/test/ui/self/self-in-mut-slot-default-method.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] struct X { a: isize @@ -30,7 +29,7 @@ pub fn main() { let new_x = x.change(); assert_eq!(new_x.a, 55); - let x: Box<_> = box new_x; + let x: Box<_> = Box::new(new_x); let new_x = x.change_again(); assert_eq!(new_x.a, 45); } diff --git a/src/test/ui/self/self-re-assign.rs b/src/test/ui/self/self-re-assign.rs index 88e8614683227..9595ebf9601fb 100644 --- a/src/test/ui/self/self-re-assign.rs +++ b/src/test/ui/self/self-re-assign.rs @@ -2,13 +2,12 @@ // Ensure assigning an owned or managed variable to itself works. In particular, // that we do not glue_drop before we glue_take (#3290). -#![feature(box_syntax)] #![allow(dead_code)] use std::rc::Rc; pub fn main() { - let mut x: Box<_> = box 3; + let mut x: Box<_> = Box::new(3); x = x; assert_eq!(*x, 3); diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index 47c04f1eb72ec..aca08d81163fd 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -66,10 +66,11 @@ error[E0531]: cannot find unit struct, unit variant or constant `Self` in this s LL | mut Self => (), | ^^^^ not found in this scope | -help: consider importing this unit struct - | -LL | use foo::Self; +note: unit struct `foo::Self` exists but is inaccessible + --> $DIR/self_type_keyword.rs:2:3 | +LL | struct Self; + | ^^^^^^^^^^^^ not accessible error[E0392]: parameter `'Self` is never used --> $DIR/self_type_keyword.rs:6:12 diff --git a/src/test/ui/self/ufcs-explicit-self.rs b/src/test/ui/self/ufcs-explicit-self.rs index 0aaaa7d47c3c1..d83af14d354fb 100644 --- a/src/test/ui/self/ufcs-explicit-self.rs +++ b/src/test/ui/self/ufcs-explicit-self.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] #![allow(dead_code)] #[derive(Copy, Clone)] @@ -37,13 +36,13 @@ impl Bar { } fn main() { - let foo: Box<_> = box Foo { + let foo: Box<_> = Box::new(Foo { f: 1, - }; + }); println!("{} {} {}", foo.foo(2), foo.bar(2), foo.baz(2)); - let bar: Box<_> = box Bar { + let bar: Box<_> = Box::new(Bar { f: 1, - }; + }); println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2)); let bar: Box> = bar; println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2)); diff --git a/src/test/ui/self/uniq-self-in-mut-slot.rs b/src/test/ui/self/uniq-self-in-mut-slot.rs index 695f06ecddafb..71e57d8c1fa1b 100644 --- a/src/test/ui/self/uniq-self-in-mut-slot.rs +++ b/src/test/ui/self/uniq-self-in-mut-slot.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] struct X { a: isize @@ -17,7 +16,7 @@ impl Changer for X { } pub fn main() { - let x: Box<_> = box X { a: 32 }; + let x: Box<_> = Box::new(X { a: 32 }); let new_x = x.change(); assert_eq!(new_x.a, 55); } diff --git a/src/test/ui/shadowed/shadowed-type-parameter.rs b/src/test/ui/shadowed/shadowed-type-parameter.rs index e74620f8900c0..66fd68a9f2362 100644 --- a/src/test/ui/shadowed/shadowed-type-parameter.rs +++ b/src/test/ui/shadowed/shadowed-type-parameter.rs @@ -1,9 +1,9 @@ // Test that shadowed lifetimes generate an error. -#![feature(box_syntax)] struct Foo(T); + impl Foo { fn shadow_in_method(&self) {} //~^ ERROR the name `T` is already used diff --git a/src/test/ui/simd/issue-89193.rs b/src/test/ui/simd/issue-89193.rs new file mode 100644 index 0000000000000..79c4e6a312c0d --- /dev/null +++ b/src/test/ui/simd/issue-89193.rs @@ -0,0 +1,51 @@ +// run-pass + +// Test that simd gather instructions on slice of usize don't cause crash +// See issue #89183 - https://github.com/rust-lang/rust/issues/89193 + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct x4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_gather(x: T, y: U, z: V) -> T; +} + +fn main() { + let x: [usize; 4] = [10, 11, 12, 13]; + let default = x4(0_usize, 1, 2, 3); + let mask = x4(1_i32, 1, 1, 1); + let expected = x4(10_usize, 11, 12, 13); + + unsafe { + let pointer = &x[0] as *const usize; + let pointers = x4( + pointer.offset(0) as *const usize, + pointer.offset(1), + pointer.offset(2), + pointer.offset(3) + ); + let result = simd_gather(default, pointers, mask); + assert_eq!(result, expected); + } + + // and again for isize + let x: [isize; 4] = [10, 11, 12, 13]; + let default = x4(0_isize, 1, 2, 3); + let expected = x4(10_isize, 11, 12, 13); + + unsafe { + let pointer = &x[0] as *const isize; + let pointers = x4( + pointer.offset(0) as *const isize, + pointer.offset(1), + pointer.offset(2), + pointer.offset(3) + ); + let result = simd_gather(default, pointers, mask); + assert_eq!(result, expected); + } +} diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr index 8fceef64c8cf2..e4ec9f875765a 100644 --- a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -56,7 +56,7 @@ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable LL | fn deref_mut_method1(x: Own) { | - help: consider changing this to be mutable: `mut x` LL | x.set(0, 0); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:121:5 @@ -64,7 +64,7 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference LL | fn deref_extend_mut_method1(x: &Own) -> &mut isize { | ----------- help: consider changing this to be a mutable reference: `&mut Own` LL | x.y_mut() - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:129:6 @@ -72,7 +72,7 @@ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable LL | fn assign_method1<'a>(x: Own) { | - help: consider changing this to be mutable: `mut x` LL | *x.y_mut() = 3; - | ^ cannot borrow as mutable + | ^^^^^^^^^ cannot borrow as mutable error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:133:6 @@ -80,7 +80,7 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference LL | fn assign_method2<'a>(x: &'a Own) { | -------------- help: consider changing this to be a mutable reference: `&'a mut Own` LL | *x.y_mut() = 3; - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 10 previous errors diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 0f630abd14876..b4693b7242ae4 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -24,7 +24,7 @@ error[E0596]: cannot borrow `f.f` as mutable, as it is behind a `&` reference LL | fn test4(f: &Test) { | ----- help: consider changing this to be a mutable reference: `&mut Test<'_>` LL | f.f.call_mut(()) - | ^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure --> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13 diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr index 6b5e0779e5fa5..1864f5de108cd 100644 --- a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr +++ b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr @@ -5,7 +5,7 @@ LL | fn b(x: &Foo) { | ---- help: consider changing this to be a mutable reference: `&mut Foo` LL | x.f(); LL | x.h(); - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-fn-in-const-b.stderr b/src/test/ui/span/borrowck-fn-in-const-b.stderr index 8949a10481a23..1f5d8bd32bb57 100644 --- a/src/test/ui/span/borrowck-fn-in-const-b.stderr +++ b/src/test/ui/span/borrowck-fn-in-const-b.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference LL | fn broken(x: &Vec) { | ------------ help: consider changing this to be a mutable reference: `&mut Vec` LL | x.push(format!("this is broken")); - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr index 7ba909d208aff..7c5caba6eae32 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.stderr @@ -32,7 +32,7 @@ LL | v4.push(&id('y')); | creates a temporary which is freed while still in use ... LL | v4.use_ref(); - | -- borrow later used here + | ------------ borrow later used here | = note: consider using a `let` binding to create a longer lived value diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr index fe6d05c588f7f..cc43f6d0928da 100644 --- a/src/test/ui/span/borrowck-object-mutability.stderr +++ b/src/test/ui/span/borrowck-object-mutability.stderr @@ -5,7 +5,7 @@ LL | fn borrowed_receiver(x: &dyn Foo) { | -------- help: consider changing this to be a mutable reference: `&mut dyn Foo` LL | x.borrowed(); LL | x.borrowed_mut(); - | ^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable --> $DIR/borrowck-object-mutability.rs:18:5 @@ -14,7 +14,7 @@ LL | fn owned_receiver(x: Box) { | - help: consider changing this to be mutable: `mut x` LL | x.borrowed(); LL | x.borrowed_mut(); - | ^ cannot borrow as mutable + | ^^^^^^^^^^^^^^^^ cannot borrow as mutable error: aborting due to 2 previous errors diff --git a/src/test/ui/span/coerce-suggestions.rs b/src/test/ui/span/coerce-suggestions.rs index c461f825d99a4..7920ae0b26cca 100644 --- a/src/test/ui/span/coerce-suggestions.rs +++ b/src/test/ui/span/coerce-suggestions.rs @@ -1,8 +1,8 @@ -#![feature(box_syntax)] - fn test(_x: &mut String) {} + fn test2(_x: &mut i32) {} + fn main() { let x: usize = String::new(); //~^ ERROR E0308 @@ -14,7 +14,7 @@ fn main() { test2(&y); //~^ ERROR E0308 let f; - f = box f; + f = Box::new(f); //~^ ERROR E0308 let s = &mut String::new(); diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index 2487684c1dd7f..74caae8645c1d 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -37,13 +37,10 @@ LL | test2(&y); error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:17:9 | -LL | f = box f; - | ^^^^^ cyclic type of infinite size - | -help: try using a conversion method - | -LL | f = (box f).to_string(); - | + +++++++++++++ +LL | f = Box::new(f); + | ^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | cyclic type of infinite size error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:21:9 diff --git a/src/test/ui/span/destructor-restrictions.stderr b/src/test/ui/span/destructor-restrictions.stderr index 8f75c388f6576..53c9404620f35 100644 --- a/src/test/ui/span/destructor-restrictions.stderr +++ b/src/test/ui/span/destructor-restrictions.stderr @@ -2,7 +2,7 @@ error[E0597]: `*a` does not live long enough --> $DIR/destructor-restrictions.rs:8:10 | LL | *a.borrow() + 1 - | ^--------- + | ^^^^^^^^^^ | | | borrowed value does not live long enough | a temporary with access to the borrow is created here ... diff --git a/src/test/ui/span/issue-11925.rs b/src/test/ui/span/issue-11925.rs index 0f6472b05f7aa..d9c08fbdd0f15 100644 --- a/src/test/ui/span/issue-11925.rs +++ b/src/test/ui/span/issue-11925.rs @@ -1,10 +1,10 @@ -#![feature(box_syntax, unboxed_closures)] +#![feature(unboxed_closures)] fn to_fn_once>(f: F) -> F { f } fn main() { let r = { - let x: Box<_> = box 42; + let x: Box<_> = Box::new(42); let f = to_fn_once(move|| &x); //~ ERROR cannot return reference to local data `x` f() }; diff --git a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr index 8d4709d660fa9..3c2022748f094 100644 --- a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr +++ b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr @@ -2,7 +2,7 @@ error[E0597]: `y` does not live long enough --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:10:5 | LL | y.borrow().clone() - | ^--------- + | ^^^^^^^^^^ | | | borrowed value does not live long enough | a temporary with access to the borrow is created here ... @@ -23,7 +23,7 @@ error[E0597]: `y` does not live long enough --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:17:9 | LL | y.borrow().clone() - | ^--------- + | ^^^^^^^^^^ | | | borrowed value does not live long enough | a temporary with access to the borrow is created here ... diff --git a/src/test/ui/span/issue-36537.stderr b/src/test/ui/span/issue-36537.stderr index 0939584380af9..79a0ebaeb8db6 100644 --- a/src/test/ui/span/issue-36537.stderr +++ b/src/test/ui/span/issue-36537.stderr @@ -7,7 +7,7 @@ LL | p = &a; LL | } | - `a` dropped here while still borrowed LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index c5a0448e798d1..92e86bf5d6c91 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -20,7 +20,22 @@ LL | let y = World::Hello + World::Goodbye; | | | World | - = note: an implementation of `std::ops::Add` might be missing for `World` +note: an implementation of `Add<_>` might be missing for `World` + --> $DIR/issue-39018.rs:15:1 + | +LL | enum World { + | ^^^^^^^^^^ must implement `Add<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Add { +LL | | /// The resulting type after applying the `+` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn add(self, rhs: Rhs) -> Self::Output; +LL | | } + | |_^ error[E0369]: cannot add `String` to `&str` --> $DIR/issue-39018.rs:11:22 diff --git a/src/test/ui/span/issue-40157.stderr b/src/test/ui/span/issue-40157.stderr index 0b365c3f7b6b3..57f80214a4f83 100644 --- a/src/test/ui/span/issue-40157.stderr +++ b/src/test/ui/span/issue-40157.stderr @@ -2,7 +2,7 @@ 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 diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr index 288c1042a26c7..783f5aca41746 100644 --- a/src/test/ui/span/issue-7575.stderr +++ b/src/test/ui/span/issue-7575.stderr @@ -27,16 +27,16 @@ LL | fn f9(_: usize) -> usize; candidate #3: `UnusedTrait` help: disambiguate the associated function for candidate #1 | -LL | u.f8(42) + CtxtFn::f9(u, 342) + m.fff(42) - | ~~~~~~~~~~~~~~~~~~ +LL | u.f8(42) + ::f9(u, 342) + m.fff(42) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ help: disambiguate the associated function for candidate #2 | -LL | u.f8(42) + OtherTrait::f9(u, 342) + m.fff(42) - | ~~~~~~~~~~~~~~~~~~~~~~ +LL | u.f8(42) + ::f9(u, 342) + m.fff(42) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ help: disambiguate the associated function for candidate #3 | -LL | u.f8(42) + UnusedTrait::f9(u, 342) + m.fff(42) - | ~~~~~~~~~~~~~~~~~~~~~~~ +LL | u.f8(42) + ::f9(u, 342) + m.fff(42) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0599]: no method named `fff` found for struct `Myisize` in the current scope --> $DIR/issue-7575.rs:62:30 @@ -72,7 +72,7 @@ LL | fn is_str() -> bool { = help: items from traits can only be used if the type parameter is bounded by the trait help: disambiguate the associated function for the candidate | -LL | ManyImplTrait::is_str(t) +LL | ::is_str(t) | error: aborting due to 3 previous errors diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr index e04e4cbdabbf6..8a7c504f0053b 100644 --- a/src/test/ui/span/mut-arg-hint.stderr +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference LL | fn foo(mut a: &String) { | ------- help: consider changing this to be a mutable reference: `&mut String` LL | a.push_str("bar"); - | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:8:5 @@ -12,7 +12,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference LL | pub fn foo<'a>(mut a: &'a String) { | ---------- help: consider changing this to be a mutable reference: `&'a mut String` LL | a.push_str("foo"); - | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:15:9 @@ -20,7 +20,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference LL | pub fn foo(mut a: &String) { | ------- help: consider changing this to be a mutable reference: `&mut String` LL | a.push_str("foo"); - | ^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | ^^^^^^^^^^^^^^^^^ `a` is a `&` reference, so the data it refers to cannot be borrowed as mutable error: aborting due to 3 previous errors diff --git a/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr b/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr index 21b29464df502..4d976a7bbfa47 100644 --- a/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr +++ b/src/test/ui/span/mut-ptr-cant-outlive-ref.stderr @@ -7,7 +7,7 @@ LL | } | - `b` dropped here while still borrowed LL | LL | p.use_ref(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr b/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr index 8e9cd59515443..0b985de609c26 100644 --- a/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr +++ b/src/test/ui/span/regionck-unboxed-closure-lifetimes.stderr @@ -7,7 +7,7 @@ LL | let c_ref = &c; LL | } | - `c` dropped here while still borrowed LL | f.use_mut(); - | - borrow later used here + | ----------- borrow later used here error: aborting due to previous error diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs index e34f84683bbc7..16b4cc2586273 100644 --- a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - fn id(x: T) -> T { x } trait Foo { } @@ -7,10 +5,12 @@ trait Foo { } impl<'a> Foo for &'a isize { } fn main() { + let blah; + { let ss: &isize = &id(1); //~^ ERROR temporary value dropped while borrowed - blah = box ss as Box; + blah = Box::new(ss) as Box; } } diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.rs b/src/test/ui/span/regions-close-over-type-parameter-2.rs index 29083154b8991..aca3972cb6c55 100644 --- a/src/test/ui/span/regions-close-over-type-parameter-2.rs +++ b/src/test/ui/span/regions-close-over-type-parameter-2.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - // Test for what happens when a type parameter `A` is closed over into // an object. This should yield errors unless `A` (and the object) // both have suitable bounds. @@ -7,14 +5,16 @@ trait Foo { fn get(&self); } impl Foo for A { - fn get(&self) { } + fn get(&self) { + } } fn repeater3<'a,A:'a>(v: A) -> Box { - box v as Box + Box::new(v) as Box } fn main() { + // Error results because the type of is inferred to be // ~Repeat<&'blk isize> where blk is the lifetime of the block below. diff --git a/src/test/ui/span/regions-escape-loop-via-vec.stderr b/src/test/ui/span/regions-escape-loop-via-vec.stderr index b47250db723fe..2b649307739f5 100644 --- a/src/test/ui/span/regions-escape-loop-via-vec.stderr +++ b/src/test/ui/span/regions-escape-loop-via-vec.stderr @@ -7,7 +7,7 @@ LL | while x < 10 { | ^ use of borrowed `x` LL | let mut z = x; LL | _y.push(&mut z); - | -- borrow later used here + | --------------- borrow later used here error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/regions-escape-loop-via-vec.rs:6:21 @@ -18,14 +18,15 @@ LL | while x < 10 { LL | let mut z = x; | ^ use of borrowed `x` LL | _y.push(&mut z); - | -- borrow later used here + | --------------- borrow later used here error[E0597]: `z` does not live long enough --> $DIR/regions-escape-loop-via-vec.rs:7:17 | LL | _y.push(&mut z); - | -- ^^^^^^ borrowed value does not live long enough - | | + | --------^^^^^^- + | | | + | | borrowed value does not live long enough | borrow later used here ... LL | } @@ -38,7 +39,7 @@ LL | let mut _y = vec![&mut x]; | ------ borrow of `x` occurs here ... LL | _y.push(&mut z); - | -- borrow later used here + | --------------- borrow later used here LL | LL | x += 1; | ^^^^^^ use of borrowed `x` diff --git a/src/test/ui/span/send-is-not-static-std-sync.stderr b/src/test/ui/span/send-is-not-static-std-sync.stderr index 81de8c29906f7..5d493a3e4ee55 100644 --- a/src/test/ui/span/send-is-not-static-std-sync.stderr +++ b/src/test/ui/span/send-is-not-static-std-sync.stderr @@ -7,7 +7,7 @@ LL | drop(y); | ^ move out of `y` occurs here ... LL | *lock.lock().unwrap() = &z; - | ---- borrow later used here + | ----------- borrow later used here error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:16:33 @@ -18,7 +18,7 @@ LL | } | - `z` dropped here while still borrowed LL | LL | lock.use_ref(); // (Mutex is #[may_dangle] so its dtor does not use `z` => needs explicit use) - | ---- borrow later used here + | -------------- borrow later used here error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/send-is-not-static-std-sync.rs:27:10 @@ -29,7 +29,7 @@ LL | drop(y); | ^ move out of `y` occurs here ... LL | *lock.write().unwrap() = &z; - | ---- borrow later used here + | ------------ borrow later used here error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:30:34 @@ -40,7 +40,7 @@ LL | } | - `z` dropped here while still borrowed LL | LL | lock.use_ref(); // (RwLock is #[may_dangle] so its dtor does not use `z` => needs explicit use) - | ---- borrow later used here + | -------------- borrow later used here error[E0505]: cannot move out of `y` because it is borrowed --> $DIR/send-is-not-static-std-sync.rs:43:10 @@ -51,7 +51,7 @@ LL | drop(y); | ^ move out of `y` occurs here ... LL | tx.send(&z).unwrap(); - | -- borrow later used here + | ----------- borrow later used here error[E0597]: `z` does not live long enough --> $DIR/send-is-not-static-std-sync.rs:46:17 diff --git a/src/test/ui/span/slice-borrow.stderr b/src/test/ui/span/slice-borrow.stderr index 62a4a6009d433..27df25be3fa03 100644 --- a/src/test/ui/span/slice-borrow.stderr +++ b/src/test/ui/span/slice-borrow.stderr @@ -7,7 +7,7 @@ LL | let x: &[isize] = &vec![1, 2, 3, 4, 5]; LL | } | - temporary value is freed at the end of this statement LL | y.use_ref(); - | - borrow later used here + | ----------- borrow later used here | = note: consider using a `let` binding to create a longer lived value = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/specialization/README-rpass.md b/src/test/ui/specialization/README-rpass.md index 1373a2cf81b3a..c1486ce1ee821 100644 --- a/src/test/ui/specialization/README-rpass.md +++ b/src/test/ui/specialization/README-rpass.md @@ -8,7 +8,7 @@ Tests that specialization is working correctly: - Specialization via concrete types vs unknown types - In top level of the trait reference - Embedded within another type (`Vec` vs `Vec`) - - [Specialization based on super trait relationships](specialization-super-traits.rs) + - [Specialization based on super trait relationships](specialization-supertraits.rs) - [On assoc fns](specialization-assoc-fns.rs) - [Ensure that impl order doesn't matter](specialization-out-of-order.rs) diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 16ffc661fe0a3..ce981bc00982a 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -22,6 +22,14 @@ LL | println!("{}", MyStruct.foo_one()); | = note: the following trait bounds were not satisfied: `MyStruct: Foo` +note: the following trait must be implemented + --> $DIR/specialization-trait-not-implemented.rs:7:1 + | +LL | / trait Foo { +LL | | fn foo_one(&self) -> &'static str; +LL | | fn foo_two(&self) -> &'static str; +LL | | } + | |_^ = help: items from traits can only be used if the trait is implemented and in scope note: `Foo` defines an item `foo_one`, perhaps you need to implement it --> $DIR/specialization-trait-not-implemented.rs:7:1 diff --git a/src/test/ui/specialization/min_specialization/spec-marker-supertraits.rs b/src/test/ui/specialization/min_specialization/spec-marker-supertraits.rs new file mode 100644 index 0000000000000..3bb2480e9e2be --- /dev/null +++ b/src/test/ui/specialization/min_specialization/spec-marker-supertraits.rs @@ -0,0 +1,29 @@ +// Check that supertraits cannot be used to work around min_specialization +// limitations. + +#![feature(min_specialization)] +#![feature(rustc_attrs)] + +trait HasMethod { + fn method(&self); +} + +#[rustc_unsafe_specialization_marker] +trait Marker: HasMethod {} + +trait Spec { + fn spec_me(&self); +} + +impl Spec for T { + default fn spec_me(&self) {} +} + +impl Spec for T { + //~^ ERROR cannot specialize on trait `HasMethod` + fn spec_me(&self) { + self.method(); + } +} + +fn main() {} diff --git a/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr b/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr new file mode 100644 index 0000000000000..964109dd10f47 --- /dev/null +++ b/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr @@ -0,0 +1,13 @@ +error: cannot specialize on trait `HasMethod` + --> $DIR/spec-marker-supertraits.rs:22:1 + | +LL | / impl Spec for T { +LL | | +LL | | fn spec_me(&self) { +LL | | self.method(); +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/specialization/specialization-super-traits.rs b/src/test/ui/specialization/specialization-supertraits.rs similarity index 100% rename from src/test/ui/specialization/specialization-super-traits.rs rename to src/test/ui/specialization/specialization-supertraits.rs diff --git a/src/test/ui/specialization/specialization-super-traits.stderr b/src/test/ui/specialization/specialization-supertraits.stderr similarity index 90% rename from src/test/ui/specialization/specialization-super-traits.stderr rename to src/test/ui/specialization/specialization-supertraits.stderr index 165703d636574..d32e47a24c2c8 100644 --- a/src/test/ui/specialization/specialization-super-traits.stderr +++ b/src/test/ui/specialization/specialization-supertraits.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/specialization-super-traits.rs:3:12 + --> $DIR/specialization-supertraits.rs:3:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/static/static-region-bound.rs b/src/test/ui/static/static-region-bound.rs index f133133b33650..d70706e5764f6 100644 --- a/src/test/ui/static/static-region-bound.rs +++ b/src/test/ui/static/static-region-bound.rs @@ -1,12 +1,12 @@ -#![feature(box_syntax)] - fn id(x: T) -> T { x } fn f(_: T) {} fn main() { - let x: Box<_> = box 3; + + let x: Box<_> = Box::new(3); f(x); + let x = &id(3); //~ ERROR temporary value dropped while borrowed f(x); } diff --git a/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs b/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs index bf1ba8a643fea..f870096fdd44a 100644 --- a/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs +++ b/src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs @@ -1,8 +1,6 @@ // run-pass // aux-build:cci_class_cast.rs -#![feature(box_syntax)] - extern crate cci_class_cast; use std::string::ToString; @@ -15,6 +13,6 @@ fn print_out(thing: Box, expected: String) { } pub fn main() { - let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; + let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; print_out(nyan, "nyan".to_string()); } diff --git a/src/test/ui/structs-enums/class-separate-impl.rs b/src/test/ui/structs-enums/class-separate-impl.rs index 947690b51f422..3d6da1cc28024 100644 --- a/src/test/ui/structs-enums/class-separate-impl.rs +++ b/src/test/ui/structs-enums/class-separate-impl.rs @@ -2,8 +2,6 @@ #![allow(dead_code)] #![allow(non_camel_case_types)] -#![feature(box_syntax)] - use std::fmt; struct cat { @@ -60,6 +58,6 @@ fn print_out(thing: Box, expected: String) { } pub fn main() { - let nyan: Box = box cat(0, 2, "nyan".to_string()) as Box; + let nyan: Box = Box::new(cat(0, 2, "nyan".to_string())) as Box; print_out(nyan, "nyan".to_string()); } diff --git a/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs b/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs index 77419e1132dc9..53892a4e0aeb4 100644 --- a/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs +++ b/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] /*! * This is a regression test for a bug in LLVM, fixed in upstream r179587, @@ -9,7 +8,7 @@ enum List { Nil, Cons(X, Box>) } pub fn main() { - match List::Cons(10, box List::Nil) { + match List::Cons(10, Box::new(List::Nil)) { List::Cons(10, _) => {} List::Nil => {} _ => panic!() diff --git a/src/test/ui/suggestions/core-std-import-order-issue-83564.rs b/src/test/ui/suggestions/core-std-import-order-issue-83564.rs new file mode 100644 index 0000000000000..b7fe5af7bf8a1 --- /dev/null +++ b/src/test/ui/suggestions/core-std-import-order-issue-83564.rs @@ -0,0 +1,10 @@ +// edition:2018 + +// This is a regression test for #83564. +// For some reason, Rust 2018 or higher is required to reproduce the bug. + +fn main() { + //~^ HELP consider importing one of these items + let _x = NonZeroU32::new(5).unwrap(); + //~^ ERROR failed to resolve: use of undeclared type `NonZeroU32` +} diff --git a/src/test/ui/suggestions/core-std-import-order-issue-83564.stderr b/src/test/ui/suggestions/core-std-import-order-issue-83564.stderr new file mode 100644 index 0000000000000..d484fb8cbe0d8 --- /dev/null +++ b/src/test/ui/suggestions/core-std-import-order-issue-83564.stderr @@ -0,0 +1,16 @@ +error[E0433]: failed to resolve: use of undeclared type `NonZeroU32` + --> $DIR/core-std-import-order-issue-83564.rs:8:14 + | +LL | let _x = NonZeroU32::new(5).unwrap(); + | ^^^^^^^^^^ not found in this scope + | +help: consider importing one of these items + | +LL | use std::num::NonZeroU32; + | +LL | use core::num::NonZeroU32; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/ui/suggestions/derive-trait-for-method-call.stderr b/src/test/ui/suggestions/derive-trait-for-method-call.stderr index 97fc1134a9477..2af3ba1d5bb9c 100644 --- a/src/test/ui/suggestions/derive-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/derive-trait-for-method-call.stderr @@ -20,6 +20,17 @@ LL | let y = x.test(); `Enum: Clone` `Enum: Default` `CloneEnum: Default` +note: the following trait must be implemented + --> $SRC_DIR/core/src/default.rs:LL:COL + | +LL | / pub trait Default: Sized { +LL | | /// Returns the "default value" for a type. +LL | | /// +LL | | /// Default values are often some kind of initial value, identity value, or anything else that +... | +LL | | fn default() -> Self; +LL | | } + | |_^ help: consider annotating `Enum` with `#[derive(Clone)]` | LL | #[derive(Clone)] diff --git a/src/test/ui/suggestions/ignore-nested-field-binding.fixed b/src/test/ui/suggestions/ignore-nested-field-binding.fixed new file mode 100644 index 0000000000000..1dc44838e8bb0 --- /dev/null +++ b/src/test/ui/suggestions/ignore-nested-field-binding.fixed @@ -0,0 +1,20 @@ +// Regression test for #88403, where prefixing with an underscore was +// erroneously suggested for a nested shorthand struct field binding. + +// run-rustfix +#![allow(unused)] +#![forbid(unused_variables)] + +struct Inner { i: i32 } +struct Outer { o: Inner } + +fn foo(Outer { o: Inner { i: _ } }: Outer) {} +//~^ ERROR: unused variable: `i` +//~| HELP: try ignoring the field + +fn main() { + let s = Outer { o: Inner { i: 42 } }; + let Outer { o: Inner { i: _ } } = s; + //~^ ERROR: unused variable: `i` + //~| HELP: try ignoring the field +} diff --git a/src/test/ui/suggestions/ignore-nested-field-binding.rs b/src/test/ui/suggestions/ignore-nested-field-binding.rs new file mode 100644 index 0000000000000..6dc0263ec9f2b --- /dev/null +++ b/src/test/ui/suggestions/ignore-nested-field-binding.rs @@ -0,0 +1,20 @@ +// Regression test for #88403, where prefixing with an underscore was +// erroneously suggested for a nested shorthand struct field binding. + +// run-rustfix +#![allow(unused)] +#![forbid(unused_variables)] + +struct Inner { i: i32 } +struct Outer { o: Inner } + +fn foo(Outer { o: Inner { i } }: Outer) {} +//~^ ERROR: unused variable: `i` +//~| HELP: try ignoring the field + +fn main() { + let s = Outer { o: Inner { i: 42 } }; + let Outer { o: Inner { i } } = s; + //~^ ERROR: unused variable: `i` + //~| HELP: try ignoring the field +} diff --git a/src/test/ui/suggestions/ignore-nested-field-binding.stderr b/src/test/ui/suggestions/ignore-nested-field-binding.stderr new file mode 100644 index 0000000000000..b2936a22a22f1 --- /dev/null +++ b/src/test/ui/suggestions/ignore-nested-field-binding.stderr @@ -0,0 +1,20 @@ +error: unused variable: `i` + --> $DIR/ignore-nested-field-binding.rs:11:27 + | +LL | fn foo(Outer { o: Inner { i } }: Outer) {} + | ^ help: try ignoring the field: `i: _` + | +note: the lint level is defined here + --> $DIR/ignore-nested-field-binding.rs:6:11 + | +LL | #![forbid(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: unused variable: `i` + --> $DIR/ignore-nested-field-binding.rs:17:28 + | +LL | let Outer { o: Inner { i } } = s; + | ^ help: try ignoring the field: `i: _` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr index 71779ecb7299f..001af27b2484e 100644 --- a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr +++ b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr @@ -22,10 +22,8 @@ error[E0277]: the trait bound `S: Trait` is not satisfied --> $DIR/imm-ref-trait-object-literal.rs:13:7 | LL | foo(s); - | --- ^ - | | | - | | expected an implementor of trait `Trait` - | | help: consider mutably borrowing here: `&mut s` + | --- ^ expected an implementor of trait `Trait` + | | | required by a bound introduced by this call | note: required by a bound in `foo` @@ -33,6 +31,10 @@ note: required by a bound in `foo` | LL | fn foo(_: X) {} | ^^^^^ required by this bound in `foo` +help: consider mutably borrowing here + | +LL | foo(&mut s); + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr index 043a771129a61..80d3c940eb7c6 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.nll.stderr @@ -4,7 +4,7 @@ error[E0597]: `val` does not live long enough LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> { | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a` LL | val.use_self() - | ^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^ borrowed value does not live long enough LL | } | - `val` dropped here while still borrowed | @@ -13,23 +13,17 @@ help: you can add a bound to the opaque type to make it last less than `'static` LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> + 'a { | ++++ -error[E0515]: cannot return value referencing function parameter `val` +error[E0515]: cannot return reference to function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9 | LL | val.use_self() - | ---^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `val` is borrowed here + | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function -error[E0515]: cannot return value referencing function parameter `val` +error[E0515]: cannot return reference to function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9 | LL | val.use_self() - | ---^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `val` is borrowed here + | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr index 29991b6572fb4..e8c3a7908f521 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -4,7 +4,7 @@ error[E0597]: `val` does not live long enough LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> { | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a` LL | val.use_self() - | ^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^ borrowed value does not live long enough LL | } | - `val` dropped here while still borrowed | @@ -13,23 +13,17 @@ help: you can add a bound to the opaque type to make it last less than `'static` LL | fn use_it<'a>(val: Box>) -> impl OtherTrait<'a> + 'a { | ++++ -error[E0515]: cannot return value referencing function parameter `val` +error[E0515]: cannot return reference to function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9 | LL | val.use_self() - | ---^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `val` is borrowed here + | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function -error[E0515]: cannot return value referencing function parameter `val` +error[E0515]: cannot return reference to function parameter `val` --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9 | LL | val.use_self() - | ---^^^^^^^^^^^ - | | - | returns a value referencing data owned by the current function - | `val` is borrowed here + | ^^^^^^^^^^^^^^ returns a reference to data owned by the current function error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:13 diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr index 6c235ae8f0277..a1ef32c5445b5 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr @@ -2,41 +2,53 @@ error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9 | LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | val.use_self::() - | ^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | val.use_self() - | ^^^^^^^^^^^^^^ `val` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | val.use_self() - | ^^^^^^^^^^^^^^ `val` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9 | LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { - | --- `val` is a reference that is only valid in the function body + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here LL | MyTrait::use_self(val) - | ^^^^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here - | - = help: consider replacing `'a` with `'static` + | ^^^^^^^^^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/invalid-bin-op.stderr b/src/test/ui/suggestions/invalid-bin-op.stderr index 7668eddf6070a..d18c24e53d030 100644 --- a/src/test/ui/suggestions/invalid-bin-op.stderr +++ b/src/test/ui/suggestions/invalid-bin-op.stderr @@ -6,7 +6,16 @@ LL | let _ = s == t; | | | S | +note: an implementation of `PartialEq<_>` might be missing for `S` + --> $DIR/invalid-bin-op.rs:5:1 + | +LL | struct S(T); + | ^^^^^^^^^^^^^^^ must implement `PartialEq<_>` = note: the trait `std::cmp::PartialEq` is not implemented for `S` +help: consider annotating `S` with `#[derive(PartialEq)]` + | +LL | #[derive(PartialEq)] + | error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-62843.stderr b/src/test/ui/suggestions/issue-62843.stderr index 93251b2c8dbfc..29ba39cbe109c 100644 --- a/src/test/ui/suggestions/issue-62843.stderr +++ b/src/test/ui/suggestions/issue-62843.stderr @@ -2,14 +2,16 @@ error[E0277]: expected a `FnMut<(char,)>` closure, found `String` --> $DIR/issue-62843.rs:4:32 | LL | println!("{:?}", line.find(pattern)); - | ---- ^^^^^^^ - | | | - | | expected an implementor of trait `Pattern<'_>` - | | help: consider borrowing here: `&pattern` + | ---- ^^^^^^^ expected an implementor of trait `Pattern<'_>` + | | | required by a bound introduced by this call | = note: the trait bound `String: Pattern<'_>` is not satisfied = note: required because of the requirements on the impl of `Pattern<'_>` for `String` +help: consider borrowing here + | +LL | println!("{:?}", line.find(&pattern)); + | + error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-72766.rs b/src/test/ui/suggestions/issue-72766.rs index 0448f0719589d..c54be7f5dff0d 100644 --- a/src/test/ui/suggestions/issue-72766.rs +++ b/src/test/ui/suggestions/issue-72766.rs @@ -1,5 +1,5 @@ // edition:2018 -// compile-flags: -Cincremental=tmp/issue-72766 +// incremental pub struct SadGirl; diff --git a/src/test/ui/suggestions/issue-84973-2.stderr b/src/test/ui/suggestions/issue-84973-2.stderr index c1a7a2e101d62..2c54ea6724505 100644 --- a/src/test/ui/suggestions/issue-84973-2.stderr +++ b/src/test/ui/suggestions/issue-84973-2.stderr @@ -2,10 +2,8 @@ error[E0277]: the trait bound `i32: Tr` is not satisfied --> $DIR/issue-84973-2.rs:11:9 | LL | foo(a); - | --- ^ - | | | - | | expected an implementor of trait `Tr` - | | help: consider mutably borrowing here: `&mut a` + | --- ^ expected an implementor of trait `Tr` + | | | required by a bound introduced by this call | note: required by a bound in `foo` @@ -13,6 +11,10 @@ note: required by a bound in `foo` | LL | fn foo(i: T) {} | ^^ required by this bound in `foo` +help: consider mutably borrowing here + | +LL | foo(&mut a); + | ++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-84973-negative.stderr b/src/test/ui/suggestions/issue-84973-negative.stderr index 14b32d8515cd7..1f33374eb29db 100644 --- a/src/test/ui/suggestions/issue-84973-negative.stderr +++ b/src/test/ui/suggestions/issue-84973-negative.stderr @@ -16,10 +16,8 @@ error[E0277]: the trait bound `f32: Tr` is not satisfied --> $DIR/issue-84973-negative.rs:11:9 | LL | bar(b); - | --- ^ - | | | - | | expected an implementor of trait `Tr` - | | help: consider borrowing here: `&b` + | --- ^ expected an implementor of trait `Tr` + | | | required by a bound introduced by this call | note: required by a bound in `bar` @@ -27,6 +25,10 @@ note: required by a bound in `bar` | LL | fn bar(t: T) {} | ^^ required by this bound in `bar` +help: consider borrowing here + | +LL | bar(&b); + | + error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-84973.stderr b/src/test/ui/suggestions/issue-84973.stderr index 169d0cccb43ef..16a28c73aa724 100644 --- a/src/test/ui/suggestions/issue-84973.stderr +++ b/src/test/ui/suggestions/issue-84973.stderr @@ -2,10 +2,8 @@ error[E0277]: the trait bound `Fancy: SomeTrait` is not satisfied --> $DIR/issue-84973.rs:6:24 | LL | let o = Other::new(f); - | ---------- ^ - | | | - | | expected an implementor of trait `SomeTrait` - | | help: consider borrowing here: `&f` + | ---------- ^ expected an implementor of trait `SomeTrait` + | | | required by a bound introduced by this call | note: required by `Other::<'a, G>::new` @@ -13,6 +11,10 @@ note: required by `Other::<'a, G>::new` | LL | pub fn new(g: G) -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | let o = Other::new(&f); + | + error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-88730.rs b/src/test/ui/suggestions/issue-88730.rs new file mode 100644 index 0000000000000..e63210a3e987e --- /dev/null +++ b/src/test/ui/suggestions/issue-88730.rs @@ -0,0 +1,16 @@ +#![allow(unused, nonstandard_style)] +#![deny(bindings_with_variant_name)] + +// If an enum has two different variants, +// then it cannot be matched upon in a function argument. +// It still gets a warning, but no suggestions. +enum Foo { + C, + D, +} + +fn foo(C: Foo) {} //~ERROR + +fn main() { + let C = Foo::D; //~ERROR +} diff --git a/src/test/ui/suggestions/issue-88730.stderr b/src/test/ui/suggestions/issue-88730.stderr new file mode 100644 index 0000000000000..eb22b0ea5c83d --- /dev/null +++ b/src/test/ui/suggestions/issue-88730.stderr @@ -0,0 +1,21 @@ +error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-88730.rs:12:8 + | +LL | fn foo(C: Foo) {} + | ^ + | +note: the lint level is defined here + --> $DIR/issue-88730.rs:2:9 + | +LL | #![deny(bindings_with_variant_name)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0170]: pattern binding `C` is named the same as one of the variants of the type `Foo` + --> $DIR/issue-88730.rs:15:9 + | +LL | let C = Foo::D; + | ^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0170`. diff --git a/src/test/ui/suggestions/issue-89333.rs b/src/test/ui/suggestions/issue-89333.rs new file mode 100644 index 0000000000000..03ed28ede21d8 --- /dev/null +++ b/src/test/ui/suggestions/issue-89333.rs @@ -0,0 +1,11 @@ +// check-fail +// Ensure we don't error when emitting trait bound not satisfied when self type +// has late bound var + +fn main() { + test(&|| 0); //~ ERROR the trait bound +} + +trait Trait {} + +fn test(arg: &impl Fn() -> T) where for<'a> &'a T: Trait {} diff --git a/src/test/ui/suggestions/issue-89333.stderr b/src/test/ui/suggestions/issue-89333.stderr new file mode 100644 index 0000000000000..f73f1147d5d9c --- /dev/null +++ b/src/test/ui/suggestions/issue-89333.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `for<'a> &'a _: Trait` is not satisfied + --> $DIR/issue-89333.rs:6:5 + | +LL | test(&|| 0); + | ^^^^ the trait `for<'a> Trait` is not implemented for `&'a _` + | +note: required by a bound in `test` + --> $DIR/issue-89333.rs:11:55 + | +LL | fn test(arg: &impl Fn() -> T) where for<'a> &'a T: Trait {} + | ^^^^^ required by this bound in `test` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr index b27980300325b..b579635ca7c08 100644 --- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.nll.stderr @@ -32,8 +32,6 @@ LL | | current: None, LL | | remaining: self.0.iter(), LL | | } | |_________^ returning this value requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: lifetime may not live long enough --> $DIR/trait-object-nested-in-impl-trait.rs:60:30 @@ -43,7 +41,6 @@ LL | fn iter<'a>(&'a self) -> impl Iterator> { | | | lifetime `'a` defined here | - = help: consider replacing `'a` with `'static` help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound | LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { diff --git a/src/test/ui/suggestions/missing-type-param-used-in-param.fixed b/src/test/ui/suggestions/missing-type-param-used-in-param.fixed new file mode 100644 index 0000000000000..cc4120041b986 --- /dev/null +++ b/src/test/ui/suggestions/missing-type-param-used-in-param.fixed @@ -0,0 +1,8 @@ +// run-rustfix + +fn two_type_params(_: B) {} + +fn main() { + two_type_params::(100); //~ ERROR this function takes 2 generic arguments + two_type_params::(100); +} diff --git a/src/test/ui/suggestions/missing-type-param-used-in-param.rs b/src/test/ui/suggestions/missing-type-param-used-in-param.rs new file mode 100644 index 0000000000000..19286331b6023 --- /dev/null +++ b/src/test/ui/suggestions/missing-type-param-used-in-param.rs @@ -0,0 +1,8 @@ +// run-rustfix + +fn two_type_params(_: B) {} + +fn main() { + two_type_params::(100); //~ ERROR this function takes 2 generic arguments + two_type_params::(100); +} diff --git a/src/test/ui/suggestions/missing-type-param-used-in-param.stderr b/src/test/ui/suggestions/missing-type-param-used-in-param.stderr new file mode 100644 index 0000000000000..4f7058a649259 --- /dev/null +++ b/src/test/ui/suggestions/missing-type-param-used-in-param.stderr @@ -0,0 +1,21 @@ +error[E0107]: this function takes 2 generic arguments but 1 generic argument was supplied + --> $DIR/missing-type-param-used-in-param.rs:6:5 + | +LL | two_type_params::(100); + | ^^^^^^^^^^^^^^^ ------ supplied 1 generic argument + | | + | expected 2 generic arguments + | +note: function defined here, with 2 generic parameters: `A`, `B` + --> $DIR/missing-type-param-used-in-param.rs:3:4 + | +LL | fn two_type_params(_: B) {} + | ^^^^^^^^^^^^^^^ - - +help: add missing generic argument + | +LL | two_type_params::(100); + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/suggestions/negative-literal-index.fixed b/src/test/ui/suggestions/negative-literal-index.fixed new file mode 100644 index 0000000000000..e52714cf97fe6 --- /dev/null +++ b/src/test/ui/suggestions/negative-literal-index.fixed @@ -0,0 +1,22 @@ +// run-rustfix + +use std::ops::Index; +struct X; +impl Index for X { + type Output = (); + + fn index(&self, _: i32) -> &() { + &() + } +} + +fn main() { + let x = vec![1, 2, 3]; + x[x.len() -1]; //~ ERROR negative integers cannot be used to index on a + let x = [1, 2, 3]; + x[x.len() -1]; //~ ERROR negative integers cannot be used to index on a + let x = &[1, 2, 3]; + x[x.len() -1]; //~ ERROR negative integers cannot be used to index on a + let _ = x; + X[-1]; +} diff --git a/src/test/ui/suggestions/negative-literal-index.rs b/src/test/ui/suggestions/negative-literal-index.rs new file mode 100644 index 0000000000000..d88b66e679e56 --- /dev/null +++ b/src/test/ui/suggestions/negative-literal-index.rs @@ -0,0 +1,22 @@ +// run-rustfix + +use std::ops::Index; +struct X; +impl Index for X { + type Output = (); + + fn index(&self, _: i32) -> &() { + &() + } +} + +fn main() { + let x = vec![1, 2, 3]; + x[-1]; //~ ERROR negative integers cannot be used to index on a + let x = [1, 2, 3]; + x[-1]; //~ ERROR negative integers cannot be used to index on a + let x = &[1, 2, 3]; + x[-1]; //~ ERROR negative integers cannot be used to index on a + let _ = x; + X[-1]; +} diff --git a/src/test/ui/suggestions/negative-literal-index.stderr b/src/test/ui/suggestions/negative-literal-index.stderr new file mode 100644 index 0000000000000..2b51bf7b7ce87 --- /dev/null +++ b/src/test/ui/suggestions/negative-literal-index.stderr @@ -0,0 +1,35 @@ +error: negative integers cannot be used to index on a `Vec<{integer}>` + --> $DIR/negative-literal-index.rs:15:7 + | +LL | x[-1]; + | ^^ cannot use a negative integer for indexing on `Vec<{integer}>` + | +help: to access an element starting from the end of the `Vec<{integer}>`, compute the index + | +LL | x[x.len() -1]; + | +++++++ + +error: negative integers cannot be used to index on a `[{integer}; 3]` + --> $DIR/negative-literal-index.rs:17:7 + | +LL | x[-1]; + | ^^ cannot use a negative integer for indexing on `[{integer}; 3]` + | +help: to access an element starting from the end of the `[{integer}; 3]`, compute the index + | +LL | x[x.len() -1]; + | +++++++ + +error: negative integers cannot be used to index on a `[{integer}; 3]` + --> $DIR/negative-literal-index.rs:19:7 + | +LL | x[-1]; + | ^^ cannot use a negative integer for indexing on `[{integer}; 3]` + | +help: to access an element starting from the end of the `[{integer}; 3]`, compute the index + | +LL | x[x.len() -1]; + | +++++++ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/suggestions/slice-issue-87994.stderr b/src/test/ui/suggestions/slice-issue-87994.stderr index 018f62e783daf..0275fd475d8c6 100644 --- a/src/test/ui/suggestions/slice-issue-87994.stderr +++ b/src/test/ui/suggestions/slice-issue-87994.stderr @@ -2,10 +2,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation --> $DIR/slice-issue-87994.rs:3:12 | LL | for _ in v[1..] { - | ^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider borrowing here: `&v[1..]` + | ^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `[i32]: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `[i32]` @@ -14,15 +11,18 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for _ in &v[1..] { + | + +LL | for _ in &mut v[1..] { + | ++++ error[E0277]: `[i32]` is not an iterator --> $DIR/slice-issue-87994.rs:3:12 | LL | for _ in v[1..] { - | ^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider borrowing here: `&v[1..]` + | ^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `[i32]: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `[i32]` @@ -31,15 +31,18 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for _ in &v[1..] { + | + +LL | for _ in &mut v[1..] { + | ++++ error[E0277]: the size for values of type `[K]` cannot be known at compilation time --> $DIR/slice-issue-87994.rs:11:13 | LL | for i2 in v2[1..] { - | ^^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider borrowing here: `&v2[1..]` + | ^^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `[K]: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `[K]` @@ -48,15 +51,18 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for i2 in &v2[1..] { + | + +LL | for i2 in &mut v2[1..] { + | ++++ error[E0277]: `[K]` is not an iterator --> $DIR/slice-issue-87994.rs:11:13 | LL | for i2 in v2[1..] { - | ^^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider borrowing here: `&v2[1..]` + | ^^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `[K]: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `[K]` @@ -65,6 +71,12 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for i2 in &v2[1..] { + | + +LL | for i2 in &mut v2[1..] { + | ++++ error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs new file mode 100644 index 0000000000000..a62669d5b2d8f --- /dev/null +++ b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs @@ -0,0 +1,23 @@ +trait Trait {} + +struct A; +struct B; +struct C; + +impl Trait for &A {} +impl Trait for &mut A {} + +impl Trait for &B {} + +impl Trait for &mut C {} + +fn foo(_: X) {} + +fn main() { + let a = A; + let b = B; + let c = C; + foo(a); //~ ERROR the trait bound `A: Trait` is not satisfied + foo(b); //~ ERROR the trait bound `B: Trait` is not satisfied + foo(c); //~ ERROR the trait bound `C: Trait` is not satisfied +} diff --git a/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr new file mode 100644 index 0000000000000..6583cabe18489 --- /dev/null +++ b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr @@ -0,0 +1,59 @@ +error[E0277]: the trait bound `A: Trait` is not satisfied + --> $DIR/suggest-imm-mut-trait-implementations.rs:20:9 + | +LL | foo(a); + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11 + | +LL | fn foo(_: X) {} + | ^^^^^ required by this bound in `foo` +help: consider borrowing here + | +LL | foo(&a); + | + +LL | foo(&mut a); + | ++++ + +error[E0277]: the trait bound `B: Trait` is not satisfied + --> $DIR/suggest-imm-mut-trait-implementations.rs:21:9 + | +LL | foo(b); + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11 + | +LL | fn foo(_: X) {} + | ^^^^^ required by this bound in `foo` +help: consider borrowing here + | +LL | foo(&b); + | + + +error[E0277]: the trait bound `C: Trait` is not satisfied + --> $DIR/suggest-imm-mut-trait-implementations.rs:22:9 + | +LL | foo(c); + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11 + | +LL | fn foo(_: X) {} + | ^^^^^ required by this bound in `foo` +help: consider mutably borrowing here + | +LL | foo(&mut c); + | ++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/suggest-trait-items.rs b/src/test/ui/suggestions/suggest-trait-items.rs new file mode 100644 index 0000000000000..9d42a73426096 --- /dev/null +++ b/src/test/ui/suggestions/suggest-trait-items.rs @@ -0,0 +1,48 @@ +trait Foo { + type Type; + + fn foo(); + fn bar(); + fn qux(); +} + +struct A; + +impl Foo for A { +//~^ ERROR not all trait items implemented + type Typ = (); + //~^ ERROR type `Typ` is not a member of trait + //~| HELP there is an associated type with a similar name + + fn fooo() {} + //~^ ERROR method `fooo` is not a member of trait + //~| HELP there is an associated function with a similar name + + fn barr() {} + //~^ ERROR method `barr` is not a member of trait + //~| HELP there is an associated function with a similar name + + fn quux() {} + //~^ ERROR method `quux` is not a member of trait + //~| HELP there is an associated function with a similar name +} +//~^ HELP implement the missing item +//~| HELP implement the missing item +//~| HELP implement the missing item +//~| HELP implement the missing item + +trait Bar { + const Const: i32; +} + +struct B; + +impl Bar for B { +//~^ ERROR not all trait items implemented + const Cnst: i32 = 0; + //~^ ERROR const `Cnst` is not a member of trait + //~| HELP there is an associated constant with a similar name +} +//~^ HELP implement the missing item + +fn main() {} diff --git a/src/test/ui/suggestions/suggest-trait-items.stderr b/src/test/ui/suggestions/suggest-trait-items.stderr new file mode 100644 index 0000000000000..151bae7d1b9cb --- /dev/null +++ b/src/test/ui/suggestions/suggest-trait-items.stderr @@ -0,0 +1,74 @@ +error[E0437]: type `Typ` is not a member of trait `Foo` + --> $DIR/suggest-trait-items.rs:13:5 + | +LL | type Typ = (); + | ^^^^^---^^^^^^ + | | | + | | help: there is an associated type with a similar name: `Type` + | not a member of trait `Foo` + +error[E0407]: method `fooo` is not a member of trait `Foo` + --> $DIR/suggest-trait-items.rs:17:5 + | +LL | fn fooo() {} + | ^^^----^^^^^ + | | | + | | help: there is an associated function with a similar name: `foo` + | not a member of trait `Foo` + +error[E0407]: method `barr` is not a member of trait `Foo` + --> $DIR/suggest-trait-items.rs:21:5 + | +LL | fn barr() {} + | ^^^----^^^^^ + | | | + | | help: there is an associated function with a similar name: `bar` + | not a member of trait `Foo` + +error[E0407]: method `quux` is not a member of trait `Foo` + --> $DIR/suggest-trait-items.rs:25:5 + | +LL | fn quux() {} + | ^^^----^^^^^ + | | | + | | help: there is an associated function with a similar name: `qux` + | not a member of trait `Foo` + +error[E0438]: const `Cnst` is not a member of trait `Bar` + --> $DIR/suggest-trait-items.rs:42:5 + | +LL | const Cnst: i32 = 0; + | ^^^^^^----^^^^^^^^^^ + | | | + | | help: there is an associated constant with a similar name: `Const` + | not a member of trait `Bar` + +error[E0046]: not all trait items implemented, missing: `Type`, `foo`, `bar`, `qux` + --> $DIR/suggest-trait-items.rs:11:1 + | +LL | type Type; + | ---------- `Type` from trait +LL | +LL | fn foo(); + | --------- `foo` from trait +LL | fn bar(); + | --------- `bar` from trait +LL | fn qux(); + | --------- `qux` from trait +... +LL | impl Foo for A { + | ^^^^^^^^^^^^^^ missing `Type`, `foo`, `bar`, `qux` in implementation + +error[E0046]: not all trait items implemented, missing: `Const` + --> $DIR/suggest-trait-items.rs:40:1 + | +LL | const Const: i32; + | ----------------- `Const` from trait +... +LL | impl Bar for B { + | ^^^^^^^^^^^^^^ missing `Const` in implementation + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0046, E0407, E0437, E0438. +For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/test-attrs/test-should-panic-attr.stderr b/src/test/ui/test-attrs/test-should-panic-attr.stderr index 375ee79ca5ab7..492d1d5e03a4b 100644 --- a/src/test/ui/test-attrs/test-should-panic-attr.stderr +++ b/src/test/ui/test-attrs/test-should-panic-attr.stderr @@ -4,7 +4,7 @@ warning: argument must be of the form: `expected = "error message"` LL | #[should_panic(expected)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release. + = note: errors in this attribute were erroneously allowed and will become a hard error in a future release warning: argument must be of the form: `expected = "error message"` --> $DIR/test-should-panic-attr.rs:18:1 @@ -12,7 +12,7 @@ warning: argument must be of the form: `expected = "error message"` LL | #[should_panic(expect)] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release. + = note: errors in this attribute were erroneously allowed and will become a hard error in a future release warning: argument must be of the form: `expected = "error message"` --> $DIR/test-should-panic-attr.rs:25:1 @@ -20,7 +20,7 @@ warning: argument must be of the form: `expected = "error message"` LL | #[should_panic(expected(foo, bar))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release. + = note: errors in this attribute were erroneously allowed and will become a hard error in a future release warning: argument must be of the form: `expected = "error message"` --> $DIR/test-should-panic-attr.rs:32:1 @@ -28,7 +28,7 @@ warning: argument must be of the form: `expected = "error message"` LL | #[should_panic(expected = "foo", bar)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: errors in this attribute were erroneously allowed and will become a hard error in a future release. + = note: errors in this attribute were erroneously allowed and will become a hard error in a future release warning: 4 warnings emitted diff --git a/src/test/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs b/src/test/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs index 8c40b2a5f11d6..1e598b9e70971 100644 --- a/src/test/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs +++ b/src/test/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs @@ -1,8 +1,6 @@ // run-pass // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; pub fn main() { test05(); } @@ -12,7 +10,7 @@ fn test05_start(f: F) { } fn test05() { - let three: Box<_> = box 3; + let three: Box<_> = Box::new(3); let fn_to_send = move|n:isize| { println!("{}", *three + n); // will copy x into the closure assert_eq!(*three, 3); diff --git a/src/test/ui/threads-sendsync/task-spawn-move-and-copy.rs b/src/test/ui/threads-sendsync/task-spawn-move-and-copy.rs index 458f5653885e9..a63903778026a 100644 --- a/src/test/ui/threads-sendsync/task-spawn-move-and-copy.rs +++ b/src/test/ui/threads-sendsync/task-spawn-move-and-copy.rs @@ -2,15 +2,13 @@ #![allow(unused_must_use)] // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; use std::sync::mpsc::channel; pub fn main() { let (tx, rx) = channel::(); - let x: Box = box 1; + let x: Box = Box::new(1); let x_in_parent = &(*x) as *const isize as usize; let t = thread::spawn(move || { diff --git a/src/test/ui/traits/alias/no-duplicates.stderr b/src/test/ui/traits/alias/no-duplicates.stderr index 9f38dd40c3acb..d3002db46a22e 100644 --- a/src/test/ui/traits/alias/no-duplicates.stderr +++ b/src/test/ui/traits/alias/no-duplicates.stderr @@ -12,7 +12,7 @@ LL | type _T00 = dyn _0 + _0; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -31,7 +31,7 @@ LL | type _T01 = dyn _1 + _0; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -53,7 +53,7 @@ LL | type _T02 = dyn _1 + _1; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -69,7 +69,7 @@ LL | type _T03 = dyn Obj + _1; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -85,7 +85,7 @@ LL | type _T04 = dyn _1 + Obj; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -110,7 +110,7 @@ LL | type _T10 = dyn _2 + _3; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -129,7 +129,7 @@ LL | type _T11 = dyn _3 + _2; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -146,7 +146,7 @@ LL | type _T12 = dyn Obj + _2; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -171,7 +171,7 @@ LL | type _T13 = dyn _2 + Obj; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -190,7 +190,7 @@ LL | type _T14 = dyn _1 + _3; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -209,7 +209,7 @@ LL | type _T15 = dyn _3 + _1; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -230,7 +230,7 @@ LL | type _T16 = dyn _1 + _4; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -251,7 +251,7 @@ LL | type _T17 = dyn _4 + _1; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -268,7 +268,7 @@ LL | type _T20 = dyn _5 + _5; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -282,7 +282,7 @@ LL | type _T21 = dyn Obj + _5; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -296,7 +296,7 @@ LL | type _T22 = dyn _5 + Obj; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -310,7 +310,7 @@ LL | type _T23 = dyn _5 + Send + Sync + Obj; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -333,7 +333,7 @@ LL | type _T30 = dyn _6; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -356,7 +356,7 @@ LL | type _T31 = dyn _6 + Send; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -379,7 +379,7 @@ LL | type _T32 = dyn Send + _6; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -398,7 +398,7 @@ LL | type _T40 = dyn _8 + Obj; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -417,7 +417,7 @@ LL | type _T41 = dyn Obj + _8; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -441,7 +441,7 @@ LL | type _T42 = dyn _8 + _4; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -465,7 +465,7 @@ LL | type _T43 = dyn _4 + _8; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -489,7 +489,7 @@ LL | type _T44 = dyn _4 + Send + Sync + _8; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -504,7 +504,7 @@ LL | type _T50 = dyn _9 + _10; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -519,7 +519,7 @@ LL | type _T60 = dyn _11 + _12; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjT fn(&'a u8)> + ObjT fn(&'b u8)> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjT fn(&'a u8)> + ObjT fn(&'b u8)> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 27 previous errors diff --git a/src/test/ui/traits/alias/no-extra-traits.stderr b/src/test/ui/traits/alias/no-extra-traits.stderr index cdb5cd90b85c6..eaba70d7ce395 100644 --- a/src/test/ui/traits/alias/no-extra-traits.stderr +++ b/src/test/ui/traits/alias/no-extra-traits.stderr @@ -9,7 +9,7 @@ LL | type _T00 = dyn _0 + ObjB; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -23,7 +23,7 @@ LL | type _T01 = dyn ObjB + _0; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -39,7 +39,7 @@ LL | type _T02 = dyn ObjB + _1; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -55,7 +55,7 @@ LL | type _T03 = dyn _1 + ObjB; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -74,7 +74,7 @@ LL | type _T10 = dyn _2 + _3; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -93,7 +93,7 @@ LL | type _T11 = dyn _3 + _2; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -114,7 +114,7 @@ LL | type _T12 = dyn _2 + _4; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -135,7 +135,7 @@ LL | type _T13 = dyn _4 + _2; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -154,7 +154,7 @@ LL | type _T20 = dyn _5 + _1; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -173,7 +173,7 @@ LL | type _T21 = dyn _1 + _5; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -187,7 +187,7 @@ LL | type _T22 = dyn _5 + ObjA; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -201,7 +201,7 @@ LL | type _T23 = dyn ObjA + _5; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -220,7 +220,7 @@ LL | type _T24 = dyn Send + _5 + _1 + Sync; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -239,7 +239,7 @@ LL | type _T25 = dyn _1 + Sync + _5 + Send; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -253,7 +253,7 @@ LL | type _T26 = dyn Sync + Send + _5 + ObjA; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -267,7 +267,7 @@ LL | type _T27 = dyn Send + Sync + ObjA + _5; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -292,7 +292,7 @@ LL | type _T30 = dyn _6; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -317,7 +317,7 @@ LL | type _T31 = dyn _6 + Send; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -342,7 +342,7 @@ LL | type _T32 = dyn Send + _6; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -377,7 +377,7 @@ LL | type _T33 = dyn _8; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -412,7 +412,7 @@ LL | type _T34 = dyn _8 + Send; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -447,7 +447,7 @@ LL | type _T35 = dyn Send + _8; | trait alias used in trait object type (additional use) | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -466,7 +466,7 @@ LL | type _T40 = dyn _10 + ObjA; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -485,7 +485,7 @@ LL | type _T41 = dyn ObjA + _10; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -509,7 +509,7 @@ LL | type _T42 = dyn _10 + _1; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -528,7 +528,7 @@ LL | type _T43 = dyn Send + _10 + Sync + ObjA; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -547,7 +547,7 @@ LL | type _T44 = dyn ObjA + _10 + Send + Sync; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -571,7 +571,7 @@ LL | type _T45 = dyn Sync + Send + _10 + _1; | | | trait alias used in trait object type (first use) | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 28 previous errors diff --git a/src/test/ui/traits/auxiliary/issue_89119_intercrate_caching.rs b/src/test/ui/traits/auxiliary/issue_89119_intercrate_caching.rs new file mode 100644 index 0000000000000..769e897316327 --- /dev/null +++ b/src/test/ui/traits/auxiliary/issue_89119_intercrate_caching.rs @@ -0,0 +1,60 @@ +// This is the auxiliary crate for the regression test for issue #89119, minimized +// from `zvariant-2.8.0`. + +use std::convert::TryFrom; +use std::borrow::Cow; + +pub struct Str<'a>(Cow<'a, str>); +impl<'a> Str<'a> { + pub fn to_owned(&self) -> Str<'static> { + todo!() + } +} + +pub enum Value<'a> { + Str(Str<'a>), + Value(Box>), +} +impl<'a> Value<'a> { + pub fn to_owned(&self) -> Value<'static> { + match self { + Value::Str(v) => Value::Str(v.to_owned()), + Value::Value(v) => { + let o = OwnedValue::from(&**v); + Value::Value(Box::new(o.into_inner())) + } + } + } +} + +struct OwnedValue(Value<'static>); +impl OwnedValue { + pub(crate) fn into_inner(self) -> Value<'static> { + todo!() + } +} +impl<'a, T> TryFrom for Vec +where + T: TryFrom, Error = ()>, +{ + type Error = (); + fn try_from(_: OwnedValue) -> Result { + todo!() + } +} +impl TryFrom for Vec { + type Error = (); + fn try_from(_: OwnedValue) -> Result { + todo!() + } +} +impl<'a> From> for OwnedValue { + fn from(_: Value<'a>) -> Self { + todo!() + } +} +impl<'a> From<&Value<'a>> for OwnedValue { + fn from(_: &Value<'a>) -> Self { + todo!() + } +} diff --git a/src/test/ui/traits/bad-sized.stderr b/src/test/ui/traits/bad-sized.stderr index 1322b66003527..5421e71509f3a 100644 --- a/src/test/ui/traits/bad-sized.stderr +++ b/src/test/ui/traits/bad-sized.stderr @@ -6,7 +6,7 @@ LL | let x: Vec = Vec::new(); | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Trait + Sized {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Trait + Sized {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time diff --git a/src/test/ui/traits/bound/in-arc.rs b/src/test/ui/traits/bound/in-arc.rs index 941f66c056104..a1492c0b98237 100644 --- a/src/test/ui/traits/bound/in-arc.rs +++ b/src/test/ui/traits/bound/in-arc.rs @@ -5,8 +5,6 @@ // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::sync::Arc; use std::sync::mpsc::channel; use std::thread; @@ -67,10 +65,11 @@ pub fn main() { swim_speed: 998, name: "alec_guinness".to_string(), }; - let arc = Arc::new(vec![box catte as Box, - box dogge1 as Box, - box fishe as Box, - box dogge2 as Box]); + let arc = Arc::new(vec![ + Box::new(catte) as Box, + Box::new(dogge1) as Box, + Box::new(fishe) as Box, + Box::new(dogge2) as Box]); let (tx1, rx1) = channel(); let arc1 = arc.clone(); let t1 = thread::spawn(move|| { check_legs(arc1); tx1.send(()); }); diff --git a/src/test/ui/traits/coercion.rs b/src/test/ui/traits/coercion.rs index cba33af1f1aca..e62742bac5c74 100644 --- a/src/test/ui/traits/coercion.rs +++ b/src/test/ui/traits/coercion.rs @@ -2,7 +2,6 @@ #![allow(dead_code)] #![allow(unused_mut)] #![allow(unused_variables)] -#![feature(box_syntax)] use std::io::{self, Write}; diff --git a/src/test/ui/traits/conditional-dispatch.rs b/src/test/ui/traits/conditional-dispatch.rs index a9c194486fecb..dd882dce66635 100644 --- a/src/test/ui/traits/conditional-dispatch.rs +++ b/src/test/ui/traits/conditional-dispatch.rs @@ -3,7 +3,6 @@ // blanket impl for T:Copy coexists with an impl for Box, because // Box does not impl Copy. -#![feature(box_syntax)] trait Get { fn get(&self) -> Self; @@ -20,7 +19,7 @@ impl Get for T { } impl Get for Box { - fn get(&self) -> Box { box get_it(&**self) } + fn get(&self) -> Box { Box::new(get_it(&**self)) } } fn get_it(t: &T) -> T { diff --git a/src/test/ui/traits/inductive-overflow/supertrait-auto-trait.stderr b/src/test/ui/traits/inductive-overflow/supertrait-auto-trait.stderr index 7895e50eef5c4..8405d7ddc7aa5 100644 --- a/src/test/ui/traits/inductive-overflow/supertrait-auto-trait.stderr +++ b/src/test/ui/traits/inductive-overflow/supertrait-auto-trait.stderr @@ -1,10 +1,10 @@ -error[E0568]: auto traits cannot have super traits - --> $DIR/supertrait-auto-trait.rs:8:19 +error[E0568]: auto traits cannot have super traits or lifetime bounds + --> $DIR/supertrait-auto-trait.rs:8:17 | LL | auto trait Magic: Copy {} - | ----- ^^^^ help: remove the super traits + | -----^^^^^^ help: remove the super traits or lifetime bounds | | - | auto trait cannot have super traits + | auto trait cannot have super traits or lifetime bounds error[E0277]: the trait bound `NoClone: Copy` is not satisfied --> $DIR/supertrait-auto-trait.rs:16:23 diff --git a/src/test/ui/traits/issue-6128.rs b/src/test/ui/traits/issue-6128.rs index 8859fbe6afb7b..07d92f8f8a016 100644 --- a/src/test/ui/traits/issue-6128.rs +++ b/src/test/ui/traits/issue-6128.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(box_syntax)] - use std::collections::HashMap; trait Graph { @@ -19,6 +17,6 @@ impl Graph for HashMap { } pub fn main() { - let g : Box> = box HashMap::new(); + let g : Box> = Box::new(HashMap::new()); let _g2 : Box> = g as Box>; } diff --git a/src/test/ui/traits/issue-89119.rs b/src/test/ui/traits/issue-89119.rs new file mode 100644 index 0000000000000..170f69915e2ab --- /dev/null +++ b/src/test/ui/traits/issue-89119.rs @@ -0,0 +1,11 @@ +// This is a regression test for issue #89119: an issue in intercrate mode caching. +// +// It requires multiple crates, of course, but the bug is triggered by the code in the dependency, +// not the main crate. This is why this file is empty. +// +// The auxiliary crate used in the test contains the code minimized from `zvariant-2.8.0`. + +// check-pass +// aux-build: issue_89119_intercrate_caching.rs + +fn main() {} diff --git a/src/test/ui/traits/kindck-owned-contains-1.rs b/src/test/ui/traits/kindck-owned-contains-1.rs index 23b91f924b553..8adb06ba3d04e 100644 --- a/src/test/ui/traits/kindck-owned-contains-1.rs +++ b/src/test/ui/traits/kindck-owned-contains-1.rs @@ -2,8 +2,6 @@ #![allow(non_snake_case)] #![allow(non_camel_case_types)] -#![feature(box_syntax)] - trait repeat { fn get(&self) -> A; } impl repeat for Box { @@ -13,11 +11,11 @@ impl repeat for Box { } fn repeater(v: Box) -> Box+'static> { - box v as Box+'static> // No + Box::new(v) as Box+'static> // No } pub fn main() { let x = 3; - let y = repeater(box x); + let y = repeater(Box::new(x)); assert_eq!(x, y.get()); } diff --git a/src/test/ui/traits/mutual-recursion-issue-75860.stderr b/src/test/ui/traits/mutual-recursion-issue-75860.stderr index d2ac3a836f622..920f66121e098 100644 --- a/src/test/ui/traits/mutual-recursion-issue-75860.stderr +++ b/src/test/ui/traits/mutual-recursion-issue-75860.stderr @@ -4,7 +4,7 @@ error[E0275]: overflow evaluating the requirement `Option<_>: Sized` LL | iso(left, right) | ^^^ | - = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`mutual_recursion_issue_75860`) + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mutual_recursion_issue_75860`) note: required by a bound in `Option` --> $SRC_DIR/core/src/option.rs:LL:COL | diff --git a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr index 790e2a81c3a8c..8059a8ca71e43 100644 --- a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -61,10 +61,8 @@ error[E0277]: `dummy2::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:48:13 | LL | is_send(Box::new(TestType)); - | ------- ^^^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Send` - | | help: consider borrowing here: `&Box::new(TestType)` + | ------- ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Send` + | | | required by a bound introduced by this call | = note: the trait bound `dummy2::TestType: Send` is not satisfied @@ -75,6 +73,10 @@ note: required by a bound in `is_send` | LL | fn is_send(_: T) {} | ^^^^ required by this bound in `is_send` +help: consider borrowing here + | +LL | is_send(&Box::new(TestType)); + | + error[E0277]: `dummy3::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:56:13 @@ -102,10 +104,8 @@ error[E0277]: `main::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:66:13 | LL | is_sync(Outer2(TestType)); - | ------- ^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Sync` - | | help: consider borrowing here: `&Outer2(TestType)` + | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Sync` + | | | required by a bound introduced by this call | = note: the trait bound `main::TestType: Sync` is not satisfied @@ -119,6 +119,12 @@ note: required by a bound in `is_sync` | LL | fn is_sync(_: T) {} | ^^^^ required by this bound in `is_sync` +help: consider borrowing here + | +LL | is_sync(&Outer2(TestType)); + | + +LL | is_sync(&mut Outer2(TestType)); + | ++++ error: aborting due to 7 previous errors diff --git a/src/test/ui/traits/normalize-super-trait.rs b/src/test/ui/traits/normalize-supertrait.rs similarity index 100% rename from src/test/ui/traits/normalize-super-trait.rs rename to src/test/ui/traits/normalize-supertrait.rs diff --git a/src/test/ui/traits/object-one-type-two-traits.rs b/src/test/ui/traits/object-one-type-two-traits.rs index b92a2ab7b4bc2..86a2094eee098 100644 --- a/src/test/ui/traits/object-one-type-two-traits.rs +++ b/src/test/ui/traits/object-one-type-two-traits.rs @@ -4,8 +4,6 @@ // Testing creating two vtables with the same self type, but different // traits. -#![feature(box_syntax)] - use std::any::Any; trait Wrap { @@ -27,7 +25,7 @@ fn is(x: &dyn Any) -> bool { } fn main() { - let x = box 22isize as Box; + let x = Box::new(22isize) as Box; println!("x={}", x.get()); let y = x.wrap(); } diff --git a/src/test/ui/traits/object/generics.rs b/src/test/ui/traits/object/generics.rs index c18754302b75b..e5a96af3810de 100644 --- a/src/test/ui/traits/object/generics.rs +++ b/src/test/ui/traits/object/generics.rs @@ -1,8 +1,6 @@ // run-pass // test for #8664 -#![feature(box_syntax)] - use std::marker; pub trait Trait2 { @@ -38,6 +36,6 @@ impl Trait for () { } pub fn main() { - let a = box () as Box>; + let a = Box::new(()) as Box>; assert_eq!(a.method(Type::Constant((1, 2))), 0); } diff --git a/src/test/ui/traits/test-2.rs b/src/test/ui/traits/test-2.rs index 183c779607c95..342928e882a55 100644 --- a/src/test/ui/traits/test-2.rs +++ b/src/test/ui/traits/test-2.rs @@ -1,6 +1,6 @@ -#![feature(box_syntax)] - #[allow(non_camel_case_types)] + + trait bar { fn dup(&self) -> Self; fn blah(&self); } impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } @@ -10,7 +10,8 @@ fn main() { //~^ ERROR this associated function takes 0 generic arguments but 1 10.blah::(); //~^ ERROR this associated function takes 1 generic argument but 2 - (box 10 as Box).dup(); + (Box::new(10) as Box).dup(); //~^ ERROR E0038 //~| ERROR E0038 + //~| ERROR E0038 } diff --git a/src/test/ui/traits/test-2.stderr b/src/test/ui/traits/test-2.stderr index d943b48fd0082..77ea4e4e974eb 100644 --- a/src/test/ui/traits/test-2.stderr +++ b/src/test/ui/traits/test-2.stderr @@ -27,10 +27,27 @@ LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } | ^^^^ - error[E0038]: the trait `bar` cannot be made into an object - --> $DIR/test-2.rs:13:16 + --> $DIR/test-2.rs:13:22 | -LL | (box 10 as Box).dup(); - | ^^^^^^^^^^^^ `bar` cannot be made into an object +LL | (Box::new(10) as Box).dup(); + | ^^^^^^^^^^^^ `bar` 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 + --> $DIR/test-2.rs:4:30 + | +LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } + | --- ^^^^ ^^^^ ...because method `blah` has generic type parameters + | | | + | | ...because method `dup` references the `Self` type in its return type + | this trait cannot be made into an object... + = help: consider moving `dup` to another trait + = help: consider moving `blah` to another trait + +error[E0038]: the trait `bar` cannot be made into an object + --> $DIR/test-2.rs:13:5 + | +LL | (Box::new(10) as Box).dup(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` 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 --> $DIR/test-2.rs:4:30 @@ -46,8 +63,8 @@ LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } error[E0038]: the trait `bar` cannot be made into an object --> $DIR/test-2.rs:13:6 | -LL | (box 10 as Box).dup(); - | ^^^^^^ `bar` cannot be made into an object +LL | (Box::new(10) as Box).dup(); + | ^^^^^^^^^^^^ `bar` 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 --> $DIR/test-2.rs:4:30 @@ -62,7 +79,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box<{integer}>` = note: required by cast to type `Box` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs b/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs index 277d9eabe4fb2..6d88002540c1a 100644 --- a/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs +++ b/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(box_syntax, trait_upcasting)] +#![feature(trait_upcasting)] #![allow(incomplete_features)] struct Test { @@ -8,6 +8,6 @@ struct Test { fn main() { let closure: Box = Box::new(|| ()); - let mut test = box Test { func: closure }; + let mut test = Box::new(Test { func: closure }); (test.func)(); } diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs new file mode 100644 index 0000000000000..c6725101858eb --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs @@ -0,0 +1,25 @@ +#![deny(deref_into_dyn_supertrait)] + +extern crate core; + +use core::ops::Deref; + +// issue 89190 +trait A {} +trait B: A {} +impl<'a> Deref for dyn 'a + B { + type Target = dyn A; + fn deref(&self) -> &Self::Target { + todo!() + } +} + +fn take_a(_: &dyn A) {} + +fn whoops(b: &dyn B) { + take_a(b) + //~^ ERROR `dyn B` implements `Deref` with supertrait `(dyn A + 'static)` as output + //~^^ WARN this was previously accepted by the compiler but is being phased out; +} + +fn main() {} diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr new file mode 100644 index 0000000000000..35af9112a27fc --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr @@ -0,0 +1,16 @@ +error: `dyn B` implements `Deref` with supertrait `(dyn A + 'static)` as output + --> $DIR/migrate-lint-deny.rs:20:12 + | +LL | take_a(b) + | ^ + | +note: the lint level is defined here + --> $DIR/migrate-lint-deny.rs:1:9 + | +LL | #![deny(deref_into_dyn_supertrait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 #89460 + +error: aborting due to previous error + diff --git a/src/test/ui/traits/vtable/vtable-diamond.rs b/src/test/ui/traits/vtable/vtable-diamond.rs index f64ae95f1d4dd..ec25e8a707111 100644 --- a/src/test/ui/traits/vtable/vtable-diamond.rs +++ b/src/test/ui/traits/vtable/vtable-diamond.rs @@ -13,13 +13,13 @@ trait B: A { #[rustc_dump_vtable] trait C: A { - //~^ error Vtable + //~^ error vtable fn foo_c(&self) {} } #[rustc_dump_vtable] trait D: B + C { - //~^ error Vtable + //~^ error vtable fn foo_d(&self) {} } diff --git a/src/test/ui/traits/vtable/vtable-diamond.stderr b/src/test/ui/traits/vtable/vtable-diamond.stderr index 92a7f29536e3d..f2b64fac3b75e 100644 --- a/src/test/ui/traits/vtable/vtable-diamond.stderr +++ b/src/test/ui/traits/vtable/vtable-diamond.stderr @@ -1,4 +1,4 @@ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -16,7 +16,7 @@ LL | | fn foo_d(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, diff --git a/src/test/ui/traits/vtable/vtable-multi-level.rs b/src/test/ui/traits/vtable/vtable-multi-level.rs index 33112b4eaaade..fcb5fd5274be4 100644 --- a/src/test/ui/traits/vtable/vtable-multi-level.rs +++ b/src/test/ui/traits/vtable/vtable-multi-level.rs @@ -17,7 +17,7 @@ trait A { #[rustc_dump_vtable] trait B { - //~^ error Vtable + //~^ error vtable fn foo_b(&self) {} } @@ -28,19 +28,19 @@ trait C: A + B { #[rustc_dump_vtable] trait D { - //~^ error Vtable + //~^ error vtable fn foo_d(&self) {} } #[rustc_dump_vtable] trait E { - //~^ error Vtable + //~^ error vtable fn foo_e(&self) {} } #[rustc_dump_vtable] trait F: D + E { - //~^ error Vtable + //~^ error vtable fn foo_f(&self) {} } @@ -51,49 +51,49 @@ trait G: C + F { #[rustc_dump_vtable] trait H { - //~^ error Vtable + //~^ error vtable fn foo_h(&self) {} } #[rustc_dump_vtable] trait I { - //~^ error Vtable + //~^ error vtable fn foo_i(&self) {} } #[rustc_dump_vtable] trait J: H + I { - //~^ error Vtable + //~^ error vtable fn foo_j(&self) {} } #[rustc_dump_vtable] trait K { - //~^ error Vtable + //~^ error vtable fn foo_k(&self) {} } #[rustc_dump_vtable] trait L { - //~^ error Vtable + //~^ error vtable fn foo_l(&self) {} } #[rustc_dump_vtable] trait M: K + L { - //~^ error Vtable + //~^ error vtable fn foo_m(&self) {} } #[rustc_dump_vtable] trait N: J + M { - //~^ error Vtable + //~^ error vtable fn foo_n(&self) {} } #[rustc_dump_vtable] trait O: G + N { - //~^ error Vtable + //~^ error vtable fn foo_o(&self) {} } diff --git a/src/test/ui/traits/vtable/vtable-multi-level.stderr b/src/test/ui/traits/vtable/vtable-multi-level.stderr index 7700db98e0bf1..742b88ea8a9c9 100644 --- a/src/test/ui/traits/vtable/vtable-multi-level.stderr +++ b/src/test/ui/traits/vtable/vtable-multi-level.stderr @@ -1,4 +1,4 @@ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -37,7 +37,7 @@ LL | | fn foo_o(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -51,7 +51,7 @@ LL | | fn foo_b(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -65,7 +65,7 @@ LL | | fn foo_d(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -79,7 +79,7 @@ LL | | fn foo_e(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -96,7 +96,7 @@ LL | | fn foo_f(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -110,7 +110,7 @@ LL | | fn foo_h(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -124,7 +124,7 @@ LL | | fn foo_i(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -141,7 +141,7 @@ LL | | fn foo_j(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -155,7 +155,7 @@ LL | | fn foo_k(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -169,7 +169,7 @@ LL | | fn foo_l(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -186,7 +186,7 @@ LL | | fn foo_m(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, diff --git a/src/test/ui/traits/vtable/vtable-multiple.rs b/src/test/ui/traits/vtable/vtable-multiple.rs index cb0d0b7248190..8e7098a495ed1 100644 --- a/src/test/ui/traits/vtable/vtable-multiple.rs +++ b/src/test/ui/traits/vtable/vtable-multiple.rs @@ -8,13 +8,13 @@ trait A { #[rustc_dump_vtable] trait B { - //~^ error Vtable + //~^ error vtable fn foo_b(&self) {} } #[rustc_dump_vtable] trait C: A + B { - //~^ error Vtable + //~^ error vtable fn foo_c(&self) {} } diff --git a/src/test/ui/traits/vtable/vtable-multiple.stderr b/src/test/ui/traits/vtable/vtable-multiple.stderr index f51b083de2515..f25ac76fbe069 100644 --- a/src/test/ui/traits/vtable/vtable-multiple.stderr +++ b/src/test/ui/traits/vtable/vtable-multiple.stderr @@ -1,4 +1,4 @@ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -15,7 +15,7 @@ LL | | fn foo_c(&self) {} LL | | } | |_^ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, diff --git a/src/test/ui/traits/vtable/vtable-non-object-safe.rs b/src/test/ui/traits/vtable/vtable-non-object-safe.rs index 45b6a8a98a79f..7661bb574613b 100644 --- a/src/test/ui/traits/vtable/vtable-non-object-safe.rs +++ b/src/test/ui/traits/vtable/vtable-non-object-safe.rs @@ -6,7 +6,7 @@ #[rustc_dump_vtable] trait A: Iterator {} -//~^ error Vtable +//~^ error vtable impl A for T where T: Iterator {} diff --git a/src/test/ui/traits/vtable/vtable-non-object-safe.stderr b/src/test/ui/traits/vtable/vtable-non-object-safe.stderr index f3175b805d1b6..34fe910525be1 100644 --- a/src/test/ui/traits/vtable/vtable-non-object-safe.stderr +++ b/src/test/ui/traits/vtable/vtable-non-object-safe.stderr @@ -1,4 +1,4 @@ -error: Vtable entries for ` as A>`: [ +error: vtable entries for ` as A>`: [ MetadataDropInPlace, MetadataSize, MetadataAlign, diff --git a/src/test/ui/traits/vtable/vtable-vacant.rs b/src/test/ui/traits/vtable/vtable-vacant.rs index 429ce523799f3..a64796358345f 100644 --- a/src/test/ui/traits/vtable/vtable-vacant.rs +++ b/src/test/ui/traits/vtable/vtable-vacant.rs @@ -13,7 +13,7 @@ trait A { #[rustc_dump_vtable] trait B: A { - //~^ error Vtable + //~^ error vtable fn foo_b1(&self) {} fn foo_b2(&self) where Self: Send {} } diff --git a/src/test/ui/traits/vtable/vtable-vacant.stderr b/src/test/ui/traits/vtable/vtable-vacant.stderr index f5cd36264fcff..e3b75e7cf33f3 100644 --- a/src/test/ui/traits/vtable/vtable-vacant.stderr +++ b/src/test/ui/traits/vtable/vtable-vacant.stderr @@ -1,4 +1,4 @@ -error: Vtable entries for ``: [ +error: vtable entries for ``: [ MetadataDropInPlace, MetadataSize, MetadataAlign, diff --git a/src/test/ui/traits/wf-object/no-duplicates.stderr b/src/test/ui/traits/wf-object/no-duplicates.stderr index b9506894f82c9..50dfcf956362e 100644 --- a/src/test/ui/traits/wf-object/no-duplicates.stderr +++ b/src/test/ui/traits/wf-object/no-duplicates.stderr @@ -6,7 +6,7 @@ LL | type _0 = dyn Obj + Obj; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -17,7 +17,7 @@ LL | type _1 = dyn Send + Obj + Obj; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -28,7 +28,7 @@ LL | type _2 = dyn Obj + Send + Obj; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Obj + Obj {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -39,7 +39,7 @@ LL | type _4 = dyn for<'a> ObjL<'a> + for<'b> ObjL<'b>; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error[E0225]: only auto traits can be used as additional traits in a trait object @@ -50,7 +50,7 @@ LL | type _5 = dyn ObjT fn(&'a u8)> + ObjT fn(&'b u8)>; | | | first non-auto trait | - = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: ObjT fn(&'a u8)> + ObjT fn(&'b u8)> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjT fn(&'a u8)> + ObjT fn(&'b u8)> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit error: aborting due to 5 previous errors diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr index 7bd951febf5c5..1e26623899bad 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr @@ -1,4 +1,4 @@ -warning: Trait bound String: Copy does not depend on any type or lifetime parameters +warning: trait bound String: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:5:51 | LL | fn copy_string(t: String) -> String where String: Copy { @@ -6,19 +6,19 @@ LL | fn copy_string(t: String) -> String where String: Copy { | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound String: Copy does not depend on any type or lifetime parameters +warning: trait bound String: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:12:56 | LL | fn copy_out_string(t: &String) -> String where String: Copy { | ^^^^ -warning: Trait bound String: Copy does not depend on any type or lifetime parameters +warning: trait bound String: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:16:55 | LL | fn copy_string_with_param(x: String) where String: Copy { | ^^^^ -warning: Trait bound for<'b> &'b mut i32: Copy does not depend on any type or lifetime parameters +warning: trait bound for<'b> &'b mut i32: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-copy.rs:22:76 | LL | fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection.stderr index e7835814cb83e..ddc13c512f60f 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection.stderr @@ -1,4 +1,4 @@ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:21:8 | LL | B: A @@ -6,37 +6,37 @@ LL | B: A | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:28:8 | LL | B: A | ^^^^^^^^^^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:35:8 | LL | B: A | ^^^^^^^^^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:42:8 | LL | B: A + A | ^^^^^^^^^^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:42:21 | LL | B: A + A | ^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:51:8 | LL | B: A + A | ^^^^^^^^^ -warning: Trait bound B: A does not depend on any type or lifetime parameters +warning: trait bound B: A does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-projection.rs:51:20 | LL | B: A + A diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr index ff254edbd7b0c..cf24d811c04e3 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr @@ -1,4 +1,4 @@ -warning: Trait bound str: Sized does not depend on any type or lifetime parameters +warning: trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:14:31 | LL | struct S(str, str) where str: Sized; @@ -6,13 +6,13 @@ LL | struct S(str, str) where str: Sized; | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound for<'a> T<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters +warning: trait bound for<'a> T<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:17:49 | LL | fn unsized_local() where for<'a> T: Sized { | ^^^^^ -warning: Trait bound str: Sized does not depend on any type or lifetime parameters +warning: trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-sized.rs:22:35 | LL | fn return_str() -> str where str: Sized { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr index a9905052ffdfb..8f58a99a86f91 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr @@ -1,4 +1,4 @@ -warning: Trait bound Vec: Debug does not depend on any type or lifetime parameters +warning: trait bound Vec: Debug does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-well-formed.rs:7:30 | LL | pub fn foo() where Vec: Debug, str: Copy { @@ -6,7 +6,7 @@ LL | pub fn foo() where Vec: Debug, str: Copy { | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound str: Copy does not depend on any type or lifetime parameters +warning: trait bound str: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent-well-formed.rs:7:42 | LL | pub fn foo() where Vec: Debug, str: Copy { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr index 94c51c5788a32..16f32e043d500 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr @@ -1,4 +1,4 @@ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:14:19 | LL | enum E where i32: Foo { V } @@ -6,19 +6,19 @@ LL | enum E where i32: Foo { V } | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:16:21 | LL | struct S where i32: Foo; | ^^^ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:18:20 | LL | trait T where i32: Foo {} | ^^^ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:20:20 | LL | union U where i32: Foo { f: i32 } @@ -37,55 +37,55 @@ LL - type Y where i32: Foo = (); LL + type Y = (); | -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:22:19 | LL | type Y where i32: Foo = (); | ^^^ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:26:28 | LL | impl Foo for () where i32: Foo { | ^^^ -warning: Trait bound i32: Foo does not depend on any type or lifetime parameters +warning: trait bound i32: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:34:19 | LL | fn f() where i32: Foo { | ^^^ -warning: Trait bound &'static str: Foo does not depend on any type or lifetime parameters +warning: trait bound &'static str: Foo does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:41:28 | LL | fn g() where &'static str: Foo { | ^^^ -warning: Trait bound str: Sized does not depend on any type or lifetime parameters +warning: trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:55:37 | LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^ -warning: Trait bound for<'a> Dst<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters +warning: trait bound for<'a> Dst<(dyn A + 'a)>: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:57:51 | LL | fn unsized_local() where for<'a> Dst: Sized { | ^^^^^ -warning: Trait bound str: Sized does not depend on any type or lifetime parameters +warning: trait bound str: Sized does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:61:35 | LL | fn return_str() -> str where str: Sized { | ^^^^^ -warning: Trait bound String: Neg does not depend on any type or lifetime parameters +warning: trait bound String: Neg does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:65:46 | LL | fn use_op(s: String) -> String where String: ::std::ops::Neg { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: Trait bound i32: Iterator does not depend on any type or lifetime parameters +warning: trait bound i32: Iterator does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-inconsistent.rs:70:25 | LL | fn use_for() where i32: Iterator { diff --git a/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr b/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr index c685d9e740919..20e0ddfc29b36 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr @@ -1,4 +1,4 @@ -error: Trait bound i32: Copy does not depend on any type or lifetime parameters +error: trait bound i32: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:5:21 | LL | struct A where i32: Copy; @@ -10,37 +10,37 @@ note: the lint level is defined here LL | #![deny(trivial_bounds)] | ^^^^^^^^^^^^^^ -error: Trait bound i32: X<()> does not depend on any type or lifetime parameters +error: trait bound i32: X<()> does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:18:30 | LL | fn global_param() where i32: X<()> {} | ^^^^^ -error: Trait bound i32: Z does not depend on any type or lifetime parameters +error: trait bound i32: Z does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:22:35 | LL | fn global_projection() where i32: Z {} | ^^^^^^^^^^ -error: Lifetime bound i32: 'static does not depend on any type or lifetime parameters +error: lifetime bound i32: 'static does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:29:34 | LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {} | ^^^^^^^ -error: Lifetime bound &'static str: 'static does not depend on any type or lifetime parameters +error: lifetime bound &'static str: 'static does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:29:57 | LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {} | ^^^^^^^ -error: Lifetime bound 'static: 'static does not depend on any type or lifetime parameters +error: lifetime bound 'static: 'static does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:35:37 | LL | fn global_outlives() where 'static: 'static {} | ^^^^^^^ -error: Trait bound i32: Copy does not depend on any type or lifetime parameters +error: trait bound i32: Copy does not depend on any type or lifetime parameters --> $DIR/trivial-bounds-lint.rs:38:46 | LL | fn mixed_bounds() where i32: X + Copy {} diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr index 86b3f87d34d03..c0147e56c9364 100644 --- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr +++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr @@ -9,7 +9,7 @@ note: ...which requires type-checking `m::bar`... | LL | is_send(foo()); | ^^^^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::fmt::Debug: std::marker::Send`... + = note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`... = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in module `m` --> $DIR/auto-trait-leakage3.rs:6:1 diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs index a15074c35936b..579067340e85c 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs @@ -7,6 +7,7 @@ trait TraitWithAssoc { } type Foo = impl Trait; +//~^ ERROR could not find defining uses trait Trait {} @@ -14,5 +15,9 @@ impl Trait for () {} fn foo_desugared(_: T) -> Foo { //~^ ERROR non-defining opaque type use in defining scope + //~| ERROR non-defining opaque type use in defining scope + //~| ERROR non-defining opaque type use in defining scope + //~| ERROR `T` is part of concrete type but not used in parameter list + //~| ERROR `T` is part of concrete type but not used in parameter list () } diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr index c9d6a43b9094a..a77c0000f12e1 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,8 +1,34 @@ +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/bound_reduction2.rs:16:60 + | +LL | fn foo_desugared(_: T) -> Foo { + | ____________________________________________________________^ +LL | | +LL | | +LL | | +... | +LL | | () +LL | | } + | |_^ + +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/bound_reduction2.rs:16:60 + | +LL | fn foo_desugared(_: T) -> Foo { + | ____________________________________________________________^ +LL | | +LL | | +LL | | +... | +LL | | () +LL | | } + | |_^ + error: non-defining opaque type use in defining scope - --> $DIR/bound_reduction2.rs:15:46 + --> $DIR/bound_reduction2.rs:16:1 | LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: used non-generic type `::Assoc` for generic parameter --> $DIR/bound_reduction2.rs:9:10 @@ -10,5 +36,35 @@ note: used non-generic type `::Assoc` for generic parameter LL | type Foo = impl Trait; | ^ -error: aborting due to previous error +error: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:16:1 + | +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: used non-generic type `_` for generic parameter + --> $DIR/bound_reduction2.rs:9:10 + | +LL | type Foo = impl Trait; + | ^ + +error: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:16:1 + | +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: used non-generic type `_` for generic parameter + --> $DIR/bound_reduction2.rs:9:10 + | +LL | type Foo = impl Trait; + | ^ + +error: could not find defining uses + --> $DIR/bound_reduction2.rs:9:15 + | +LL | type Foo = impl Trait; + | ^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs index 31f992976b189..885aae619d6a2 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.rs @@ -3,6 +3,7 @@ fn main() {} type Two<'a, 'b> = impl std::fmt::Debug; +//~^ ERROR could not find defining uses fn one<'a>(t: &'a ()) -> Two<'a, 'a> { //~^ ERROR non-defining opaque type use diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr index 08b26b8fc1307..b99c6a51f4b1d 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_lifetime_param.stderr @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_lifetime_param.rs:7:26 + --> $DIR/generic_duplicate_lifetime_param.rs:8:26 | LL | fn one<'a>(t: &'a ()) -> Two<'a, 'a> { | ^^^^^^^^^^^ @@ -10,5 +10,11 @@ note: lifetime used multiple times LL | type Two<'a, 'b> = impl std::fmt::Debug; | ^^ ^^ -error: aborting due to previous error +error: could not find defining uses + --> $DIR/generic_duplicate_lifetime_param.rs:5:20 + | +LL | type Two<'a, 'b> = impl std::fmt::Debug; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs index a4e40f516dcef..33cd2f6ba0753 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs @@ -6,8 +6,11 @@ fn main() {} // test that unused generic parameters are ok type TwoTys = impl Debug; +//~^ ERROR could not find defining uses type TwoLifetimes<'a, 'b> = impl Debug; +//~^ ERROR could not find defining uses type TwoConsts = impl Debug; +//~^ ERROR could not find defining uses fn one_ty(t: T) -> TwoTys { //~^ ERROR non-defining opaque type use in defining scope diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr index 641cce26d9944..52c60d1777e49 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:12:30 + --> $DIR/generic_duplicate_param_use.rs:15:30 | LL | fn one_ty(t: T) -> TwoTys { | ^^^^^^^^^^^^ @@ -10,29 +10,47 @@ note: type used multiple times LL | type TwoTys = impl Debug; | ^ ^ +error: could not find defining uses + --> $DIR/generic_duplicate_param_use.rs:8:21 + | +LL | type TwoTys = impl Debug; + | ^^^^^^^^^^ + error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:17:36 + --> $DIR/generic_duplicate_param_use.rs:20:36 | LL | fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> { | ^^^^^^^^^^^^^^^^^^^^ | note: lifetime used multiple times - --> $DIR/generic_duplicate_param_use.rs:9:19 + --> $DIR/generic_duplicate_param_use.rs:10:19 | LL | type TwoLifetimes<'a, 'b> = impl Debug; | ^^ ^^ +error: could not find defining uses + --> $DIR/generic_duplicate_param_use.rs:10:29 + | +LL | type TwoLifetimes<'a, 'b> = impl Debug; + | ^^^^^^^^^^ + error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use.rs:22:50 + --> $DIR/generic_duplicate_param_use.rs:25:50 | LL | fn one_const(t: *mut [u8; N]) -> TwoConsts { | ^^^^^^^^^^^^^^^ | note: constant used multiple times - --> $DIR/generic_duplicate_param_use.rs:10:22 + --> $DIR/generic_duplicate_param_use.rs:12:22 | LL | type TwoConsts = impl Debug; | ^ ^ -error: aborting due to 3 previous errors +error: could not find defining uses + --> $DIR/generic_duplicate_param_use.rs:12:50 + | +LL | type TwoConsts = impl Debug; + | ^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs index a74731df69515..04fb57b39c052 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs @@ -6,6 +6,7 @@ fn main() {} // test that unused generic parameters are ok type Two = impl Debug; +//~^ ERROR `T` doesn't implement `Debug` fn one(t: T) -> Two { //~^ ERROR non-defining opaque type use in defining scope diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr index d87e8c5783b65..fca9b70d18441 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use2.rs:10:27 + --> $DIR/generic_duplicate_param_use2.rs:11:27 | LL | fn one(t: T) -> Two { | ^^^^^^^^^ @@ -10,5 +10,17 @@ note: type used multiple times LL | type Two = impl Debug; | ^ ^ -error: aborting due to previous error +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/generic_duplicate_param_use2.rs:8:18 + | +LL | type Two = impl Debug; + | ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +help: consider restricting type parameter `T` + | +LL | type Two = impl Debug; + | +++++++++++++++++ + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs index 0597b8385d252..1a755d3902612 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs @@ -6,6 +6,7 @@ fn main() {} // test that unused generic parameters are ok type Two = impl Debug; +//~^ ERROR `T` doesn't implement `Debug` fn one(t: T) -> Two { //~^ ERROR non-defining opaque type use in defining scope @@ -17,5 +18,6 @@ fn two(t: T, _: U) -> Two { } fn three(_: T, u: U) -> Two { + //~^ ERROR concrete type differs from previous defining opaque type use u } diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr index 711de855f0d10..90b04c043a00c 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use3.rs:10:27 + --> $DIR/generic_duplicate_param_use3.rs:11:27 | LL | fn one(t: T) -> Two { | ^^^^^^^^^ @@ -10,5 +10,29 @@ note: type used multiple times LL | type Two = impl Debug; | ^ ^ -error: aborting due to previous error +error: concrete type differs from previous defining opaque type use + --> $DIR/generic_duplicate_param_use3.rs:20:1 + | +LL | fn three(_: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `T`, got `U` + | +note: previous use here + --> $DIR/generic_duplicate_param_use3.rs:16:1 + | +LL | fn two(t: T, _: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/generic_duplicate_param_use3.rs:8:18 + | +LL | type Two = impl Debug; + | ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +help: consider restricting type parameter `T` + | +LL | type Two = impl Debug; + | +++++++++++++++++ + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs index e77c94988f73e..50d95c83d58e6 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.rs @@ -6,6 +6,7 @@ fn main() {} // test that unused generic parameters are ok type Two = impl Debug; +//~^ ERROR `U` doesn't implement `Debug` fn one(t: T) -> Two { //~^ ERROR non-defining opaque type use in defining scope diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr index fcf01f5164ae4..c4be2fa83f130 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_duplicate_param_use4.rs:10:27 + --> $DIR/generic_duplicate_param_use4.rs:11:27 | LL | fn one(t: T) -> Two { | ^^^^^^^^^ @@ -10,5 +10,17 @@ note: type used multiple times LL | type Two = impl Debug; | ^ ^ -error: aborting due to previous error +error[E0277]: `U` doesn't implement `Debug` + --> $DIR/generic_duplicate_param_use4.rs:8:18 + | +LL | type Two = impl Debug; + | ^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | +help: consider restricting type parameter `U` + | +LL | type Two = impl Debug; + | +++++++++++++++++ + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs index 7ee5f7b068f45..cf43085877f4c 100644 --- a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs +++ b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.rs @@ -5,8 +5,11 @@ use std::fmt::Debug; fn main() {} type OneTy = impl Debug; +//~^ ERROR could not find defining uses type OneLifetime<'a> = impl Debug; +//~^ ERROR could not find defining uses type OneConst = impl Debug; +//~^ ERROR could not find defining uses // Not defining uses, because they doesn't define *all* possible generics. diff --git a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr index 5b42f10a6ee34..3aa42a25484d1 100644 --- a/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_nondefining_use.stderr @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:13:21 + --> $DIR/generic_nondefining_use.rs:16:21 | LL | fn concrete_ty() -> OneTy { | ^^^^^^^^^^ @@ -10,8 +10,14 @@ note: used non-generic type `u32` for generic parameter LL | type OneTy = impl Debug; | ^ +error: could not find defining uses + --> $DIR/generic_nondefining_use.rs:7:17 + | +LL | type OneTy = impl Debug; + | ^^^^^^^^^^ + error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:18:27 + --> $DIR/generic_nondefining_use.rs:21:27 | LL | type OneLifetime<'a> = impl Debug; | -- cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type @@ -19,17 +25,29 @@ LL | type OneLifetime<'a> = impl Debug; LL | fn concrete_lifetime() -> OneLifetime<'static> { | ^^^^^^^^^^^^^^^^^^^^ +error: could not find defining uses + --> $DIR/generic_nondefining_use.rs:9:24 + | +LL | type OneLifetime<'a> = impl Debug; + | ^^^^^^^^^^ + error: non-defining opaque type use in defining scope - --> $DIR/generic_nondefining_use.rs:23:24 + --> $DIR/generic_nondefining_use.rs:26:24 | LL | fn concrete_const() -> OneConst<{ 123 }> { | ^^^^^^^^^^^^^^^^^ | note: used non-generic constant `123_usize` for generic parameter - --> $DIR/generic_nondefining_use.rs:9:21 + --> $DIR/generic_nondefining_use.rs:11:21 | LL | type OneConst = impl Debug; | ^ -error: aborting due to 3 previous errors +error: could not find defining uses + --> $DIR/generic_nondefining_use.rs:11:33 + | +LL | type OneConst = impl Debug; + | ^^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/src/test/ui/type-alias-impl-trait/incomplete-inference.rs b/src/test/ui/type-alias-impl-trait/incomplete-inference.rs index 955d1288a457d..4c8bf2cfca11e 100644 --- a/src/test/ui/type-alias-impl-trait/incomplete-inference.rs +++ b/src/test/ui/type-alias-impl-trait/incomplete-inference.rs @@ -8,7 +8,6 @@ fn bar() -> Foo { } fn baz() -> Foo { - //~^ ERROR: concrete type differs from previous defining opaque type use Some(()) } diff --git a/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr b/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr index 53cdf9e5b385f..0cdd4cc8dc3ba 100644 --- a/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr +++ b/src/test/ui/type-alias-impl-trait/incomplete-inference.stderr @@ -4,18 +4,6 @@ error[E0282]: type annotations needed LL | None | ^^^^ cannot infer type for type parameter `T` declared on the enum `Option` -error: concrete type differs from previous defining opaque type use - --> $DIR/incomplete-inference.rs:10:1 - | -LL | fn baz() -> Foo { - | ^^^^^^^^^^^^^^^ expected `[type error]`, got `Option<()>` - | -note: previous use here - --> $DIR/incomplete-inference.rs:5:1 - | -LL | fn bar() -> Foo { - | ^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr index 4c5921c7f660b..e12124664778e 100644 --- a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr +++ b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr @@ -9,7 +9,7 @@ note: ...which requires type-checking `m::bar`... | LL | is_send(foo()); // Today: error | ^^^^^^^ - = note: ...which requires evaluating trait selection obligation `impl std::fmt::Debug: std::marker::Send`... + = note: ...which requires evaluating trait selection obligation `impl core::fmt::Debug: core::marker::Send`... = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle note: cycle used when checking item types in module `m` --> $DIR/inference-cycle.rs:4:1 diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.rs b/src/test/ui/type-alias-impl-trait/issue-60371.rs index 37a2f28ce074f..9d2ba849c8667 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60371.rs @@ -11,6 +11,7 @@ impl Bug for &() { const FUN: fn() -> Self::Item = || (); //~^ ERROR the trait bound `(): Bug` is not satisfied + //~| ERROR non-defining opaque type use in defining scope } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-60371.stderr b/src/test/ui/type-alias-impl-trait/issue-60371.stderr index 1710e07644d64..62ab7eb456010 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60371.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60371.stderr @@ -16,7 +16,16 @@ LL | const FUN: fn() -> Self::Item = || (); = help: the following implementations were found: <&() as Bug> -error: aborting due to 2 previous errors +error: non-defining opaque type use in defining scope + --> $DIR/issue-60371.rs:12:37 + | +LL | impl Bug for &() { + | - cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type +... +LL | const FUN: fn() -> Self::Item = || (); + | ^^^^^ + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0658. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs index 78def0d1136de..44dcec2c3da98 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.rs +++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs @@ -6,6 +6,7 @@ trait IterBits { } type IterBitsIter = impl std::iter::Iterator; +//~^ ERROR could not find defining uses impl IterBits for T where diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.stderr b/src/test/ui/type-alias-impl-trait/issue-60564.stderr index 66fa862ef9d7a..6b73fbef011ec 100644 --- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-60564.rs:19:34 + --> $DIR/issue-60564.rs:20:34 | LL | fn iter_bits(self, n: u8) -> Self::BitsIter { | ^^^^^^^^^^^^^^ @@ -10,5 +10,11 @@ note: used non-generic type `u8` for generic parameter LL | type IterBitsIter = impl std::iter::Iterator; | ^ -error: aborting due to previous error +error: could not find defining uses + --> $DIR/issue-60564.rs:8:30 + | +LL | type IterBitsIter = impl std::iter::Iterator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs new file mode 100644 index 0000000000000..2e6354088ac5a --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs @@ -0,0 +1,14 @@ +// Regression test for issue #68368 +// Ensures that we don't ICE when emitting an error +// for a non-defining use when lifetimes are involved + +#![feature(type_alias_impl_trait)] +trait Trait {} +type Alias<'a, U> = impl Trait; +//~^ ERROR could not find defining uses +fn f<'a>() -> Alias<'a, ()> {} +//~^ ERROR non-defining opaque type use in defining scope + +fn main() {} + +impl Trait for () {} diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr new file mode 100644 index 0000000000000..721f99a3f0d18 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use-2.stderr @@ -0,0 +1,20 @@ +error: non-defining opaque type use in defining scope + --> $DIR/issue-68368-non-defining-use-2.rs:9:15 + | +LL | fn f<'a>() -> Alias<'a, ()> {} + | ^^^^^^^^^^^^^ + | +note: used non-generic type `()` for generic parameter + --> $DIR/issue-68368-non-defining-use-2.rs:7:16 + | +LL | type Alias<'a, U> = impl Trait; + | ^ + +error: could not find defining uses + --> $DIR/issue-68368-non-defining-use-2.rs:7:21 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs index 3b6decbe9c65e..3addd8dcc4fb3 100644 --- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs +++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs @@ -5,6 +5,7 @@ #![feature(type_alias_impl_trait)] trait Trait {} type Alias<'a, U> = impl Trait; +//~^ ERROR could not find defining uses fn f<'a>() -> Alias<'a, ()> {} //~^ ERROR non-defining opaque type use in defining scope diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr index c2fa54f50f881..f5b8fccf65d16 100644 --- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-68368-non-defining-use.rs:8:15 + --> $DIR/issue-68368-non-defining-use.rs:9:15 | LL | fn f<'a>() -> Alias<'a, ()> {} | ^^^^^^^^^^^^^ @@ -10,5 +10,11 @@ note: used non-generic type `()` for generic parameter LL | type Alias<'a, U> = impl Trait; | ^ -error: aborting due to previous error +error: could not find defining uses + --> $DIR/issue-68368-non-defining-use.rs:7:21 + | +LL | type Alias<'a, U> = impl Trait; + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs index bcd9aeff6b451..11a922443e64a 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.rs @@ -11,7 +11,6 @@ fn f(a: A, b: B) -> (X, X) } fn g(a: A, b: B) -> (X, X) { - //~^ ERROR concrete type differs from previous defining opaque type (a, b) //~^ ERROR mismatched types } diff --git a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr index 3d943b77af57d..bbe709dccab4e 100644 --- a/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr +++ b/src/test/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn3.stderr @@ -1,11 +1,10 @@ error[E0308]: mismatched types - --> $DIR/multiple-def-uses-in-one-fn3.rs:15:9 + --> $DIR/multiple-def-uses-in-one-fn3.rs:14:9 | LL | fn g(a: A, b: B) -> (X, X) { | - - found type parameter | | | expected type parameter -LL | LL | (a, b) | ^ expected type parameter `A`, found type parameter `B` | @@ -14,18 +13,6 @@ LL | (a, b) = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters -error: concrete type differs from previous defining opaque type use - --> $DIR/multiple-def-uses-in-one-fn3.rs:13:1 - | -LL | fn g(a: A, b: B) -> (X, X) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `A`, got `[type error]` - | -note: previous use here - --> $DIR/multiple-def-uses-in-one-fn3.rs:9:1 - | -LL | fn f(a: A, b: B) -> (X, X) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs index f29b980dfd0e5..107cd39457935 100644 --- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs +++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs @@ -5,6 +5,7 @@ use std::fmt::Debug; fn main() {} type Two = impl Debug; +//~^ ERROR `T` doesn't implement `Debug` fn two(t: T) -> Two { //~^ ERROR non-defining opaque type use in defining scope @@ -26,6 +27,7 @@ impl Bar for u32 { } fn four(t: T) -> Two { + //~^ ERROR concrete type differs from previous (t, ::FOO) } diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr index 2fa236b373a40..08e49845521c6 100644 --- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr +++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr @@ -1,5 +1,5 @@ error: non-defining opaque type use in defining scope - --> $DIR/not_a_defining_use.rs:9:27 + --> $DIR/not_a_defining_use.rs:10:27 | LL | fn two(t: T) -> Two { | ^^^^^^^^^^^ @@ -10,5 +10,30 @@ note: used non-generic type `u32` for generic parameter LL | type Two = impl Debug; | ^ -error: aborting due to previous error +error: concrete type differs from previous defining opaque type use + --> $DIR/not_a_defining_use.rs:29:1 + | +LL | fn four(t: T) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(T, i8)`, got `(T, ::Blub)` + | +note: previous use here + --> $DIR/not_a_defining_use.rs:15:1 + | +LL | fn three(t: T) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/not_a_defining_use.rs:7:18 + | +LL | type Two = impl Debug; + | ^^^^^^^^^^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` + | + = note: required because of the requirements on the impl of `Debug` for `(T, i8)` +help: consider restricting type parameter `T` + | +LL | type Two = impl Debug; + | +++++++++++++++++ + +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-param-constraints.rs b/src/test/ui/type-param-constraints.rs index 4b42fddaf5c88..3d87a089fca3a 100644 --- a/src/test/ui/type-param-constraints.rs +++ b/src/test/ui/type-param-constraints.rs @@ -4,8 +4,6 @@ #![allow(dead_code)] // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - fn p_foo(_pinned: T) { } fn s_foo(_shared: T) { } fn u_foo(_unique: T) { } @@ -27,13 +25,13 @@ fn r(i:isize) -> r { pub fn main() { p_foo(r(10)); - p_foo::>(box r(10)); - p_foo::>(box 10); + p_foo::>(Box::new(r(10))); + p_foo::>(Box::new(10)); p_foo(10); - s_foo::>(box 10); + s_foo::>(Box::new(10)); s_foo(10); - u_foo::>(box 10); + u_foo::>(Box::new(10)); u_foo(10); } diff --git a/src/test/ui/type/type-ascription-precedence.stderr b/src/test/ui/type/type-ascription-precedence.stderr index 92d3f18e82f44..ebce257b278bb 100644 --- a/src/test/ui/type/type-ascription-precedence.stderr +++ b/src/test/ui/type/type-ascription-precedence.stderr @@ -28,7 +28,22 @@ error[E0600]: cannot apply unary operator `-` to type `Z` LL | -(S: Z); | ^^^^^^^ cannot apply unary operator `-` | - = note: an implementation of `std::ops::Neg` might be missing for `Z` +note: an implementation of `std::ops::Neg` might be missing for `Z` + --> $DIR/type-ascription-precedence.rs:9:1 + | +LL | struct Z; + | ^^^^^^^^^ must implement `std::ops::Neg` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | / pub trait Neg { +LL | | /// The resulting type after applying the `-` operator. +LL | | #[stable(feature = "rust1", since = "1.0.0")] +LL | | type Output; +... | +LL | | fn neg(self) -> Self::Output; +LL | | } + | |_^ error[E0308]: mismatched types --> $DIR/type-ascription-precedence.rs:45:5 diff --git a/src/test/ui/typeck/call-block.rs b/src/test/ui/typeck/call-block.rs new file mode 100644 index 0000000000000..0390d7db040b4 --- /dev/null +++ b/src/test/ui/typeck/call-block.rs @@ -0,0 +1,3 @@ +fn main() { + let _ = {42}(); //~ ERROR expected function, found `{integer}` +} diff --git a/src/test/ui/typeck/call-block.stderr b/src/test/ui/typeck/call-block.stderr new file mode 100644 index 0000000000000..68984bc1c453f --- /dev/null +++ b/src/test/ui/typeck/call-block.stderr @@ -0,0 +1,11 @@ +error[E0618]: expected function, found `{integer}` + --> $DIR/call-block.rs:2:13 + | +LL | let _ = {42}(); + | ^^^^-- + | | + | call expression requires function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0618`. diff --git a/src/test/ui/typeck/issue-79040.rs b/src/test/ui/typeck/issue-79040.rs index af2a9c1ba87ef..941612542207c 100644 --- a/src/test/ui/typeck/issue-79040.rs +++ b/src/test/ui/typeck/issue-79040.rs @@ -1,5 +1,5 @@ fn main() { const FOO = "hello" + 1; //~ ERROR cannot add `{integer}` to `&str` - //~^ ERROR cannot add `{integer}` to `&str` + //~^ missing type for `const` item println!("{}", FOO); } diff --git a/src/test/ui/typeck/issue-79040.stderr b/src/test/ui/typeck/issue-79040.stderr index 32049e5d96860..aec2e1ec9e4ef 100644 --- a/src/test/ui/typeck/issue-79040.stderr +++ b/src/test/ui/typeck/issue-79040.stderr @@ -6,13 +6,11 @@ LL | const FOO = "hello" + 1; | | | &str -error[E0369]: cannot add `{integer}` to `&str` - --> $DIR/issue-79040.rs:2:25 +error: missing type for `const` item + --> $DIR/issue-79040.rs:2:11 | LL | const FOO = "hello" + 1; - | ------- ^ - {integer} - | | - | &str + | ^^^ help: provide a type for the item: `FOO: ` error: aborting due to 2 previous errors diff --git a/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.rs b/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.rs new file mode 100644 index 0000000000000..751dc8719cf33 --- /dev/null +++ b/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.rs @@ -0,0 +1,4 @@ +fn main() { + let mut a; + a = a = true; //~ ERROR mismatched types +} diff --git a/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr b/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr new file mode 100644 index 0000000000000..fe10fa733d238 --- /dev/null +++ b/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/issue-87771-ice-assign-assign-to-bool.rs:3:9 + | +LL | a = a = true; + | ^^^^^^^^ expected `bool`, found `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/typeck/issue-88609.rs b/src/test/ui/typeck/issue-88609.rs new file mode 100644 index 0000000000000..dc459c885fa70 --- /dev/null +++ b/src/test/ui/typeck/issue-88609.rs @@ -0,0 +1,19 @@ +// Regression test for #88609: +// The return type for `main` is not normalized while checking if it implements +// the trait `std::process::Termination`. + +// build-pass + +trait Same { + type Output; +} + +impl Same for T { + type Output = T; +} + +type Unit = <() as Same>::Output; + +fn main() -> Result { + unimplemented!() +} diff --git a/src/test/ui/typeclasses-eq-example-static.rs b/src/test/ui/typeclasses-eq-example-static.rs index 282d51a93df89..f982ad6a0ddc3 100644 --- a/src/test/ui/typeclasses-eq-example-static.rs +++ b/src/test/ui/typeclasses-eq-example-static.rs @@ -3,7 +3,6 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(dead_code)] -#![feature(box_syntax)] // Example from lkuper's intern talk, August 2012 -- now with static // methods! @@ -59,11 +58,11 @@ pub fn main() { assert!(Equal::isEq(&leaf(cyan), &leaf(cyan))); assert!(!Equal::isEq(&leaf(cyan), &leaf(yellow))); - assert!(Equal::isEq(&branch(box leaf(magenta), box leaf(cyan)), - &branch(box leaf(magenta), box leaf(cyan)))); + assert!(Equal::isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))), + &branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))))); - assert!(!Equal::isEq(&branch(box leaf(magenta), box leaf(cyan)), - &branch(box leaf(magenta), box leaf(magenta)))); + assert!(!Equal::isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))), + &branch(Box::new(leaf(magenta)), Box::new(leaf(magenta))))); println!("Assertions all succeeded!"); } diff --git a/src/test/ui/typeclasses-eq-example.rs b/src/test/ui/typeclasses-eq-example.rs index 8d1d22eb82300..4400301e61ed7 100644 --- a/src/test/ui/typeclasses-eq-example.rs +++ b/src/test/ui/typeclasses-eq-example.rs @@ -3,7 +3,6 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(dead_code)] -#![feature(box_syntax)] // Example from lkuper's intern talk, August 2012. use Color::{cyan, magenta, yellow, black}; @@ -55,11 +54,11 @@ pub fn main() { assert!(leaf(cyan).isEq(&leaf(cyan))); assert!(!leaf(cyan).isEq(&leaf(yellow))); - assert!(branch(box leaf(magenta), box leaf(cyan)) - .isEq(&branch(box leaf(magenta), box leaf(cyan)))); + assert!(branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))) + .isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))))); - assert!(!branch(box leaf(magenta), box leaf(cyan)) - .isEq(&branch(box leaf(magenta), box leaf(magenta)))); + assert!(!branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))) + .isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(magenta))))); println!("Assertions all succeeded!"); } diff --git a/src/test/ui/ufcs/ufcs-explicit-self-bad.rs b/src/test/ui/ufcs/ufcs-explicit-self-bad.rs index e836d33976a93..cb1fac0bae6ae 100644 --- a/src/test/ui/ufcs/ufcs-explicit-self-bad.rs +++ b/src/test/ui/ufcs/ufcs-explicit-self-bad.rs @@ -1,9 +1,9 @@ -#![feature(box_syntax)] - struct Foo { f: isize, } + + impl Foo { fn foo(self: isize, x: isize) -> isize { //~^ ERROR invalid `self` parameter type @@ -48,12 +48,12 @@ impl<'a, T> SomeTrait for &'a Bar { } fn main() { - let foo = box Foo { + let foo = Box::new(Foo { f: 1, - }; + }); println!("{}", foo.foo(2)); - let bar = box Bar { + let bar = Box::new(Bar { f: 1, - }; + }); println!("{} {}", bar.foo(2), bar.bar(2)); } diff --git a/src/test/ui/unboxed-closures/unboxed-closures-boxed.rs b/src/test/ui/unboxed-closures/unboxed-closures-boxed.rs index b2596e49aa78e..3f550fd04259f 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-boxed.rs +++ b/src/test/ui/unboxed-closures/unboxed-closures-boxed.rs @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] use std::ops::FnMut; fn make_adder(x: i32) -> Boxi32+'static> { - (box move |y: i32| -> i32 { x + y }) as + Box::new(move |y: i32| -> i32 { x + y }) as Boxi32+'static> } diff --git a/src/test/ui/uninhabited/uninhabited-patterns.rs b/src/test/ui/uninhabited/uninhabited-patterns.rs index 58c726d2185c4..f1573b6adf0ce 100644 --- a/src/test/ui/uninhabited/uninhabited-patterns.rs +++ b/src/test/ui/uninhabited/uninhabited-patterns.rs @@ -1,8 +1,8 @@ #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(never_type)] #![feature(exhaustive_patterns)] + #![deny(unreachable_patterns)] mod foo { diff --git a/src/test/ui/unique-object-noncopyable.rs b/src/test/ui/unique-object-noncopyable.rs index d243b8f34dbcf..2c40dfc7a4b25 100644 --- a/src/test/ui/unique-object-noncopyable.rs +++ b/src/test/ui/unique-object-noncopyable.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - trait Foo { fn f(&self); } @@ -18,8 +16,10 @@ impl Foo for Bar { } } + + fn main() { - let x = box Bar { x: 10 }; + let x = Box::new(Bar { x: 10 }); let y: Box = x as Box; let _z = y.clone(); //~ ERROR the method } diff --git a/src/test/ui/unique/unique-assign-copy.rs b/src/test/ui/unique/unique-assign-copy.rs index 194698102377e..b742973ce327d 100644 --- a/src/test/ui/unique/unique-assign-copy.rs +++ b/src/test/ui/unique/unique-assign-copy.rs @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let mut i: Box<_> = box 1; + let mut i: Box<_> = Box::new(1); // Should be a copy let mut j; j = i.clone(); diff --git a/src/test/ui/unique/unique-assign-drop.rs b/src/test/ui/unique/unique-assign-drop.rs index 32068e79df49c..e7685b589ca8e 100644 --- a/src/test/ui/unique/unique-assign-drop.rs +++ b/src/test/ui/unique/unique-assign-drop.rs @@ -1,11 +1,9 @@ // run-pass #![allow(unused_assignments)] -#![feature(box_syntax)] - pub fn main() { - let i: Box<_> = box 1; - let mut j: Box<_> = box 2; + let i: Box<_> = Box::new(1); + let mut j: Box<_> = Box::new(2); // Should drop the previous value of j j = i; assert_eq!(*j, 1); diff --git a/src/test/ui/unique/unique-assign-generic.rs b/src/test/ui/unique/unique-assign-generic.rs index 2d62ce59ad012..d4932d8333ab7 100644 --- a/src/test/ui/unique/unique-assign-generic.rs +++ b/src/test/ui/unique/unique-assign-generic.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] fn f(t: T) -> T { let t1 = t; @@ -7,6 +6,6 @@ fn f(t: T) -> T { } pub fn main() { - let t = f::>(box 100); - assert_eq!(t, box 100); + let t = f::>(Box::new(100)); + assert_eq!(t, Box::new(100)); } diff --git a/src/test/ui/unique/unique-assign.rs b/src/test/ui/unique/unique-assign.rs index 5a88df071a0b9..d598744f145b2 100644 --- a/src/test/ui/unique/unique-assign.rs +++ b/src/test/ui/unique/unique-assign.rs @@ -1,9 +1,8 @@ // run-pass #![allow(unused_mut)] -#![feature(box_syntax)] pub fn main() { let mut i: Box<_>; - i = box 1; + i = Box::new(1); assert_eq!(*i, 1); } diff --git a/src/test/ui/unique/unique-autoderef-field.rs b/src/test/ui/unique/unique-autoderef-field.rs index 0360646f1330e..64147e11f1c0c 100644 --- a/src/test/ui/unique/unique-autoderef-field.rs +++ b/src/test/ui/unique/unique-autoderef-field.rs @@ -1,11 +1,10 @@ // run-pass -#![feature(box_syntax)] struct J { j: isize } pub fn main() { - let i: Box<_> = box J { + let i: Box<_> = Box::new(J { j: 100 - }; + }); assert_eq!(i.j, 100); } diff --git a/src/test/ui/unique/unique-autoderef-index.rs b/src/test/ui/unique/unique-autoderef-index.rs index 5a3d17a84efc2..ea6598a7f6b35 100644 --- a/src/test/ui/unique/unique-autoderef-index.rs +++ b/src/test/ui/unique/unique-autoderef-index.rs @@ -1,7 +1,6 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box vec![100]; + let i: Box<_> = Box::new(vec![100]); assert_eq!((*i)[0], 100); } diff --git a/src/test/ui/unique/unique-cmp.rs b/src/test/ui/unique/unique-cmp.rs index 7bbc61d25ac78..ee05dd5a31d5b 100644 --- a/src/test/ui/unique/unique-cmp.rs +++ b/src/test/ui/unique/unique-cmp.rs @@ -1,12 +1,11 @@ // run-pass #![allow(unused_allocation)] -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; - assert_eq!(i, box 100); - assert!(i < box 101); - assert!(i <= box 100); - assert!(i > box 99); - assert!(i >= box 99); + let i: Box<_> = Box::new(100); + assert_eq!(i, Box::new(100)); + assert!(i < Box::new(101)); + assert!(i <= Box::new(100)); + assert!(i > Box::new(99)); + assert!(i >= Box::new(99)); } diff --git a/src/test/ui/unique/unique-containing-tag.rs b/src/test/ui/unique/unique-containing-tag.rs index f24b3a8645f29..6c31ae99b8eef 100644 --- a/src/test/ui/unique/unique-containing-tag.rs +++ b/src/test/ui/unique/unique-containing-tag.rs @@ -4,12 +4,10 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { enum t { t1(isize), t2(isize), } - let _x: Box<_> = box t::t1(10); + let _x: Box<_> = Box::new(t::t1(10)); /*alt *x { t1(a) { @@ -19,9 +17,9 @@ pub fn main() { }*/ /*alt x { - box t1(a) { + Box::new(t1(a) { assert_eq!(a, 10); - } + }) _ { panic!(); } }*/ } diff --git a/src/test/ui/unique/unique-create.rs b/src/test/ui/unique/unique-create.rs index 3df0f7d55fd58..c566e79620a95 100644 --- a/src/test/ui/unique/unique-create.rs +++ b/src/test/ui/unique/unique-create.rs @@ -2,10 +2,8 @@ #![allow(dead_code)] // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let _: Box<_> = box 100; + let _: Box<_> = Box::new(100); } fn vec() { diff --git a/src/test/ui/unique/unique-decl-init-copy.rs b/src/test/ui/unique/unique-decl-init-copy.rs index 6ae95949e84da..5b9576fcc7a5b 100644 --- a/src/test/ui/unique/unique-decl-init-copy.rs +++ b/src/test/ui/unique/unique-decl-init-copy.rs @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let mut i: Box<_> = box 1; + let mut i: Box<_> = Box::new(1); // Should be a copy let mut j = i.clone(); *i = 2; diff --git a/src/test/ui/unique/unique-decl-init.rs b/src/test/ui/unique/unique-decl-init.rs index 2c7b9d6054f44..1d70860c7cec0 100644 --- a/src/test/ui/unique/unique-decl-init.rs +++ b/src/test/ui/unique/unique-decl-init.rs @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 1; + let i: Box<_> = Box::new(1); let j = i; assert_eq!(*j, 1); } diff --git a/src/test/ui/unique/unique-decl-move.rs b/src/test/ui/unique/unique-decl-move.rs index 4a5ee56ea9282..21187510ff0c5 100644 --- a/src/test/ui/unique/unique-decl-move.rs +++ b/src/test/ui/unique/unique-decl-move.rs @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; + let i: Box<_> = Box::new(100); let j = i; assert_eq!(*j, 100); } diff --git a/src/test/ui/unique/unique-deref.rs b/src/test/ui/unique/unique-deref.rs index 0c6af0f7f97af..33a1e9932b5d1 100644 --- a/src/test/ui/unique/unique-deref.rs +++ b/src/test/ui/unique/unique-deref.rs @@ -1,7 +1,6 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; + let i: Box<_> = Box::new(100); assert_eq!(*i, 100); } diff --git a/src/test/ui/unique/unique-destructure.rs b/src/test/ui/unique/unique-destructure.rs index 9b9f95dfbcae6..7207ac962953e 100644 --- a/src/test/ui/unique/unique-destructure.rs +++ b/src/test/ui/unique/unique-destructure.rs @@ -1,10 +1,9 @@ // run-pass #![feature(box_patterns)] -#![feature(box_syntax)] struct Foo { a: isize, b: isize } pub fn main() { - let box Foo{a, b} = box Foo{a: 100, b: 200}; + let box Foo{ a, b } = Box::new(Foo { a: 100, b: 200 }); assert_eq!(a + b, 300); } diff --git a/src/test/ui/unique/unique-drop-complex.rs b/src/test/ui/unique/unique-drop-complex.rs index 0b7bda83b3fa1..2324f1e1a652f 100644 --- a/src/test/ui/unique/unique-drop-complex.rs +++ b/src/test/ui/unique/unique-drop-complex.rs @@ -1,8 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let _x: Box<_> = box vec![0,0,0,0,0]; + let _x: Box<_> = Box::new(vec![0,0,0,0,0]); } diff --git a/src/test/ui/unique/unique-fn-arg-move.rs b/src/test/ui/unique/unique-fn-arg-move.rs index ff33839e57ee2..6d42df218fbfd 100644 --- a/src/test/ui/unique/unique-fn-arg-move.rs +++ b/src/test/ui/unique/unique-fn-arg-move.rs @@ -1,11 +1,10 @@ // run-pass -#![feature(box_syntax)] fn f(i: Box) { assert_eq!(*i, 100); } pub fn main() { - let i = box 100; + let i = Box::new(100); f(i); } diff --git a/src/test/ui/unique/unique-fn-arg-mut.rs b/src/test/ui/unique/unique-fn-arg-mut.rs index e8bb35e4eb0cf..01510200b11b7 100644 --- a/src/test/ui/unique/unique-fn-arg-mut.rs +++ b/src/test/ui/unique/unique-fn-arg-mut.rs @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] fn f(i: &mut Box) { - *i = box 200; + *i = Box::new(200); } pub fn main() { - let mut i = box 100; + let mut i = Box::new(100); f(&mut i); assert_eq!(*i, 200); } diff --git a/src/test/ui/unique/unique-fn-arg.rs b/src/test/ui/unique/unique-fn-arg.rs index 75f2a767f59ba..b4f3bc4b294ba 100644 --- a/src/test/ui/unique/unique-fn-arg.rs +++ b/src/test/ui/unique/unique-fn-arg.rs @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] fn f(i: Box) { assert_eq!(*i, 100); } pub fn main() { - f(box 100); - let i = box 100; + f(Box::new(100)); + let i = Box::new(100); f(i); } diff --git a/src/test/ui/unique/unique-fn-ret.rs b/src/test/ui/unique/unique-fn-ret.rs index cd44cfa983661..773a9bce1adb0 100644 --- a/src/test/ui/unique/unique-fn-ret.rs +++ b/src/test/ui/unique/unique-fn-ret.rs @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] fn f() -> Box { - box 100 + Box::new(100) } pub fn main() { - assert_eq!(f(), box 100); + assert_eq!(f(), Box::new(100)); } diff --git a/src/test/ui/unique/unique-in-tag.rs b/src/test/ui/unique/unique-in-tag.rs index 8d97ebe659097..6daa06fb12de6 100644 --- a/src/test/ui/unique/unique-in-tag.rs +++ b/src/test/ui/unique/unique-in-tag.rs @@ -2,12 +2,10 @@ #![allow(dead_code)] #![allow(non_camel_case_types)] -#![feature(box_syntax)] - fn test1() { enum bar { u(Box), w(isize), } - let x = bar::u(box 10); + let x = bar::u(Box::new(10)); assert!(match x { bar::u(a) => { println!("{}", a); diff --git a/src/test/ui/unique/unique-in-vec-copy.rs b/src/test/ui/unique/unique-in-vec-copy.rs index 8907a8b20a7ae..ce52d15ef1acb 100644 --- a/src/test/ui/unique/unique-in-vec-copy.rs +++ b/src/test/ui/unique/unique-in-vec-copy.rs @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let mut a: Vec> = vec![box 10]; + let mut a: Vec> = vec![Box::new(10)]; let b = a.clone(); assert_eq!(*a[0], 10); diff --git a/src/test/ui/unique/unique-in-vec.rs b/src/test/ui/unique/unique-in-vec.rs index 528ea4fb870e8..1e8d05e3d269f 100644 --- a/src/test/ui/unique/unique-in-vec.rs +++ b/src/test/ui/unique/unique-in-vec.rs @@ -1,7 +1,6 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let vect : Vec> = vec![box 100]; - assert_eq!(vect[0], box 100); + let vect : Vec> = vec![Box::new(100)]; + assert_eq!(vect[0], Box::new(100)); } diff --git a/src/test/ui/unique/unique-init.rs b/src/test/ui/unique/unique-init.rs index c8a150522fd2e..d19605046e1bc 100644 --- a/src/test/ui/unique/unique-init.rs +++ b/src/test/ui/unique/unique-init.rs @@ -1,8 +1,6 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let _i: Box<_> = box 100; + let _i: Box<_> = Box::new(100); } diff --git a/src/test/ui/unique/unique-kinds.rs b/src/test/ui/unique/unique-kinds.rs index f369a1e2a190d..f02d0b50764ae 100644 --- a/src/test/ui/unique/unique-kinds.rs +++ b/src/test/ui/unique/unique-kinds.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(box_syntax)] use std::cmp::PartialEq; use std::fmt::Debug; @@ -14,11 +13,11 @@ fn sendable() { assert!(i != j); } - let i: Box<_> = box 100; - let j: Box<_> = box 100; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(100); f(i, j); - let i: Box<_> = box 100; - let j: Box<_> = box 101; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(101); g(i, j); } @@ -32,11 +31,11 @@ fn copyable() { assert!(i != j); } - let i: Box<_> = box 100; - let j: Box<_> = box 100; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(100); f(i, j); - let i: Box<_> = box 100; - let j: Box<_> = box 101; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(101); g(i, j); } @@ -50,11 +49,11 @@ fn noncopyable() { assert!(i != j); } - let i: Box<_> = box 100; - let j: Box<_> = box 100; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(100); f(i, j); - let i: Box<_> = box 100; - let j: Box<_> = box 101; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(101); g(i, j); } diff --git a/src/test/ui/unique/unique-log.rs b/src/test/ui/unique/unique-log.rs index 279777177061d..0715d16628f87 100644 --- a/src/test/ui/unique/unique-log.rs +++ b/src/test/ui/unique/unique-log.rs @@ -1,7 +1,6 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; + let i: Box<_> = Box::new(100); println!("{}", i); } diff --git a/src/test/ui/unique/unique-move-drop.rs b/src/test/ui/unique/unique-move-drop.rs index e1ea58b39ef50..c0f5d8f90532d 100644 --- a/src/test/ui/unique/unique-move-drop.rs +++ b/src/test/ui/unique/unique-move-drop.rs @@ -1,11 +1,10 @@ // run-pass #![allow(unused_variables)] -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; - let j: Box<_> = box 200; + let i: Box<_> = Box::new(100); + let j: Box<_> = Box::new(200); let j = i; assert_eq!(*j, 100); } diff --git a/src/test/ui/unique/unique-move-temp.rs b/src/test/ui/unique/unique-move-temp.rs index 4f5de50b722f9..103af8e1f1e02 100644 --- a/src/test/ui/unique/unique-move-temp.rs +++ b/src/test/ui/unique/unique-move-temp.rs @@ -1,9 +1,8 @@ // run-pass #![allow(unused_mut)] -#![feature(box_syntax)] pub fn main() { let mut i: Box<_>; - i = box 100; + i = Box::new(100); assert_eq!(*i, 100); } diff --git a/src/test/ui/unique/unique-move.rs b/src/test/ui/unique/unique-move.rs index 0f6bff1432b3f..40a2718e4e5f6 100644 --- a/src/test/ui/unique/unique-move.rs +++ b/src/test/ui/unique/unique-move.rs @@ -1,9 +1,8 @@ // run-pass #![allow(unused_mut)] -#![feature(box_syntax)] pub fn main() { - let i: Box<_> = box 100; + let i: Box<_> = Box::new(100); let mut j; j = i; assert_eq!(*j, 100); diff --git a/src/test/ui/unique/unique-mutable.rs b/src/test/ui/unique/unique-mutable.rs index 176cf33d4889c..0367c08099a83 100644 --- a/src/test/ui/unique/unique-mutable.rs +++ b/src/test/ui/unique/unique-mutable.rs @@ -1,8 +1,7 @@ // run-pass -#![feature(box_syntax)] pub fn main() { - let mut i: Box<_> = box 0; + let mut i: Box<_> = Box::new(0); *i = 1; assert_eq!(*i, 1); } diff --git a/src/test/ui/unique/unique-object-move.rs b/src/test/ui/unique/unique-object-move.rs index 84e8cdb32b84e..bb35a9b2d73e2 100644 --- a/src/test/ui/unique/unique-object-move.rs +++ b/src/test/ui/unique/unique-object-move.rs @@ -4,8 +4,6 @@ // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub trait EventLoop { fn foo(&self) {} } pub struct UvEventLoop { @@ -15,6 +13,6 @@ pub struct UvEventLoop { impl EventLoop for UvEventLoop { } pub fn main() { - let loop_: Box = box UvEventLoop { uvio: 0 } as Box; + let loop_: Box = Box::new(UvEventLoop { uvio: 0 }) as Box; let _loop2_ = loop_; } diff --git a/src/test/ui/unique/unique-pat-2.rs b/src/test/ui/unique/unique-pat-2.rs index c18e029b252cb..9c73fd2204c38 100644 --- a/src/test/ui/unique/unique-pat-2.rs +++ b/src/test/ui/unique/unique-pat-2.rs @@ -4,15 +4,15 @@ #![allow(non_shorthand_field_patterns)] #![feature(box_patterns)] -#![feature(box_syntax)] struct Foo {a: isize, b: usize} enum bar { u(Box), w(isize), } pub fn main() { - assert!(match bar::u(box Foo{a: 10, b: 40}) { - bar::u(box Foo{a: a, b: b}) => { a + (b as isize) } - _ => { 66 } - } == 50); + let v = match bar::u(Box::new(Foo{ a: 10, b: 40 })) { + bar::u(box Foo{ a: a, b: b }) => { a + (b as isize) } + _ => { 66 } + }; + assert_eq!(v, 50); } diff --git a/src/test/ui/unique/unique-pat-3.rs b/src/test/ui/unique/unique-pat-3.rs index e17b5a3ddb450..2e81f898d0c98 100644 --- a/src/test/ui/unique/unique-pat-3.rs +++ b/src/test/ui/unique/unique-pat-3.rs @@ -2,16 +2,15 @@ #![allow(dead_code)] #![allow(non_camel_case_types)] -#![feature(box_syntax)] - enum bar { u(Box), w(isize), } pub fn main() { - assert!(match bar::u(box 10) { - bar::u(a) => { - println!("{}", a); - *a - } - _ => { 66 } - } == 10); + let v = match bar::u(10.into()) { + bar::u(a) => { + println!("{}", a); + *a + } + _ => { 66 } + }; + assert_eq!(v, 10); } diff --git a/src/test/ui/unique/unique-pat.rs b/src/test/ui/unique/unique-pat.rs index b32195ac27421..c2474d0e77214 100644 --- a/src/test/ui/unique/unique-pat.rs +++ b/src/test/ui/unique/unique-pat.rs @@ -1,10 +1,9 @@ // run-pass #![feature(box_patterns)] -#![feature(box_syntax)] fn simple() { - match box true { + match Box::new(true) { box true => { } _ => { panic!(); } } diff --git a/src/test/ui/unique/unique-rec.rs b/src/test/ui/unique/unique-rec.rs index c8bddd246a805..9f8ad9bb05043 100644 --- a/src/test/ui/unique/unique-rec.rs +++ b/src/test/ui/unique/unique-rec.rs @@ -1,10 +1,9 @@ // run-pass -#![feature(box_syntax)] struct X { x: isize } pub fn main() { - let x: Box<_> = box X {x: 1}; + let x: Box<_> = Box::new(X {x: 1}); let bar = x; assert_eq!(bar.x, 1); } diff --git a/src/test/ui/unique/unique-send-2.rs b/src/test/ui/unique/unique-send-2.rs index 22f0e6c3a49b0..23ddd2cdca25d 100644 --- a/src/test/ui/unique/unique-send-2.rs +++ b/src/test/ui/unique/unique-send-2.rs @@ -2,13 +2,11 @@ #![allow(unused_must_use)] // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::sync::mpsc::{channel, Sender}; use std::thread; fn child(tx: &Sender>, i: usize) { - tx.send(box i).unwrap(); + tx.send(Box::new(i)).unwrap(); } pub fn main() { diff --git a/src/test/ui/unique/unique-send.rs b/src/test/ui/unique/unique-send.rs index a5c7561b9ae3c..431cc2be5d20e 100644 --- a/src/test/ui/unique/unique-send.rs +++ b/src/test/ui/unique/unique-send.rs @@ -1,11 +1,10 @@ // run-pass -#![feature(box_syntax)] use std::sync::mpsc::channel; pub fn main() { let (tx, rx) = channel::>(); - tx.send(box 100).unwrap(); + tx.send(Box::new(100)).unwrap(); let v = rx.recv().unwrap(); - assert_eq!(v, box 100); + assert_eq!(v, Box::new(100)); } diff --git a/src/test/ui/unique/unique-swap.rs b/src/test/ui/unique/unique-swap.rs index 33a6b3b3ed046..4f33ff9a8a35e 100644 --- a/src/test/ui/unique/unique-swap.rs +++ b/src/test/ui/unique/unique-swap.rs @@ -1,12 +1,11 @@ // run-pass -#![feature(box_syntax)] use std::mem::swap; pub fn main() { - let mut i: Box<_> = box 100; - let mut j: Box<_> = box 200; + let mut i: Box<_> = Box::new(100); + let mut j: Box<_> = Box::new(200); swap(&mut i, &mut j); - assert_eq!(i, box 200); - assert_eq!(j, box 100); + assert_eq!(i, Box::new(200)); + assert_eq!(j, Box::new(100)); } diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr index 95a0f4f5fabee..199d5e3727850 100644 --- a/src/test/ui/unop-move-semantics.stderr +++ b/src/test/ui/unop-move-semantics.stderr @@ -7,7 +7,7 @@ LL | !x; | -- `x` moved due to usage in operator LL | LL | x.clone(); - | ^ value borrowed here after move + | ^^^^^^^^^ value borrowed here after move | note: calling this operator moves the left-hand side --> $SRC_DIR/core/src/ops/bit.rs:LL:COL diff --git a/src/test/ui/unsized/unsized2.rs b/src/test/ui/unsized/unsized2.rs index be4406399fd0f..bbeb00d5fed60 100644 --- a/src/test/ui/unsized/unsized2.rs +++ b/src/test/ui/unsized/unsized2.rs @@ -4,7 +4,6 @@ #![allow(dead_code)] #![allow(unused_variables)] #![allow(unused_imports)] -#![feature(box_syntax)] // Test sized-ness checking in substitution. @@ -36,7 +35,7 @@ trait T2 { struct S; impl T2 for S { fn f() -> Box { - box S + Box::new(S) } } fn f5(x: &X) { @@ -51,7 +50,7 @@ trait T3 { } impl T3 for S { fn f() -> Box { - box S + Box::new(S) } } fn f7(x: &X) { diff --git a/src/test/ui/unsized/unsized3-rpass.rs b/src/test/ui/unsized/unsized3-rpass.rs index c5c5ed26c7384..4d5e89575bef6 100644 --- a/src/test/ui/unsized/unsized3-rpass.rs +++ b/src/test/ui/unsized/unsized3-rpass.rs @@ -2,7 +2,7 @@ // Test structs with always-unsized fields. #![allow(warnings)] -#![feature(box_syntax, unsize, ptr_metadata)] +#![feature(unsize, ptr_metadata)] use std::mem; use std::ptr; @@ -58,7 +58,7 @@ pub fn main() { f: [T; 3], } - let data: Box> = box Foo_ { f: [1, 2, 3] }; + let data: Box> = Box::new(Foo_ { f: [1, 2, 3] }); let x: &Foo = mem::transmute(slice::from_raw_parts(&*data, 3)); assert_eq!(x.f.len(), 3); assert_eq!(x.f[0], 1); @@ -69,7 +69,7 @@ pub fn main() { } let data: Box<_> = - box Baz_ { f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] }; + Box::new(Baz_ { f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] }); let x: &Baz = mem::transmute(slice::from_raw_parts(&*data, 5)); assert_eq!(x.f1, 42); let chs: Vec = x.f2.chars().collect(); @@ -84,9 +84,9 @@ pub fn main() { f: St, } - let obj: Box = box St { f: 42 }; + let obj: Box = Box::new(St { f: 42 }); let obj: &Tr = &*obj; - let data: Box<_> = box Qux_ { f: St { f: 234 } }; + let data: Box<_> = Box::new(Qux_ { f: St { f: 234 } }); let x: &Qux = &*ptr::from_raw_parts::((&*data as *const _).cast(), ptr::metadata(obj)); assert_eq!(x.f.foo(), 234); } diff --git a/src/test/ui/unused-move-capture.rs b/src/test/ui/unused-move-capture.rs index e9d4684736ebf..efaf10da4a99f 100644 --- a/src/test/ui/unused-move-capture.rs +++ b/src/test/ui/unused-move-capture.rs @@ -1,10 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 -#![feature(box_syntax)] - pub fn main() { - let _x: Box<_> = box 1; + let _x: Box<_> = Box::new(1); let lam_move = || {}; lam_move(); } diff --git a/src/test/ui/unused-move.rs b/src/test/ui/unused-move.rs index 37aee22f85dbb..697434d47ebb2 100644 --- a/src/test/ui/unused-move.rs +++ b/src/test/ui/unused-move.rs @@ -6,10 +6,8 @@ // pretty-expanded FIXME #23616 #![allow(path_statements)] -#![feature(box_syntax)] -pub fn main() -{ - let y: Box<_> = box 1; +pub fn main() { + let y: Box<_> = Box::new(1); y; } diff --git a/src/test/ui/unwind-unique.rs b/src/test/ui/unwind-unique.rs index ea3089e747fb5..7ca53b664ac6c 100644 --- a/src/test/ui/unwind-unique.rs +++ b/src/test/ui/unwind-unique.rs @@ -1,12 +1,10 @@ // run-pass // ignore-emscripten no threads support -#![feature(box_syntax)] - use std::thread; fn f() { - let _a: Box<_> = box 0; + let _a: Box<_> = Box::new(0); panic!(); } diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.rs b/src/test/ui/use/use-after-move-implicity-coerced-object.rs index 76487ef1c1409..47fbb5bf1c362 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.rs +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - use std::fmt; struct Number { @@ -22,9 +20,11 @@ impl List { } fn main() { - let n: Box<_> = box Number { n: 42 }; - let mut l: Box<_> = box List { list: Vec::new() }; + + let n: Box<_> = Number { n: 42 }.into(); + let mut l: Box<_> = List { list: Vec::new() }.into(); l.push(n); + let x = n.to_string(); //~^ ERROR: borrow of moved value: `n` } diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr index b3266562d14b6..0ad6d6c7c0e07 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr @@ -1,13 +1,14 @@ error[E0382]: borrow of moved value: `n` --> $DIR/use-after-move-implicity-coerced-object.rs:28:13 | -LL | let n: Box<_> = box Number { n: 42 }; +LL | let n: Box<_> = Number { n: 42 }.into(); | - move occurs because `n` has type `Box`, which does not implement the `Copy` trait -LL | let mut l: Box<_> = box List { list: Vec::new() }; +LL | let mut l: Box<_> = List { list: Vec::new() }.into(); LL | l.push(n); | - value moved here +LL | LL | let x = n.to_string(); - | ^ value borrowed here after move + | ^^^^^^^^^^^^^ value borrowed here after move error: aborting due to previous error diff --git a/src/test/ui/use/use-after-move-self.rs b/src/test/ui/use/use-after-move-self.rs index a6f6c45573d0a..f7a3c0ecce5ba 100644 --- a/src/test/ui/use/use-after-move-self.rs +++ b/src/test/ui/use/use-after-move-self.rs @@ -1,9 +1,9 @@ -#![feature(box_syntax)] - struct S { x: Box, } + + impl S { pub fn foo(self) -> isize { self.bar(); @@ -14,6 +14,6 @@ impl S { } fn main() { - let x = S { x: box 1 }; + let x = S { x: 1.into() }; println!("{}", x.foo()); } diff --git a/src/test/ui/use/use-from-trait-xc.stderr b/src/test/ui/use/use-from-trait-xc.stderr index 37b4e61c8085e..14523afbdac05 100644 --- a/src/test/ui/use/use-from-trait-xc.stderr +++ b/src/test/ui/use/use-from-trait-xc.stderr @@ -38,7 +38,7 @@ error[E0432]: unresolved import `use_from_trait_xc::Baz::new` --> $DIR/use-from-trait-xc.rs:23:5 | LL | use use_from_trait_xc::Baz::new as baznew; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `new` in `Baz` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `new` in `sub::Baz` error[E0603]: struct `Foo` is private --> $DIR/use-from-trait-xc.rs:14:24 diff --git a/src/test/ui/variance/variance-associated-types2.nll.stderr b/src/test/ui/variance/variance-associated-types2.nll.stderr index 27d1e1844167e..35871c1236fae 100644 --- a/src/test/ui/variance/variance-associated-types2.nll.stderr +++ b/src/test/ui/variance/variance-associated-types2.nll.stderr @@ -5,8 +5,6 @@ LL | fn take<'a>(_: &'a u32) { | -- lifetime `'a` defined here LL | let _: Box> = make(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` - | - = help: consider replacing `'a` with `'static` error: aborting due to previous error diff --git a/src/test/ui/variance/variance-btree-invariant-types.nll.stderr b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr index 4b653238aa750..1f06949c0331b 100644 --- a/src/test/ui/variance/variance-btree-invariant-types.nll.stderr +++ b/src/test/ui/variance/variance-btree-invariant-types.nll.stderr @@ -5,8 +5,6 @@ LL | fn iter_cov_key<'a, 'new>(v: IterMut<'a, &'static (), ()>) -> IterMut<'a, & | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:7:5 @@ -15,8 +13,6 @@ LL | fn iter_cov_val<'a, 'new>(v: IterMut<'a, (), &'static ()>) -> IterMut<'a, ( | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:10:5 @@ -25,8 +21,6 @@ LL | fn iter_contra_key<'a, 'new>(v: IterMut<'a, &'new (), ()>) -> IterMut<'a, & | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:13:5 @@ -35,8 +29,6 @@ LL | fn iter_contra_val<'a, 'new>(v: IterMut<'a, (), &'new ()>) -> IterMut<'a, ( | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:17:5 @@ -45,8 +37,6 @@ LL | fn range_cov_key<'a, 'new>(v: RangeMut<'a, &'static (), ()>) -> RangeMut<'a | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:20:5 @@ -55,8 +45,6 @@ LL | fn range_cov_val<'a, 'new>(v: RangeMut<'a, (), &'static ()>) -> RangeMut<'a | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:23:5 @@ -65,8 +53,6 @@ LL | fn range_contra_key<'a, 'new>(v: RangeMut<'a, &'new (), ()>) -> RangeMut<'a | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:26:5 @@ -75,8 +61,6 @@ LL | fn range_contra_val<'a, 'new>(v: RangeMut<'a, (), &'new ()>) -> RangeMut<'a | ---- lifetime `'new` defined here LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:31:5 @@ -86,8 +70,6 @@ LL | fn occ_cov_key<'a, 'new>(v: OccupiedEntry<'a, &'static (), ()>) LL | -> OccupiedEntry<'a, &'new (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:35:5 @@ -97,8 +79,6 @@ LL | fn occ_cov_val<'a, 'new>(v: OccupiedEntry<'a, (), &'static ()>) LL | -> OccupiedEntry<'a, (), &'new ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:39:5 @@ -108,8 +88,6 @@ LL | fn occ_contra_key<'a, 'new>(v: OccupiedEntry<'a, &'new (), ()>) LL | -> OccupiedEntry<'a, &'static (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:43:5 @@ -119,8 +97,6 @@ LL | fn occ_contra_val<'a, 'new>(v: OccupiedEntry<'a, (), &'new ()>) LL | -> OccupiedEntry<'a, (), &'static ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:48:5 @@ -130,8 +106,6 @@ LL | fn vac_cov_key<'a, 'new>(v: VacantEntry<'a, &'static (), ()>) LL | -> VacantEntry<'a, &'new (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:52:5 @@ -141,8 +115,6 @@ LL | fn vac_cov_val<'a, 'new>(v: VacantEntry<'a, (), &'static ()>) LL | -> VacantEntry<'a, (), &'new ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:56:5 @@ -152,8 +124,6 @@ LL | fn vac_contra_key<'a, 'new>(v: VacantEntry<'a, &'new (), ()>) LL | -> VacantEntry<'a, &'static (), ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: lifetime may not live long enough --> $DIR/variance-btree-invariant-types.rs:60:5 @@ -163,8 +133,6 @@ LL | fn vac_contra_val<'a, 'new>(v: VacantEntry<'a, (), &'new ()>) LL | -> VacantEntry<'a, (), &'static ()> { LL | v | ^ returning this value requires that `'new` must outlive `'static` - | - = help: consider replacing `'new` with `'static` error: aborting due to 16 previous errors diff --git a/src/test/ui/wf/hir-wf-check-erase-regions.rs b/src/test/ui/wf/hir-wf-check-erase-regions.rs index bb398e5698a80..2b4b480df0acf 100644 --- a/src/test/ui/wf/hir-wf-check-erase-regions.rs +++ b/src/test/ui/wf/hir-wf-check-erase-regions.rs @@ -1,5 +1,5 @@ // Regression test for #87549. -// compile-flags: -C incremental=tmp/wf/hir-wf-check-erase-regions +// incremental pub struct Table([Option; N]); diff --git a/src/tools/cargo b/src/tools/cargo index 0121d66aa2ef5..d56b42c549dbb 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 0121d66aa2ef5ffa9735f86c2b56f5fdc5a837a6 +Subproject commit d56b42c549dbb7e7d0f712c51b39400260d114d4 diff --git a/src/tools/clippy/.cargo/config b/src/tools/clippy/.cargo/config index 84ae36a46d71d..688473f2f9bfc 100644 --- a/src/tools/clippy/.cargo/config +++ b/src/tools/clippy/.cargo/config @@ -1,9 +1,10 @@ [alias] uitest = "test --test compile-test" -dev = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" -lintcheck = "run --target-dir lintcheck/target --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " +dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" +lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored" [build] # -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"] +target-dir = "target" diff --git a/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md b/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md index 2891d5e5da1e1..866303a1f9fd5 100644 --- a/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md +++ b/src/tools/clippy/.github/ISSUE_TEMPLATE/blank_issue.md @@ -8,7 +8,7 @@ about: Create a blank issue. Additional labels can be added to this issue by including the following command (without the space after the @ symbol): -`@rustbot label +

` (where P is one \ of the previous types except `Self`)"; @@ -1290,10 +1204,10 @@ fn receiver_is_implemented( cause: ObligationCause<'tcx>, receiver_ty: Ty<'tcx>, ) -> bool { - let trait_ref = ty::TraitRef { + let trait_ref = ty::Binder::dummy(ty::TraitRef { def_id: receiver_trait_def_id, substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]), - }; + }); let obligation = traits::Obligation::new( cause, @@ -1439,20 +1353,23 @@ impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> { hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir()) } + #[instrument(skip(self, i), level = "debug")] fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - debug!("visit_item: {:?}", i); + trace!(?i); self.tcx.ensure().check_item_well_formed(i.def_id); hir_visit::walk_item(self, i); } + #[instrument(skip(self, trait_item), level = "debug")] fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { - debug!("visit_trait_item: {:?}", trait_item); + trace!(?trait_item); self.tcx.ensure().check_trait_item_well_formed(trait_item.def_id); hir_visit::walk_trait_item(self, trait_item); } + #[instrument(skip(self, impl_item), level = "debug")] fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { - debug!("visit_impl_item: {:?}", impl_item); + trace!(?impl_item); self.tcx.ensure().check_impl_item_well_formed(impl_item.def_id); hir_visit::walk_impl_item(self, impl_item); } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index c57ec9ef78f68..d951df94dcf50 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -140,7 +140,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // operating on scalars, we clear the overload. fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) { match e.kind { - hir::ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, ref inner) => { + hir::ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, inner) => { let inner_ty = self.fcx.node_ty(inner.hir_id); let inner_ty = self.fcx.resolve_vars_if_possible(inner_ty); @@ -150,8 +150,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { typeck_results.node_substs_mut().remove(e.hir_id); } } - hir::ExprKind::Binary(ref op, ref lhs, ref rhs) - | hir::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => { + hir::ExprKind::Binary(ref op, lhs, rhs) | hir::ExprKind::AssignOp(ref op, lhs, rhs) => { let lhs_ty = self.fcx.node_ty(lhs.hir_id); let lhs_ty = self.fcx.resolve_vars_if_possible(lhs_ty); @@ -198,7 +197,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // All valid indexing looks like this; might encounter non-valid indexes at this point. let base_ty = typeck_results - .expr_ty_adjusted_opt(&base) + .expr_ty_adjusted_opt(base) .map(|t| self.fcx.resolve_vars_if_possible(t).kind()); if base_ty.is_none() { // When encountering `return [0][0]` outside of a `fn` body we can encounter a base @@ -207,7 +206,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { self.tcx().sess.delay_span_bug(e.span, &format!("bad base: `{:?}`", base)); } if let Some(ty::Ref(_, base_ty, _)) = base_ty { - let index_ty = typeck_results.expr_ty_adjusted_opt(&index).unwrap_or_else(|| { + let index_ty = typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| { // When encountering `return [0][0]` outside of a `fn` body we would attempt // to access an unexistend index. We assume that more relevant errors will // already have been emitted, so we only gate on this with an ICE if no @@ -497,6 +496,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fcx_typeck_results.generator_interior_types.clone(); } + #[instrument(skip(self, span), level = "debug")] fn visit_opaque_types(&mut self, span: Span) { let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone(); for (opaque_type_key, opaque_defn) in opaque_types { @@ -564,6 +564,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + #[instrument(skip(self, span), level = "debug")] fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) { // Export associated path extensions and method resolutions. if let Some(def) = @@ -579,7 +580,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let n_ty = self.fcx.node_ty(hir_id); let n_ty = self.resolve(n_ty, &span); self.write_ty_to_typeck_results(hir_id, n_ty); - debug!("node {:?} has type {:?}", hir_id, n_ty); + debug!(?n_ty); // Resolve any substitutions if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) { @@ -590,31 +591,33 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + #[instrument(skip(self, span), level = "debug")] fn visit_adjustments(&mut self, span: Span, hir_id: hir::HirId) { let adjustment = self.fcx.typeck_results.borrow_mut().adjustments_mut().remove(hir_id); match adjustment { None => { - debug!("no adjustments for node {:?}", hir_id); + debug!("no adjustments for node"); } Some(adjustment) => { let resolved_adjustment = self.resolve(adjustment, &span); - debug!("adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); + debug!(?resolved_adjustment); self.typeck_results.adjustments_mut().insert(hir_id, resolved_adjustment); } } } + #[instrument(skip(self, span), level = "debug")] fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) { let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id); match adjustment { None => { - debug!("no pat_adjustments for node {:?}", hir_id); + debug!("no pat_adjustments for node"); } Some(adjustment) => { let resolved_adjustment = self.resolve(adjustment, &span); - debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment); + debug!(?resolved_adjustment); self.typeck_results.pat_adjustments_mut().insert(hir_id, resolved_adjustment); } } @@ -732,6 +735,26 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { } } +struct EraseEarlyRegions<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) { + ty.super_fold_with(self) + } else { + ty + } + } + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased } + } +} + impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx @@ -739,7 +762,13 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match self.infcx.fully_resolve(t) { - Ok(t) => self.infcx.tcx.erase_regions(t), + Ok(t) => { + // Do not anonymize late-bound regions + // (e.g. keep `for<'a>` named `for<'a>`). + // This allows NLL to generate error messages that + // refer to the higher-ranked lifetime names written by the user. + EraseEarlyRegions { tcx: self.infcx.tcx }.fold_ty(t) + } Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); self.report_type_error(t); diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs index cb127880c62b3..89ce3700aadcd 100644 --- a/compiler/rustc_typeck/src/check_unused.rs +++ b/compiler/rustc_typeck/src/check_unused.rs @@ -9,14 +9,14 @@ use rustc_span::{Span, Symbol}; pub fn check_crate(tcx: TyCtxt<'_>) { let mut used_trait_imports = FxHashSet::default(); - for item_def_id in tcx.body_owners() { + for item_def_id in tcx.hir().body_owners() { let imports = tcx.used_trait_imports(item_def_id); debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); used_trait_imports.extend(imports.iter()); } let mut visitor = CheckVisitor { tcx, used_trait_imports }; - tcx.hir().krate().visit_all_item_likes(&mut visitor); + tcx.hir().visit_all_item_likes(&mut visitor); unused_crates_lint(tcx); } @@ -26,7 +26,7 @@ impl ItemLikeVisitor<'v> for CheckVisitor<'tcx> { if item.vis.node.is_pub() || item.span.is_dummy() { return; } - if let hir::ItemKind::Use(ref path, _) = item.kind { + if let hir::ItemKind::Use(path, _) = item.kind { self.check_import(item.item_id(), path.span); } } @@ -111,7 +111,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { // Collect all the extern crates (in a reliable order). let mut crates_to_lint = vec![]; - tcx.hir().krate().visit_all_item_likes(&mut CollectExternCrateVisitor { + tcx.hir().visit_all_item_likes(&mut CollectExternCrateVisitor { crates_to_lint: &mut crates_to_lint, }); diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index f3fe09ac0033d..6a9ba9d49134c 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -17,9 +17,8 @@ use rustc_span::Span; /// On-demand query: yields a map containing all types mapped to their inherent impls. pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls { - let krate = tcx.hir().krate(); let mut collect = InherentCollect { tcx, impls_map: Default::default() }; - krate.visit_all_item_likes(&mut collect); + tcx.hir().visit_all_item_likes(&mut collect); collect.impls_map } @@ -57,7 +56,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { ty::Foreign(did) => { self.check_def_id(item, did); } - ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => { + ty::Dynamic(data, ..) if data.principal_def_id().is_some() => { self.check_def_id(item, data.principal_def_id().unwrap()); } ty::Dynamic(..) => { @@ -411,7 +410,7 @@ impl InherentCollect<'tcx> { // OK } _ => { - let to_implement = if assoc_items.len() == 0 { + let to_implement = if assoc_items.is_empty() { String::new() } else { let plural = assoc_items.len() > 1; diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs index 1c36335be8167..b5eb74f708d5c 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs @@ -10,8 +10,7 @@ use smallvec::SmallVec; use std::collections::hash_map::Entry; pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) { - let krate = tcx.hir().krate(); - krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx }); + tcx.hir().visit_all_item_likes(&mut InherentOverlapChecker { tcx }); } struct InherentOverlapChecker<'tcx> { @@ -188,7 +187,7 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> { .collect::>(); match ids.len() { 0 | 1 => { - let id_to_set = if ids.len() == 0 { + let id_to_set = if ids.is_empty() { // Create a new connected region let region = ConnectedRegion { idents: idents_to_add, diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs index 7ac26a31872df..079604f128d43 100644 --- a/compiler/rustc_typeck/src/coherence/mod.rs +++ b/compiler/rustc_typeck/src/coherence/mod.rs @@ -221,7 +221,7 @@ fn check_object_overlap<'tcx>( } // check for overlap with the automatic `impl Trait for dyn Trait` - if let ty::Dynamic(ref data, ..) = trait_ref.self_ty().kind() { + if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() { // This is something like impl Trait1 for Trait2. Illegal // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 05932427bcf7a..0326d1fd74f62 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -10,7 +10,7 @@ use rustc_trait_selection::traits; pub fn check(tcx: TyCtxt<'_>) { let mut orphan = OrphanChecker { tcx }; - tcx.hir().krate().visit_all_item_likes(&mut orphan); + tcx.hir().visit_all_item_likes(&mut orphan); } struct OrphanChecker<'tcx> { diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs index 6b995b9738612..e7b03fa3ac68a 100644 --- a/compiler/rustc_typeck/src/coherence/unsafety.rs +++ b/compiler/rustc_typeck/src/coherence/unsafety.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::TyCtxt; pub fn check(tcx: TyCtxt<'_>) { let mut unsafety = UnsafetyChecker { tcx }; - tcx.hir().krate().visit_all_item_likes(&mut unsafety); + tcx.hir().visit_all_item_likes(&mut unsafety); } struct UnsafetyChecker<'tcx> { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 1bc7bc3e063d4..f21c5c760ea50 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -40,7 +40,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt}; use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness}; use rustc_session::lint; use rustc_session::parse::feature_err; @@ -199,20 +199,16 @@ crate fn placeholder_type_error( let parent_id = tcx.hir().get_parent_node(hir_ty.hir_id); let parent_node = tcx.hir().get(parent_id); - is_const_or_static = match parent_node { + is_const_or_static = matches!( + parent_node, Node::Item(&hir::Item { kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), .. - }) - | Node::TraitItem(&hir::TraitItem { + }) | Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. - }) - | Node::ImplItem(&hir::ImplItem { - kind: hir::ImplItemKind::Const(..), .. - }) => true, - _ => false, - }; + }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) + ); } } @@ -681,10 +677,10 @@ impl ItemCtxt<'tcx> { _ => None, }) .flat_map(|bp| { - let bt = if is_param(self.tcx, &bp.bounded_ty, param_id) { + let bt = if is_param(self.tcx, bp.bounded_ty, param_id) { Some(ty) } else if !only_self_bounds.0 { - Some(self.to_ty(&bp.bounded_ty)) + Some(self.to_ty(bp.bounded_ty)) } else { None }; @@ -723,7 +719,7 @@ impl ItemCtxt<'tcx> { /// `ast_ty_to_ty`, because we want to avoid triggering an all-out /// conversion of the type to avoid inducing unnecessary cycles. fn is_param(tcx: TyCtxt<'_>, ast_ty: &hir::Ty<'_>, param_id: hir::HirId) -> bool { - if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = ast_ty.kind { + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ast_ty.kind { match path.res { Res::SelfTy(Some(def_id), None) | Res::Def(DefKind::TyParam, def_id) => { def_id == tcx.hir().local_def_id(param_id).to_def_id() @@ -776,7 +772,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); tcx.ensure().predicates_of(def_id); - convert_enum_variant_types(tcx, def_id.to_def_id(), &enum_definition.variants); + convert_enum_variant_types(tcx, def_id.to_def_id(), enum_definition.variants); } hir::ItemKind::Impl { .. } => { tcx.ensure().generics_of(def_id); @@ -1153,11 +1149,11 @@ fn super_predicates_that_define_assoc_type( >::compute_bounds_that_match_assoc_type( &icx, self_param_ty, - &bounds, + bounds, assoc_name, ) } else { - >::compute_bounds(&icx, self_param_ty, &bounds) + >::compute_bounds(&icx, self_param_ty, bounds) }; let superbounds1 = superbounds1.predicates(tcx, self_param_ty); @@ -1334,25 +1330,25 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option match item.kind { hir::TraitItemKind::Fn(ref sig, _) => { - has_late_bound_regions(tcx, &item.generics, &sig.decl) + has_late_bound_regions(tcx, &item.generics, sig.decl) } _ => None, }, Node::ImplItem(item) => match item.kind { hir::ImplItemKind::Fn(ref sig, _) => { - has_late_bound_regions(tcx, &item.generics, &sig.decl) + has_late_bound_regions(tcx, &item.generics, sig.decl) } _ => None, }, Node::ForeignItem(item) => match item.kind { - hir::ForeignItemKind::Fn(ref fn_decl, _, ref generics) => { + hir::ForeignItemKind::Fn(fn_decl, _, ref generics) => { has_late_bound_regions(tcx, generics, fn_decl) } _ => None, }, Node::Item(item) => match item.kind { hir::ItemKind::Fn(ref sig, .., ref generics, _) => { - has_late_bound_regions(tcx, generics, &sig.decl) + has_late_bound_regions(tcx, generics, sig.decl) } _ => None, }, @@ -1374,7 +1370,7 @@ impl<'v> Visitor<'v> for AnonConstInParamTyDetector { } fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { - if let GenericParamKind::Const { ref ty, default: _ } = p.kind { + if let GenericParamKind::Const { ty, default: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; self.visit_ty(ty); @@ -1587,7 +1583,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let mut own_start = has_self as u32; let parent_count = parent_def_id.map_or(0, |def_id| { let generics = tcx.generics_of(def_id); - assert_eq!(has_self, false); + assert!(!has_self); parent_has_self = generics.has_self; own_start = generics.count() as u32; generics.parent_count + generics.params.len() @@ -1738,9 +1734,9 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool { } pub fn get_infer_ret_ty(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> { - if let hir::FnRetTy::Return(ref ty) = output { + if let hir::FnRetTy::Return(ty) = output { if is_suggestable_infer_ty(ty) { - return Some(&**ty); + return Some(&*ty); } } None @@ -1810,8 +1806,8 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { hir_id, sig.header.unsafety, sig.header.abi, - &sig.decl, - &generics, + sig.decl, + generics, Some(ident.span), None, ), @@ -1829,15 +1825,13 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { header.unsafety, header.abi, decl, - &generics, + generics, Some(ident.span), None, ), ForeignItem(&hir::ForeignItem { - kind: ForeignItemKind::Fn(ref fn_decl, _, _), - ident, - .. + kind: ForeignItemKind::Fn(fn_decl, _, _), ident, .. }) => { let abi = tcx.hir().get_foreign_abi(hir_id); compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi, ident) @@ -2042,7 +2036,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP match item.kind { ItemKind::Impl(ref impl_) => { if impl_.defaultness.is_default() { - is_default_impl_trait = tcx.impl_trait_ref(def_id); + is_default_impl_trait = tcx.impl_trait_ref(def_id).map(ty::Binder::dummy); } &impl_.generics } @@ -2122,10 +2116,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { - predicates.insert(( - trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx), - tcx.def_span(def_id), - )); + predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id))); } // Collect the region predicates that were declared inline as @@ -2144,7 +2135,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP GenericParamKind::Lifetime { .. } => { param.bounds.iter().for_each(|bound| match bound { hir::GenericBound::Outlives(lt) => { - let bound = >::ast_region_to_region(&icx, <, None); + let bound = >::ast_region_to_region(&icx, lt, None); let outlives = ty::Binder::dummy(ty::OutlivesPredicate(region, bound)); predicates.insert((outlives.to_predicate(tcx), lt.span)); } @@ -2166,12 +2157,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP let param_ty = ty::ParamTy::new(index, name).to_ty(tcx); index += 1; - let mut bounds = >::compute_bounds(&icx, param_ty, ¶m.bounds); + let mut bounds = >::compute_bounds(&icx, param_ty, param.bounds); // Params are implicitly sized unless a `?Sized` bound is found >::add_implicitly_sized( &icx, &mut bounds, - ¶m.bounds, + param.bounds, Some((param.hir_id, ast_generics.where_clause.predicates)), param.span, ); @@ -2190,7 +2181,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP for predicate in where_clause.predicates { match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { - let ty = icx.to_ty(&bound_pred.bounded_ty); + let ty = icx.to_ty(bound_pred.bounded_ty); let bound_vars = icx.tcx.late_bound_vars(bound_pred.bounded_ty.hir_id); // Keep the type around in a dummy predicate, in case of no bounds. @@ -2238,8 +2229,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } _ => bug!(), }; - let pred = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) - .to_predicate(icx.tcx); + let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives( + ty::OutlivesPredicate(r1, r2), + )) + .to_predicate(icx.tcx); (pred, span) })) @@ -2304,7 +2297,8 @@ fn const_evaluatable_predicates_of<'tcx>( assert_eq!(uv.promoted, None); let span = self.tcx.hir().span(c.hir_id); self.preds.insert(( - ty::PredicateKind::ConstEvaluatable(uv.shrink()).to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink())) + .to_predicate(self.tcx), span, )); } @@ -2408,7 +2402,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat } else { if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) { + if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() { // In `generics_of` we set the generics' parent to be our parent's parent which means that // we lose out on the predicates of our actual parent if we dont return those predicates here. // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) @@ -2501,10 +2495,10 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( } }; for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) { - check(&input, ty) + check(input, ty) } if let hir::FnRetTy::Return(ref ty) = decl.output { - check(&ty, fty.output().skip_binder()) + check(ty, fty.output().skip_binder()) } } @@ -2559,7 +2553,7 @@ fn from_target_feature( let msg = "malformed `target_feature` attribute input"; let code = "enable = \"..\"".to_owned(); tcx.sess - .struct_span_err(span, &msg) + .struct_span_err(span, msg) .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders) .emit(); }; @@ -2778,10 +2772,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } else if attr.has_name(sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; } else if attr.has_name(sym::track_caller) { - if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust { + if !tcx.is_closure(id) && tcx.fn_sig(id).abi() != abi::Abi::Rust { struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") .emit(); } + if tcx.is_closure(id) && !tcx.features().closure_track_caller { + feature_err( + &tcx.sess.parse_sess, + sym::closure_track_caller, + attr.span, + "`#[track_caller]` on closures is currently unstable", + ) + .emit(); + } codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } else if attr.has_name(sym::export_name) { if let Some(s) = attr.value_str() { @@ -2835,7 +2838,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { tcx, id, attr, - &supported_target_features, + supported_target_features, &mut codegen_fn_attrs.target_features, ); } else if attr.has_name(sym::linkage) { @@ -3102,7 +3105,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } let check_name = |attr: &Attribute, sym| attr.has_name(sym); - if let Some(name) = weak_lang_items::link_name(check_name, &attrs) { + if let Some(name) = weak_lang_items::link_name(check_name, attrs) { codegen_fn_attrs.export_name = Some(name); codegen_fn_attrs.link_name = Some(name); } diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index 2bc048ac8a0e9..26cad8fb18058 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -26,9 +26,9 @@ fn associated_type_bounds<'tcx>( ); let icx = ItemCtxt::new(tcx, assoc_item_def_id); - let mut bounds = >::compute_bounds(&icx, item_ty, &ast_bounds); + let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds); // Associated types are implicitly sized unless a `?Sized` bound is found - >::add_implicitly_sized(&icx, &mut bounds, &ast_bounds, None, span); + >::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span); let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id(); let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local()); @@ -64,9 +64,9 @@ fn opaque_type_bounds<'tcx>( tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id)); let icx = ItemCtxt::new(tcx, opaque_def_id); - let mut bounds = >::compute_bounds(&icx, item_ty, &ast_bounds); + let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds); // Opaque types are implicitly sized unless a `?Sized` bound is found - >::add_implicitly_sized(&icx, &mut bounds, &ast_bounds, None, span); + >::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span); let bounds = bounds.predicates(tcx, item_ty); debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds); diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 7f9afaae0eaa2..cee3679d0a052 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, ErrorReported, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -7,7 +6,7 @@ use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, Node}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef}; +use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::symbol::Ident; @@ -313,7 +312,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) } - TraitItemKind::Const(ref ty, body_id) => body_id + TraitItemKind::Const(ty, body_id) => body_id .and_then(|body_id| { if is_suggestable_infer_ty(ty) { Some(infer_placeholder_type( @@ -324,7 +323,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } }) .unwrap_or_else(|| icx.to_ty(ty)), - TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty), + TraitItemKind::Type(_, Some(ty)) => icx.to_ty(ty), TraitItemKind::Type(_, None) => { span_bug!(item.span, "associated type missing default"); } @@ -335,14 +334,14 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) } - ImplItemKind::Const(ref ty, body_id) => { + ImplItemKind::Const(ty, body_id) => { if is_suggestable_infer_ty(ty) { infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant") } else { icx.to_ty(ty) } } - ImplItemKind::TyAlias(ref ty) => { + ImplItemKind::TyAlias(ty) => { if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id).to_def_id()).is_none() { check_feature_inherent_assoc_ty(tcx, item.span); } @@ -353,7 +352,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Item(item) => { match item.kind { - ItemKind::Static(ref ty, .., body_id) => { + ItemKind::Static(ty, .., body_id) => { if is_suggestable_infer_ty(ty) { infer_placeholder_type( tcx, @@ -367,7 +366,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { icx.to_ty(ty) } } - ItemKind::Const(ref ty, body_id) => { + ItemKind::Const(ty, body_id) => { if is_suggestable_infer_ty(ty) { infer_placeholder_type( tcx, def_id, body_id, ty.span, item.ident, "constant", @@ -376,8 +375,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { icx.to_ty(ty) } } - ItemKind::TyAlias(ref self_ty, _) - | ItemKind::Impl(hir::Impl { ref self_ty, .. }) => icx.to_ty(self_ty), + ItemKind::TyAlias(self_ty, _) + | ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(self_ty), ItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) @@ -396,7 +395,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { .mir_borrowck(owner.expect_local()) .concrete_opaque_types .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id()) - .map(|concrete_ty| *concrete_ty) + .copied() .unwrap_or_else(|| { tcx.sess.delay_span_bug( DUMMY_SP, @@ -447,7 +446,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) } - ForeignItemKind::Static(ref t, _) => icx.to_ty(t), + ForeignItemKind::Static(t, _) => icx.to_ty(t), ForeignItemKind::Type => tcx.mk_foreign(def_id.to_def_id()), }, @@ -461,7 +460,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } }, - Node::Field(field) => icx.to_ty(&field.ty), + Node::Field(field) => icx.to_ty(field.ty), Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); @@ -539,6 +538,25 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } #[instrument(skip(tcx), level = "debug")] +/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions +/// laid for "higher-order pattern unification". +/// This ensures that inference is tractable. +/// In particular, definitions of opaque types can only use other generics as arguments, +/// and they cannot repeat an argument. Example: +/// +/// ```rust +/// type Foo = impl Bar; +/// +/// // Okay -- `Foo` is applied to two distinct, generic types. +/// fn a() -> Foo { .. } +/// +/// // Not okay -- `Foo` is applied to `T` twice. +/// fn b() -> Foo { .. } +/// +/// // Not okay -- `Foo` is applied to a non-generic type. +/// fn b() -> Foo { .. } +/// ``` +/// fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { use rustc_hir::{Expr, ImplItem, Item, TraitItem}; @@ -584,50 +602,8 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { // FIXME(oli-obk): trace the actual span from inference to improve errors. let span = self.tcx.def_span(def_id); - // HACK(eddyb) this check shouldn't be needed, as `wfcheck` - // performs the same checks, in theory, but I've kept it here - // using `delay_span_bug`, just in case `wfcheck` slips up. - let opaque_generics = self.tcx.generics_of(self.def_id); - let mut used_params: FxHashSet<_> = FxHashSet::default(); - 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) => { - matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) - } - GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)), - }; - - if arg_is_param { - if !used_params.insert(arg) { - // There was already an entry for `arg`, meaning a generic parameter - // was used twice. - self.tcx.sess.delay_span_bug( - span, - &format!( - "defining opaque type use restricts opaque \ - type by using the generic parameter `{}` twice", - arg, - ), - ); - } - } else { - let param = opaque_generics.param_at(i, self.tcx); - self.tcx.sess.delay_span_bug( - span, - &format!( - "defining opaque type use does not fully define opaque type: \ - generic parameter `{}` is specified as concrete {} `{}`", - param.name, - param.kind.descr(), - arg, - ), - ); - } - } - if let Some((prev_span, prev_ty)) = self.found { - if *concrete_type != prev_ty { + if *concrete_type != prev_ty && !(*concrete_type, prev_ty).references_error() { debug!(?span); // Found different concrete types for the opaque type. let mut err = self.tcx.sess.struct_span_err( @@ -709,9 +685,9 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { // // requires us to explicitly process `foo()` in order // to notice the defining usage of `Blah`. - Node::Item(ref it) => locator.visit_item(it), - Node::ImplItem(ref it) => locator.visit_impl_item(it), - Node::TraitItem(ref it) => locator.visit_trait_item(it), + Node::Item(it) => locator.visit_item(it), + Node::ImplItem(it) => locator.visit_impl_item(it), + Node::TraitItem(it) => locator.visit_trait_item(it), other => bug!("{:?} is not a valid scope for an opaque type item", other), } } @@ -776,29 +752,31 @@ fn infer_placeholder_type<'a>( // us to improve in typeck so we do that now. match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { Some(mut err) => { - // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. - // We are typeck and have the real type, so remove that and suggest the actual type. - err.suggestions.clear(); - - // Suggesting unnameable types won't help. - let mut mk_nameable = MakeNameable::new(tcx); - let ty = mk_nameable.fold_ty(ty); - let sugg_ty = if mk_nameable.success { Some(ty) } else { None }; - if let Some(sugg_ty) = sugg_ty { - err.span_suggestion( - span, - &format!("provide a type for the {item}", item = kind), - format!("{}: {}", item_ident, sugg_ty), - Applicability::MachineApplicable, - ); - } else { - err.span_note( - tcx.hir().body(body_id).value.span, - &format!("however, the inferred type `{}` cannot be named", ty.to_string()), - ); + if !ty.references_error() { + // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. + // We are typeck and have the real type, so remove that and suggest the actual type. + err.suggestions.clear(); + + // Suggesting unnameable types won't help. + let mut mk_nameable = MakeNameable::new(tcx); + let ty = mk_nameable.fold_ty(ty); + let sugg_ty = if mk_nameable.success { Some(ty) } else { None }; + if let Some(sugg_ty) = sugg_ty { + err.span_suggestion( + span, + &format!("provide a type for the {item}", item = kind), + format!("{}: {}", item_ident, sugg_ty), + Applicability::MachineApplicable, + ); + } else { + err.span_note( + tcx.hir().body(body_id).value.span, + &format!("however, the inferred type `{}` cannot be named", ty.to_string()), + ); + } } - err.emit_unless(ty.references_error()); + err.emit(); } None => { let mut diag = bad_placeholder_type(tcx, vec![span], kind); diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 9b6f0be47caf5..88877ad78525a 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -206,7 +206,7 @@ pub fn setup_constraining_predicates<'tcx>( // Then the projection only applies if `T` is known, but it still // does not determine `U`. let inputs = parameters_for(tcx, &projection.projection_ty, true); - let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); + let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p)); if !relies_only_on_inputs { continue; } diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index ba70006fe96b3..7d0600b99e36e 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -124,12 +124,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub fn consume_body(&mut self, body: &hir::Body<'_>) { for param in body.params { - let param_ty = return_if_err!(self.mc.pat_ty_adjusted(¶m.pat)); + let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat)); debug!("consume_body: param_ty = {:?}", param_ty); let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty); - self.walk_irrefutable_pat(¶m_place, ¶m.pat); + self.walk_irrefutable_pat(¶m_place, param.pat); } self.consume_expr(&body.value); @@ -145,7 +145,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) { for expr in exprs { - self.consume_expr(&expr); + self.consume_expr(expr); } } @@ -184,57 +184,57 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { match expr.kind { hir::ExprKind::Path(_) => {} - hir::ExprKind::Type(ref subexpr, _) => self.walk_expr(subexpr), + hir::ExprKind::Type(subexpr, _) => self.walk_expr(subexpr), - hir::ExprKind::Unary(hir::UnOp::Deref, ref base) => { + hir::ExprKind::Unary(hir::UnOp::Deref, base) => { // *base self.select_from_expr(base); } - hir::ExprKind::Field(ref base, _) => { + hir::ExprKind::Field(base, _) => { // base.f self.select_from_expr(base); } - hir::ExprKind::Index(ref lhs, ref rhs) => { + hir::ExprKind::Index(lhs, rhs) => { // lhs[rhs] self.select_from_expr(lhs); self.consume_expr(rhs); } - hir::ExprKind::Call(ref callee, ref args) => { + hir::ExprKind::Call(callee, args) => { // callee(args) self.consume_expr(callee); self.consume_exprs(args); } - hir::ExprKind::MethodCall(.., ref args, _) => { + hir::ExprKind::MethodCall(.., args, _) => { // callee.m(args) self.consume_exprs(args); } - hir::ExprKind::Struct(_, ref fields, ref opt_with) => { + hir::ExprKind::Struct(_, fields, ref opt_with) => { self.walk_struct_expr(fields, opt_with); } - hir::ExprKind::Tup(ref exprs) => { + hir::ExprKind::Tup(exprs) => { self.consume_exprs(exprs); } hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => { - self.consume_expr(&cond_expr); - self.consume_expr(&then_expr); + self.consume_expr(cond_expr); + self.consume_expr(then_expr); if let Some(ref else_expr) = *opt_else_expr { - self.consume_expr(&else_expr); + self.consume_expr(else_expr); } } - hir::ExprKind::Let(ref pat, ref expr, _) => { - self.walk_local(expr, pat, |t| t.borrow_expr(&expr, ty::ImmBorrow)); + hir::ExprKind::Let(pat, ref expr, _) => { + self.walk_local(expr, pat, |t| t.borrow_expr(expr, ty::ImmBorrow)); } hir::ExprKind::Match(ref discr, arms, _) => { - let discr_place = return_if_err!(self.mc.cat_expr(&discr)); + let discr_place = return_if_err!(self.mc.cat_expr(discr)); // Matching should not always be considered a use of the place, hence // discr does not necessarily need to be borrowed. @@ -243,7 +243,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self; let mut needs_to_be_read = false; for arm in arms.iter() { - return_if_err!(mc.cat_pattern(discr_place.clone(), &arm.pat, |place, pat| { + return_if_err!(mc.cat_pattern(discr_place.clone(), arm.pat, |place, pat| { match &pat.kind { PatKind::Binding(.., opt_sub_pat) => { // If the opt_sub_pat is None, than the binding does not count as @@ -303,7 +303,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } if needs_to_be_read { - self.borrow_expr(&discr, ty::ImmBorrow); + self.borrow_expr(discr, ty::ImmBorrow); } else { let closure_def_id = match discr_place.place.base { PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()), @@ -318,7 +318,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // We always want to walk the discriminant. We want to make sure, for instance, // that the discriminant has been initialized. - self.walk_expr(&discr); + self.walk_expr(discr); } // treatment of the discriminant is handled while walking the arms. @@ -327,7 +327,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } - hir::ExprKind::Array(ref exprs) => { + hir::ExprKind::Array(exprs) => { self.consume_exprs(exprs); } @@ -336,10 +336,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: let bk = ty::BorrowKind::from_mutbl(m); - self.borrow_expr(&base, bk); + self.borrow_expr(base, bk); } - hir::ExprKind::InlineAsm(ref asm) => { + hir::ExprKind::InlineAsm(asm) => { for (op, _op_sp) in asm.operands { match op { hir::InlineAsmOperand::In { expr, .. } @@ -360,7 +360,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } - hir::ExprKind::LlvmInlineAsm(ref ia) => { + hir::ExprKind::LlvmInlineAsm(ia) => { for (o, output) in iter::zip(&ia.inner.outputs, ia.outputs_exprs) { if o.is_indirect { self.consume_expr(output); @@ -368,7 +368,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.mutate_expr(output); } } - self.consume_exprs(&ia.inputs_exprs); + self.consume_exprs(ia.inputs_exprs); } hir::ExprKind::Continue(..) @@ -376,43 +376,43 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err => {} - hir::ExprKind::Loop(ref blk, ..) => { + hir::ExprKind::Loop(blk, ..) => { self.walk_block(blk); } - hir::ExprKind::Unary(_, ref lhs) => { + hir::ExprKind::Unary(_, lhs) => { self.consume_expr(lhs); } - hir::ExprKind::Binary(_, ref lhs, ref rhs) => { + hir::ExprKind::Binary(_, lhs, rhs) => { self.consume_expr(lhs); self.consume_expr(rhs); } - hir::ExprKind::Block(ref blk, _) => { + hir::ExprKind::Block(blk, _) => { self.walk_block(blk); } hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => { - if let Some(ref expr) = *opt_expr { + if let Some(expr) = *opt_expr { self.consume_expr(expr); } } - hir::ExprKind::Assign(ref lhs, ref rhs, _) => { + hir::ExprKind::Assign(lhs, rhs, _) => { self.mutate_expr(lhs); self.consume_expr(rhs); } - hir::ExprKind::Cast(ref base, _) => { + hir::ExprKind::Cast(base, _) => { self.consume_expr(base); } - hir::ExprKind::DropTemps(ref expr) => { + hir::ExprKind::DropTemps(expr) => { self.consume_expr(expr); } - hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => { + hir::ExprKind::AssignOp(_, lhs, rhs) => { if self.mc.typeck_results.is_method_call(expr) { self.consume_expr(lhs); } else { @@ -421,7 +421,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_expr(rhs); } - hir::ExprKind::Repeat(ref base, _) => { + hir::ExprKind::Repeat(base, _) => { self.consume_expr(base); } @@ -433,7 +433,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_expr(base); } - hir::ExprKind::Yield(ref value, _) => { + hir::ExprKind::Yield(value, _) => { self.consume_expr(value); } } @@ -441,7 +441,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) { match stmt.kind { - hir::StmtKind::Local(hir::Local { pat, init: Some(ref expr), .. }) => { + hir::StmtKind::Local(hir::Local { pat, init: Some(expr), .. }) => { self.walk_local(expr, pat, |_| {}); } @@ -453,7 +453,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { - self.consume_expr(&expr); + self.consume_expr(expr); } } } @@ -462,8 +462,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { where F: FnMut(&mut Self), { - self.walk_expr(&expr); - let expr_place = return_if_err!(self.mc.cat_expr(&expr)); + self.walk_expr(expr); + let expr_place = return_if_err!(self.mc.cat_expr(expr)); f(self); self.walk_irrefutable_pat(&expr_place, &pat); } @@ -478,7 +478,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } if let Some(ref tail_expr) = blk.expr { - self.consume_expr(&tail_expr); + self.consume_expr(tail_expr); } } @@ -489,17 +489,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ) { // Consume the expressions supplying values for each field. for field in fields { - self.consume_expr(&field.expr); + self.consume_expr(field.expr); } let with_expr = match *opt_with { - Some(ref w) => &**w, + Some(w) => &*w, None => { return; } }; - let with_place = return_if_err!(self.mc.cat_expr(&with_expr)); + let with_place = return_if_err!(self.mc.cat_expr(with_expr)); // Select just those fields of the `with` // expression that will actually be used @@ -569,7 +569,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } place_with_id = - return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, &adjustment)); + return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, adjustment)); } } @@ -615,13 +615,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { FakeReadCause::ForMatchedPlace(closure_def_id), discr_place.hir_id, ); - self.walk_pat(discr_place, &arm.pat); + self.walk_pat(discr_place, arm.pat); - if let Some(hir::Guard::If(ref e)) = arm.guard { + if let Some(hir::Guard::If(e)) = arm.guard { + self.consume_expr(e) + } else if let Some(hir::Guard::IfLet(_, ref e)) = arm.guard { self.consume_expr(e) } - self.consume_expr(&arm.body); + self.consume_expr(arm.body); } /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or @@ -834,7 +836,7 @@ fn delegate_consume<'a, 'tcx>( ) { debug!("delegate_consume(place_with_id={:?})", place_with_id); - let mode = copy_or_move(&mc, place_with_id); + let mode = copy_or_move(mc, place_with_id); match mode { ConsumeMode::Move => delegate.consume(place_with_id, diag_expr_id), diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index b7ede0e4bf251..39bcf8999323d 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -83,7 +83,8 @@ fn diagnostic_hir_wf_check<'tcx>( traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(tcx_ty.into()).to_predicate(self.tcx), + ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into())) + .to_predicate(self.tcx), ), ); diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 8ecd6034ad695..f4bb5761c19bd 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -74,7 +74,7 @@ use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt}; use rustc_infer::traits::specialization_graph::Node; use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; use rustc_middle::ty::trait_def::TraitSpecializationKind; -use rustc_middle::ty::{self, InstantiatedPredicates, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::traits::{self, translate_substs, wf}; @@ -294,13 +294,27 @@ fn check_predicates<'tcx>( span: Span, ) { let tcx = infcx.tcx; - let impl1_predicates = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs); + let impl1_predicates: Vec<_> = traits::elaborate_predicates( + tcx, + tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(), + ) + .map(|obligation| obligation.predicate) + .collect(); + let mut impl2_predicates = if impl2_node.is_from_trait() { // Always applicable traits have to be always applicable without any // assumptions. - InstantiatedPredicates::empty() + Vec::new() } else { - tcx.predicates_of(impl2_node.def_id()).instantiate(tcx, impl2_substs) + traits::elaborate_predicates( + tcx, + tcx.predicates_of(impl2_node.def_id()) + .instantiate(tcx, impl2_substs) + .predicates + .into_iter(), + ) + .map(|obligation| obligation.predicate) + .collect() }; debug!( "check_always_applicable(\nimpl1_predicates={:?},\nimpl2_predicates={:?}\n)", @@ -322,13 +336,12 @@ fn check_predicates<'tcx>( // which is sound because we forbid impls like the following // // impl AlwaysApplicable for D { } - let always_applicable_traits = - impl1_predicates.predicates.iter().copied().filter(|&predicate| { - matches!( - trait_predicate_kind(tcx, predicate), - Some(TraitSpecializationKind::AlwaysApplicable) - ) - }); + let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| { + matches!( + trait_predicate_kind(tcx, predicate), + Some(TraitSpecializationKind::AlwaysApplicable) + ) + }); // Include the well-formed predicates of the type parameters of the impl. for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs { @@ -340,18 +353,19 @@ fn check_predicates<'tcx>( arg, span, ) { - impl2_predicates - .predicates - .extend(obligations.into_iter().map(|obligation| obligation.predicate)) + impl2_predicates.extend( + traits::elaborate_obligations(tcx, obligations) + .map(|obligation| obligation.predicate), + ) } } - impl2_predicates.predicates.extend( + impl2_predicates.extend( traits::elaborate_predicates(tcx, always_applicable_traits) .map(|obligation| obligation.predicate), ); - for predicate in impl1_predicates.predicates { - if !impl2_predicates.predicates.contains(&predicate) { + for predicate in impl1_predicates { + if !impl2_predicates.contains(&predicate) { check_specialization_on(tcx, predicate, span) } } diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index f8714cdc70c19..65eedd2daafa8 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -107,6 +107,7 @@ use rustc_middle::util; use rustc_session::config::EntryFnType; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, @@ -143,7 +144,7 @@ fn require_same_types<'tcx>( tcx.infer_ctxt().enter(|ref infcx| { let param_env = ty::ParamEnv::empty(); let mut fulfill_cx = >::new(infcx.tcx); - match infcx.at(&cause, param_env).eq(expected, actual) { + match infcx.at(cause, param_env).eq(expected, actual) { Ok(InferOk { obligations, .. }) => { fulfill_cx.register_predicate_obligations(infcx, obligations); } @@ -187,9 +188,11 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { - let generics_param_span = - if !generics.params.is_empty() { Some(generics.span) } else { None }; - generics_param_span + if !generics.params.is_empty() { + Some(generics.span) + } else { + None + } } _ => { span_bug!(tcx.def_span(def_id), "main has a non-function type"); @@ -326,7 +329,26 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { ObligationCauseCode::MainFunctionType, ); let mut fulfillment_cx = traits::FulfillmentContext::new(); - fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), return_ty, term_id, cause); + // normalize any potential projections in the return type, then add + // any possible obligations to the fulfillment context. + // HACK(ThePuzzlemaker) this feels symptomatic of a problem within + // checking trait fulfillment, not this here. I'm not sure why it + // works in the example in `fn test()` given in #88609? This also + // probably isn't the best way to do this. + let InferOk { value: norm_return_ty, obligations } = infcx + .partially_normalize_associated_types_in( + cause.clone(), + ty::ParamEnv::empty(), + return_ty, + ); + fulfillment_cx.register_predicate_obligations(&infcx, obligations); + fulfillment_cx.register_bound( + &infcx, + ty::ParamEnv::empty(), + norm_return_ty, + term_id, + cause, + ); if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { infcx.report_fulfillment_errors(&err, None, false); error = true; diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index f876d0f251367..440ce04e61a27 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -307,13 +307,13 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { if self.typeck_results.is_method_call(expr) { self.cat_overloaded_place(expr, e_base) } else { - let base = self.cat_expr(&e_base)?; + let base = self.cat_expr(e_base)?; self.cat_deref(expr, base) } } hir::ExprKind::Field(ref base, _) => { - let base = self.cat_expr(&base)?; + let base = self.cat_expr(base)?; debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base); let field_idx = self @@ -340,7 +340,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // dereferencing. self.cat_overloaded_place(expr, base) } else { - let base = self.cat_expr(&base)?; + let base = self.cat_expr(base)?; Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index)) } } @@ -350,7 +350,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_res(expr.hir_id, expr.span, expr_ty, res) } - hir::ExprKind::Type(ref e, _) => self.cat_expr(&e), + hir::ExprKind::Type(ref e, _) => self.cat_expr(e), hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) @@ -674,31 +674,31 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { op(&place_with_id, pat); match pat.kind { - PatKind::Tuple(ref subpats, dots_pos) => { + PatKind::Tuple(subpats, dots_pos) => { // (p1, ..., pN) let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?; for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { - let subpat_ty = self.pat_ty_adjusted(&subpat)?; + let subpat_ty = self.pat_ty_adjusted(subpat)?; let projection_kind = ProjectionKind::Field(i as u32, VariantIdx::new(0)); let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); - self.cat_pattern_(sub_place, &subpat, op)?; + self.cat_pattern_(sub_place, subpat, op)?; } } - PatKind::TupleStruct(ref qpath, ref subpats, dots_pos) => { + PatKind::TupleStruct(ref qpath, subpats, dots_pos) => { // S(p1, ..., pN) let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; let total_fields = self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?; for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { - let subpat_ty = self.pat_ty_adjusted(&subpat)?; + let subpat_ty = self.pat_ty_adjusted(subpat)?; let projection_kind = ProjectionKind::Field(i as u32, variant_index); let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); - self.cat_pattern_(sub_place, &subpat, op)?; + self.cat_pattern_(sub_place, subpat, op)?; } } @@ -708,7 +708,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; for fp in field_pats { - let field_ty = self.pat_ty_adjusted(&fp.pat)?; + let field_ty = self.pat_ty_adjusted(fp.pat)?; let field_index = self .typeck_results .field_indices() @@ -722,18 +722,18 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { field_ty, ProjectionKind::Field(field_index as u32, variant_index), ); - self.cat_pattern_(field_place, &fp.pat, op)?; + self.cat_pattern_(field_place, fp.pat, op)?; } } PatKind::Or(pats) => { for pat in pats { - self.cat_pattern_(place_with_id.clone(), &pat, op)?; + self.cat_pattern_(place_with_id.clone(), pat, op)?; } } PatKind::Binding(.., Some(ref subpat)) => { - self.cat_pattern_(place_with_id, &subpat, op)?; + self.cat_pattern_(place_with_id, subpat, op)?; } PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => { @@ -741,7 +741,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // PatKind::Ref since that information is already contained // in the type. let subplace = self.cat_deref(pat, place_with_id)?; - self.cat_pattern_(subplace, &subpat, op)?; + self.cat_pattern_(subplace, subpat, op)?; } PatKind::Slice(before, ref slice, after) => { @@ -759,20 +759,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ProjectionKind::Index, ); for before_pat in before { - self.cat_pattern_(elt_place.clone(), &before_pat, op)?; + self.cat_pattern_(elt_place.clone(), before_pat, op)?; } if let Some(ref slice_pat) = *slice { - let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?; + let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?; let slice_place = self.cat_projection( pat, place_with_id, slice_pat_ty, ProjectionKind::Subslice, ); - self.cat_pattern_(slice_place, &slice_pat, op)?; + self.cat_pattern_(slice_place, slice_pat, op)?; } for after_pat in after { - self.cat_pattern_(elt_place.clone(), &after_pat, op)?; + self.cat_pattern_(elt_place.clone(), after_pat, op)?; } } diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs index 2ac1a18cffaf1..bbf31de527eb3 100644 --- a/compiler/rustc_typeck/src/outlives/explicit.rs +++ b/compiler/rustc_typeck/src/outlives/explicit.rs @@ -30,20 +30,20 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { // process predicates and convert to `RequiredPredicates` entry, see below for &(predicate, span) in predicates.predicates { match predicate.kind().skip_binder() { - ty::PredicateKind::TypeOutlives(OutlivesPredicate(ref ty, ref reg)) => { + ty::PredicateKind::TypeOutlives(OutlivesPredicate(ty, reg)) => { insert_outlives_predicate( tcx, - (*ty).into(), + ty.into(), reg, span, &mut required_predicates, ) } - ty::PredicateKind::RegionOutlives(OutlivesPredicate(ref reg1, ref reg2)) => { + ty::PredicateKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => { insert_outlives_predicate( tcx, - (*reg1).into(), + reg1.into(), reg2, span, &mut required_predicates, diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index 0e96601d89fd8..86d712e2d7922 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -37,7 +37,7 @@ pub fn infer_predicates<'tcx>( }; // Visit all the crates and infer predicates - tcx.hir().krate().visit_all_item_likes(&mut visitor); + tcx.hir().visit_all_item_likes(&mut visitor); } global_inferred_outlives diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 70a2ba7fcd9d9..957ff2525190d 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -22,7 +22,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization() { - if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) { + if tcx.hir().opt_const_param_default_param_hir_id(id).is_some() { // In `generics_of` we set the generics' parent to be our parent's parent which means that // we lose out on the predicates of our actual parent if we dont return those predicates here. // (See comment in `generics_of` for more information on why the parent shenanigans is necessary) @@ -104,13 +104,15 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> { |(ty::OutlivesPredicate(kind1, region2), &span)| { match kind1.unpack() { GenericArgKind::Type(ty1) => Some(( - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty1, region2)) - .to_predicate(tcx), + ty::Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(ty1, region2), + )) + .to_predicate(tcx), span, )), GenericArgKind::Lifetime(region1) => Some(( - ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate( - region1, region2, + ty::Binder::dummy(ty::PredicateKind::RegionOutlives( + ty::OutlivesPredicate(region1, region2), )) .to_predicate(tcx), span, diff --git a/compiler/rustc_typeck/src/outlives/test.rs b/compiler/rustc_typeck/src/outlives/test.rs index d4bef0c409a8f..ec4fa9cd4b577 100644 --- a/compiler/rustc_typeck/src/outlives/test.rs +++ b/compiler/rustc_typeck/src/outlives/test.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; pub fn test_inferred_outlives(tcx: TyCtxt<'_>) { - tcx.hir().krate().visit_all_item_likes(&mut OutlivesTest { tcx }); + tcx.hir().visit_all_item_likes(&mut OutlivesTest { tcx }); } struct OutlivesTest<'tcx> { diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index 7e69ad21d0343..8d3862ffc8f01 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -1,6 +1,7 @@ use crate::structured_errors::StructuredDiagnostic; use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; +use rustc_middle::hir::map::fn_sig; use rustc_middle::middle::resolve_lifetime::LifetimeScopeForPath; use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::Session; @@ -292,12 +293,30 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { &self, num_params_to_take: usize, ) -> String { + let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(fn_sig); + let is_used_in_input = |def_id| { + fn_sig.map_or(false, |fn_sig| { + fn_sig.decl.inputs.iter().any(|ty| match ty.kind { + hir::TyKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::Def(_, id), .. }, + )) if *id == def_id => true, + _ => false, + }) + }) + }; self.gen_params .params .iter() .skip(self.params_offset + self.num_provided_type_or_const_args()) .take(num_params_to_take) - .map(|param| param.name.to_string()) + .map(|param| match param.kind { + // This is being infered from the item's inputs, no need to set it. + ty::GenericParamDefKind::Type { .. } if is_used_in_input(param.def_id) => { + "_".to_string() + } + _ => param.name.to_string(), + }) .collect::>() .join(", ") } @@ -712,7 +731,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { /// Builds the `type defined here` message. fn show_definition(&self, err: &mut DiagnosticBuilder<'_>) { let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) { - def_span.into() + if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() { + def_span.into() + } else { + return; + } } else { return; }; diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index f5355ea042bdf..1c8ac10818c03 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -62,7 +62,7 @@ pub fn add_constraints_from_crate<'a, 'tcx>( constraints: Vec::new(), }; - tcx.hir().krate().visit_all_item_likes(&mut constraint_cx); + tcx.hir().visit_all_item_likes(&mut constraint_cx); constraint_cx } @@ -293,7 +293,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_invariant_substs(current, substs, variance); } - ty::Dynamic(ref data, r) => { + ty::Dynamic(data, r) => { // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); self.add_constraints_from_region(current, r, contra); diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs index 5d5baf78d33c3..d7f9df668bf36 100644 --- a/compiler/rustc_typeck/src/variance/terms.rs +++ b/compiler/rustc_typeck/src/variance/terms.rs @@ -79,7 +79,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>( // // - https://rustc-dev-guide.rust-lang.org/query.html // - https://rustc-dev-guide.rust-lang.org/variance.html - tcx.hir().krate().visit_all_item_likes(&mut terms_cx); + tcx.hir().visit_all_item_likes(&mut terms_cx); terms_cx } diff --git a/compiler/rustc_typeck/src/variance/test.rs b/compiler/rustc_typeck/src/variance/test.rs index 2a0d950c87dab..7be3c68e8f617 100644 --- a/compiler/rustc_typeck/src/variance/test.rs +++ b/compiler/rustc_typeck/src/variance/test.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; pub fn test_variance(tcx: TyCtxt<'_>) { - tcx.hir().krate().visit_all_item_likes(&mut VarianceTest { tcx }); + tcx.hir().visit_all_item_likes(&mut VarianceTest { tcx }); } struct VarianceTest<'tcx> { diff --git a/config.toml.example b/config.toml.example index aff4e8fa82ac1..d811b914d20a1 100644 --- a/config.toml.example +++ b/config.toml.example @@ -313,6 +313,12 @@ changelog-seen = 2 # this setting's very existence, are all subject to change.) #print-step-rusage = false +# Always patch binaries for usage with Nix toolchains. If `true` then binaries +# will be patched unconditionally. If `false` or unset, binaries will be patched +# only if the current distribution is NixOS. This option is useful when using +# a Nix toolchain on non-NixOS distributions. +#patch-binaries-for-nix = false + # ============================================================================= # General install configuration options # ============================================================================= diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index c93a493cadb0d..8e1d374b5d42b 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -732,3 +732,18 @@ fn bench_flat_map_collect(b: &mut Bencher) { let v = vec![777u32; 500000]; b.iter(|| v.iter().flat_map(|color| color.rotate_left(8).to_be_bytes()).collect::>()); } + +#[bench] +fn bench_retain_100000(b: &mut Bencher) { + let v = (1..=100000).collect::>(); + b.iter(|| { + let mut v = v.clone(); + v.retain(|x| x & 1 == 0) + }); +} + +#[bench] +fn bench_retain_whole_100000(b: &mut Bencher) { + let mut v = black_box(vec![826u32; 100000]); + b.iter(|| v.retain(|x| *x == 826u32)); +} diff --git a/library/alloc/benches/vec_deque.rs b/library/alloc/benches/vec_deque.rs index bf2dffd1e931e..404cfa6addb73 100644 --- a/library/alloc/benches/vec_deque.rs +++ b/library/alloc/benches/vec_deque.rs @@ -52,3 +52,18 @@ fn bench_try_fold(b: &mut Bencher) { b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b)))) } + +#[bench] +fn bench_from_array_1000(b: &mut Bencher) { + const N: usize = 1000; + let mut array: [usize; N] = [0; N]; + + for i in 0..N { + array[i] = i; + } + + b.iter(|| { + let deq: VecDeque<_> = array.into(); + black_box(deq); + }) +} diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 3ed3c2382cac6..4a5b0fcf03709 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -307,7 +307,6 @@ unsafe impl Allocator for Global { } /// The allocator for unique pointers. -// This function must not unwind. If it does, MIR codegen will fail. #[cfg(all(not(no_global_oom_handling), not(test)))] #[lang = "exchange_malloc"] #[inline] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 2b3a18a439fc9..52ade972b8a54 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1277,6 +1277,7 @@ impl From for Box { /// from the stack into it. /// /// # Examples + /// /// ```rust /// let x = 5; /// let boxed = Box::new(5); @@ -1330,6 +1331,12 @@ impl From<&[T]> for Box<[T]> { #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box<[T]> { + /// Converts a `Cow<'_, [T]>` into a `Box<[T]>` + /// + /// When `cow` is the `Cow::Borrowed` variant, this + /// conversion allocates on the heap and performs a copy of the + /// underlying slice. Otherwise, it will try to re-use the owned + /// vec's allocation. #[inline] fn from(cow: Cow<'_, [T]>) -> Box<[T]> { match cow { @@ -1348,6 +1355,7 @@ impl From<&str> for Box { /// and performs a copy of `s`. /// /// # Examples + /// /// ```rust /// let boxed: Box = Box::from("hello"); /// println!("{}", boxed); @@ -1361,6 +1369,29 @@ impl From<&str> for Box { #[cfg(not(no_global_oom_handling))] #[stable(feature = "box_from_cow", since = "1.45.0")] impl From> for Box { + /// Converts a `Cow<'_, str>` into a `Box` + /// + /// When `cow` is the `Cow::Borrowed` variant, this + /// conversion allocates on the heap and performs a copy of the + /// underlying `str`. Otherwise, it will try to re-use the owned + /// `String`'s allocation. + /// + /// # Examples + /// + /// ```rust + /// use std::borrow::Cow; + /// + /// let unboxed = Cow::Borrowed("hello"); + /// let boxed: Box = Box::from(unboxed); + /// println!("{}", boxed); + /// ``` + /// + /// ```rust + /// # use std::borrow::Cow; + /// let unboxed = Cow::Owned("hello".to_string()); + /// let boxed: Box = Box::from(unboxed); + /// println!("{}", boxed); + /// ``` #[inline] fn from(cow: Cow<'_, str>) -> Box { match cow { @@ -1403,6 +1434,7 @@ impl From<[T; N]> for Box<[T]> { /// This conversion moves the array to newly heap-allocated memory. /// /// # Examples + /// /// ```rust /// let boxed: Box<[u8]> = Box::from([4, 2]); /// println!("{:?}", boxed); @@ -1416,6 +1448,15 @@ impl From<[T; N]> for Box<[T]> { impl TryFrom> for Box<[T; N]> { type Error = Box<[T]>; + /// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`. + /// + /// The conversion occurs in-place and does not require a + /// new memory allocation. + /// + /// # Errors + /// + /// Returns the old `Box<[T]>` in the `Err` variant if + /// `boxed_slice.len()` does not equal `N`. fn try_from(boxed_slice: Box<[T]>) -> Result { if boxed_slice.len() == N { Ok(unsafe { Box::from_raw(Box::into_raw(boxed_slice) as *mut [T; N]) }) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 28e4f8bba05c8..4ed3702f7d224 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -3,7 +3,7 @@ //! Insertion and popping the largest element have *O*(log(*n*)) time complexity. //! Checking the largest element is *O*(1). Converting a vector to a binary heap //! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be -//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* \* log(*n*)) +//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* * log(*n*)) //! in-place heapsort. //! //! # Examples @@ -159,9 +159,9 @@ use super::SpecExtend; /// This will be a max-heap. /// /// It is a logic error for an item to be modified in such a way that the -/// item's ordering relative to any other item, as determined by the `Ord` +/// item's ordering relative to any other item, as determined by the [`Ord`] /// trait, changes while it is in the heap. This is normally only possible -/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. The +/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The /// behavior resulting from such a logic error is not specified, but will /// not result in undefined behavior. This could include panics, incorrect /// results, aborts, memory leaks, and non-termination. @@ -219,7 +219,7 @@ use super::SpecExtend; /// /// ## Min-heap /// -/// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to +/// Either [`core::cmp::Reverse`] or a custom [`Ord`] implementation can be used to /// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest /// value instead of the greatest one. /// @@ -243,13 +243,17 @@ use super::SpecExtend; /// /// # Time complexity /// -/// | [push] | [pop] | [peek]/[peek\_mut] | -/// |--------|-----------|--------------------| -/// | O(1)~ | *O*(log(*n*)) | *O*(1) | +/// | [push] | [pop] | [peek]/[peek\_mut] | +/// |---------|---------------|--------------------| +/// | *O*(1)~ | *O*(log(*n*)) | *O*(1) | /// /// The value for `push` is an expected cost; the method documentation gives a /// more detailed analysis. /// +/// [`core::cmp::Reverse`]: core::cmp::Reverse +/// [`Ord`]: core::cmp::Ord +/// [`Cell`]: core::cell::Cell +/// [`RefCell`]: core::cell::RefCell /// [push]: BinaryHeap::push /// [pop]: BinaryHeap::pop /// [peek]: BinaryHeap::peek @@ -1255,9 +1259,10 @@ impl FusedIterator for Iter<'_, T> {} /// An owning iterator over the elements of a `BinaryHeap`. /// /// This `struct` is created by [`BinaryHeap::into_iter()`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: BinaryHeap::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct IntoIter { diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 501a604e7f76d..d6032372168f1 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -19,16 +19,16 @@ mod entry; pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry}; use Entry::*; -/// Minimum number of elements in nodes that are not a root. +/// Minimum number of elements in a node that is not a root. /// We might temporarily have fewer elements during methods. pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; // A tree in a `BTreeMap` is a tree in the `node` module with additional invariants: // - Keys must appear in ascending order (according to the key's type). -// - If the root node is internal, it must contain at least 1 element. +// - Every non-leaf node contains at least 1 element (has at least 2 children). // - Every non-root node contains at least MIN_LEN elements. // -// An empty map may be represented both by the absence of a root node or by a +// An empty map is represented either by the absence of a root node or by a // root node that is an empty leaf. /// A map based on a [B-Tree]. @@ -155,6 +155,7 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")] +#[rustc_insignificant_dtor] pub struct BTreeMap { root: Option>, length: usize, @@ -326,10 +327,12 @@ impl fmt::Debug for IterMut<'_, K, V> { /// An owning iterator over the entries of a `BTreeMap`. /// /// This `struct` is created by the [`into_iter`] method on [`BTreeMap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct IntoIter { range: LazyLeafRange, length: usize, @@ -1732,8 +1735,8 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { pub(super) fn size_hint(&self) -> (usize, Option) { // In most of the btree iterators, `self.length` is the number of elements // yet to be visited. Here, it includes elements that were visited and that - // the predicate decided not to drain. Making this upper bound more accurate - // requires maintaining an extra field and is not worth while. + // the predicate decided not to drain. Making this upper bound more tight + // during iteration would require an extra field. (0, Some(*self.length)) } } @@ -1965,6 +1968,7 @@ impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Hash for BTreeMap { fn hash(&self, state: &mut H) { + self.len().hash(state); for elt in self { elt.hash(state); } diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index a99d6c49ab7b3..b8e11e109c831 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1494,33 +1494,40 @@ fn test_clone() { map.check(); } -#[test] -fn test_clone_panic_leak() { - let a = CrashTestDummy::new(0); - let b = CrashTestDummy::new(1); - let c = CrashTestDummy::new(2); +fn test_clone_panic_leak(size: usize) { + for i in 0..size { + let dummies: Vec = (0..size).map(|id| CrashTestDummy::new(id)).collect(); + let map: BTreeMap<_, ()> = dummies + .iter() + .map(|dummy| { + let panic = if dummy.id == i { Panic::InClone } else { Panic::Never }; + (dummy.spawn(panic), ()) + }) + .collect(); - let mut map = BTreeMap::new(); - map.insert(a.spawn(Panic::Never), ()); - map.insert(b.spawn(Panic::InClone), ()); - map.insert(c.spawn(Panic::Never), ()); + catch_unwind(|| map.clone()).unwrap_err(); + for d in &dummies { + assert_eq!(d.cloned(), if d.id <= i { 1 } else { 0 }, "id={}/{}", d.id, i); + assert_eq!(d.dropped(), if d.id < i { 1 } else { 0 }, "id={}/{}", d.id, i); + } + assert_eq!(map.len(), size); - catch_unwind(|| map.clone()).unwrap_err(); - assert_eq!(a.cloned(), 1); - assert_eq!(b.cloned(), 1); - assert_eq!(c.cloned(), 0); - assert_eq!(a.dropped(), 1); - assert_eq!(b.dropped(), 0); - assert_eq!(c.dropped(), 0); - assert_eq!(map.len(), 3); + drop(map); + for d in &dummies { + assert_eq!(d.cloned(), if d.id <= i { 1 } else { 0 }, "id={}/{}", d.id, i); + assert_eq!(d.dropped(), if d.id < i { 2 } else { 1 }, "id={}/{}", d.id, i); + } + } +} - drop(map); - assert_eq!(a.cloned(), 1); - assert_eq!(b.cloned(), 1); - assert_eq!(c.cloned(), 0); - assert_eq!(a.dropped(), 2); - assert_eq!(b.dropped(), 1); - assert_eq!(c.dropped(), 1); +#[test] +fn test_clone_panic_leak_height_0() { + test_clone_panic_leak(3) +} + +#[test] +fn test_clone_panic_leak_height_1() { + test_clone_panic_leak(MIN_INSERTS_HEIGHT_1) } #[test] diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index 7b1d4d68c4f56..9d0db34500945 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -440,8 +440,7 @@ impl Handle, marker::Edge> { /// - The given edge must not have been previously returned by counterpart /// `deallocating_next_back`. /// - The returned KV handle is only valid to access the key and value, - /// and only valid until the next call to this method or counterpart - /// `deallocating_next_back`. + /// and only valid until the next call to a `deallocating_` method. unsafe fn deallocating_next( self, ) -> Option<(Self, Handle, marker::KV>)> @@ -470,8 +469,7 @@ impl Handle, marker::Edge> { /// - The given edge must not have been previously returned by counterpart /// `deallocating_next`. /// - The returned KV handle is only valid to access the key and value, - /// and only valid until the next call to this method or counterpart - /// `deallocating_next`. + /// and only valid until the next call to a `deallocating_` method. unsafe fn deallocating_next_back( self, ) -> Option<(Self, Handle, marker::KV>)> diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index a73f00a083af3..dfce98f97bd44 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -574,7 +574,7 @@ impl NodeRef { /// no cleanup is done on any of the keys, values and other children. /// This decreases the height by 1 and is the opposite of `push_internal_level`. /// - /// Requires exclusive access to the `Root` object but not to the root node; + /// Requires exclusive access to the `NodeRef` object but not to the root node; /// it will not invalidate other handles or references to the root node. /// /// Panics if there is no internal level, i.e., if the root node is a leaf. diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index c664e201aec54..16150ceeb62c1 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -107,9 +107,10 @@ impl fmt::Debug for Iter<'_, T> { /// An owning iterator over the items of a `BTreeSet`. /// /// This `struct` is created by the [`into_iter`] method on [`BTreeSet`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: BTreeSet#method.into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IntoIter { diff --git a/library/alloc/src/collections/btree/testing/crash_test.rs b/library/alloc/src/collections/btree/testing/crash_test.rs index b2527b95f5bba..488eaa07a95b4 100644 --- a/library/alloc/src/collections/btree/testing/crash_test.rs +++ b/library/alloc/src/collections/btree/testing/crash_test.rs @@ -11,7 +11,7 @@ use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; /// on anything defined in the crate, apart from the `Debug` trait. #[derive(Debug)] pub struct CrashTestDummy { - id: usize, + pub id: usize, cloned: AtomicUsize, dropped: AtomicUsize, queried: AtomicUsize, diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 9d45c5082db43..a769c558b4fa9 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -38,11 +38,15 @@ mod tests; /// let list = LinkedList::from([1, 2, 3]); /// ``` /// -/// NOTE: It is almost always better to use `Vec` or `VecDeque` because +/// NOTE: It is almost always better to use [`Vec`] or [`VecDeque`] because /// array-based containers are generally faster, /// more memory efficient, and make better use of CPU cache. +/// +/// [`Vec`]: crate::vec::Vec +/// [`VecDeque`]: super::vec_deque::VecDeque #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")] +#[rustc_insignificant_dtor] pub struct LinkedList { head: Option>>, tail: Option>>, @@ -121,9 +125,10 @@ impl fmt::Debug for IterMut<'_, T> { /// An owning iterator over the elements of a `LinkedList`. /// /// This `struct` is created by the [`into_iter`] method on [`LinkedList`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: LinkedList::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { @@ -631,6 +636,8 @@ impl LinkedList { /// Returns `true` if the `LinkedList` contains an element equal to the /// given value. /// + /// This operation should compute in *O*(*n*) time. + /// /// # Examples /// /// ``` @@ -656,6 +663,8 @@ impl LinkedList { /// Provides a reference to the front element, or `None` if the list is /// empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -676,6 +685,8 @@ impl LinkedList { /// Provides a mutable reference to the front element, or `None` if the list /// is empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -702,6 +713,8 @@ impl LinkedList { /// Provides a reference to the back element, or `None` if the list is /// empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` @@ -722,6 +735,8 @@ impl LinkedList { /// Provides a mutable reference to the back element, or `None` if the list /// is empty. /// + /// This operation should compute in *O*(1) time. + /// /// # Examples /// /// ``` diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 4e31df8b4b8c2..77d28bdfe6475 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -57,7 +57,7 @@ use core::fmt::Display; /// The error type for `try_reserve` methods. #[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] +#[stable(feature = "try_reserve", since = "1.57.0")] pub struct TryReserveError { kind: TryReserveErrorKind, } @@ -126,7 +126,7 @@ impl From for TryReserveErrorKind { } } -#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] +#[stable(feature = "try_reserve", since = "1.57.0")] impl Display for TryReserveError { fn fmt( &self, diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index dfa0227dea3b8..05f94da6de70d 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -18,10 +18,21 @@ pub struct Drain< T: 'a, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, > { - pub(crate) after_tail: usize, - pub(crate) after_head: usize, - pub(crate) iter: Iter<'a, T>, - pub(crate) deque: NonNull>, + after_tail: usize, + after_head: usize, + iter: Iter<'a, T>, + deque: NonNull>, +} + +impl<'a, T, A: Allocator> Drain<'a, T, A> { + pub(super) unsafe fn new( + after_tail: usize, + after_head: usize, + iter: Iter<'a, T>, + deque: NonNull>, + ) -> Self { + Drain { after_tail, after_head, iter, deque } + } } #[stable(feature = "collection_debug", since = "1.17.0")] diff --git a/library/alloc/src/collections/vec_deque/into_iter.rs b/library/alloc/src/collections/vec_deque/into_iter.rs index 54a157be0b96a..55f6138cd0f31 100644 --- a/library/alloc/src/collections/vec_deque/into_iter.rs +++ b/library/alloc/src/collections/vec_deque/into_iter.rs @@ -8,9 +8,10 @@ use super::VecDeque; /// An owning iterator over the elements of a `VecDeque`. /// /// This `struct` is created by the [`into_iter`] method on [`VecDeque`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: VecDeque::into_iter +/// [`IntoIterator`]: core::iter::IntoIterator #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter< diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index 7700b31cf5b46..31e6e3b06af5f 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -13,10 +13,21 @@ use super::{count, wrap_index, RingSlices}; #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { // Internal safety invariant: the entire slice is dereferencable. - pub(crate) ring: *mut [T], - pub(crate) tail: usize, - pub(crate) head: usize, - pub(crate) phantom: PhantomData<&'a mut [T]>, + ring: *mut [T], + tail: usize, + head: usize, + phantom: PhantomData<&'a mut [T]>, +} + +impl<'a, T> IterMut<'a, T> { + pub(super) unsafe fn new( + ring: *mut [T], + tail: usize, + head: usize, + phantom: PhantomData<&'a mut [T]>, + ) -> Self { + IterMut { ring, tail, head, phantom } + } } // SAFETY: we do nothing thread-local and there is no interior mutability, diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 10144cc17bf30..e996784bbad28 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -88,8 +88,9 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible /// [`extend`]: VecDeque::extend /// [`append`]: VecDeque::append /// [`make_contiguous`]: VecDeque::make_contiguous -#[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "VecDeque")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct VecDeque< T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -710,7 +711,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// use std::collections::VecDeque; /// @@ -729,7 +729,7 @@ impl VecDeque { /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.try_reserve(additional) } @@ -748,7 +748,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// use std::collections::VecDeque; /// @@ -767,7 +766,7 @@ impl VecDeque { /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { let old_cap = self.cap(); let used_cap = self.len() + 1; @@ -1001,12 +1000,9 @@ impl VecDeque { pub fn iter_mut(&mut self) -> IterMut<'_, T> { // SAFETY: The internal `IterMut` safety invariant is established because the // `ring` we create is a dereferencable slice for lifetime '_. - IterMut { - tail: self.tail, - head: self.head, - ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()), - phantom: PhantomData, - } + let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()); + + unsafe { IterMut::new(ring, self.tail, self.head, PhantomData) } } /// Returns a pair of slices which contain, in order, the contents of the @@ -1193,12 +1189,9 @@ impl VecDeque { // SAFETY: The internal `IterMut` safety invariant is established because the // `ring` we create is a dereferencable slice for lifetime '_. - IterMut { - tail, - head, - ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()), - phantom: PhantomData, - } + let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()); + + unsafe { IterMut::new(ring, tail, head, PhantomData) } } /// Creates a draining iterator that removes the specified range in the @@ -1270,19 +1263,17 @@ impl VecDeque { // the drain is complete and the Drain destructor is run. self.head = drain_tail; - Drain { - deque: NonNull::from(&mut *self), - after_tail: drain_head, - after_head: head, - iter: Iter { - tail: drain_tail, - head: drain_head, - // Crucially, we only create shared references from `self` here and read from - // it. We do not write to `self` nor reborrow to a mutable reference. - // Hence the raw pointer we created above, for `deque`, remains valid. - ring: unsafe { self.buffer_as_slice() }, - }, - } + let deque = NonNull::from(&mut *self); + let iter = Iter { + tail: drain_tail, + head: drain_head, + // Crucially, we only create shared references from `self` here and read from + // it. We do not write to `self` nor reborrow to a mutable reference. + // Hence the raw pointer we created above, for `deque`, remains valid. + ring: unsafe { self.buffer_as_slice() }, + }; + + unsafe { Drain::new(drain_head, head, iter, deque) } } /// Clears the `VecDeque`, removing all values. @@ -3003,6 +2994,16 @@ impl From<[T; N]> for VecDeque { /// assert_eq!(deq1, deq2); /// ``` fn from(arr: [T; N]) -> Self { - core::array::IntoIter::new(arr).collect() + let mut deq = VecDeque::with_capacity(N); + let arr = ManuallyDrop::new(arr); + if mem::size_of::() != 0 { + // SAFETY: VecDeque::with_capacity ensures that there is enough capacity. + unsafe { + ptr::copy_nonoverlapping(arr.as_ptr(), deq.ptr(), N); + } + } + deq.tail = 0; + deq.head = N; + deq } } diff --git a/library/alloc/src/collections/vec_deque/pair_slices.rs b/library/alloc/src/collections/vec_deque/pair_slices.rs index 8e3ac9cfd1d87..6735424a3ef33 100644 --- a/library/alloc/src/collections/vec_deque/pair_slices.rs +++ b/library/alloc/src/collections/vec_deque/pair_slices.rs @@ -20,10 +20,10 @@ use super::VecDeque; /// /// and the uneven remainder of either A or B is skipped. pub struct PairSlices<'a, 'b, T> { - pub(crate) a0: &'a mut [T], - pub(crate) a1: &'a mut [T], - pub(crate) b0: &'b [T], - pub(crate) b1: &'b [T], + a0: &'a mut [T], + a1: &'a mut [T], + b0: &'b [T], + b1: &'b [T], } impl<'a, 'b, T> PairSlices<'a, 'b, T> { diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs index 56257e4346254..2be83f68f017f 100644 --- a/library/alloc/src/collections/vec_deque/tests.rs +++ b/library/alloc/src/collections/vec_deque/tests.rs @@ -507,6 +507,36 @@ fn test_from_vec_zst_overflow() { assert_eq!(vd.len(), vec.len()); } +#[test] +fn test_from_array() { + fn test() { + let mut array: [usize; N] = [0; N]; + + for i in 0..N { + array[i] = i; + } + + let deq: VecDeque<_> = array.into(); + + for i in 0..N { + assert_eq!(deq[i], i); + } + + assert!(deq.cap().is_power_of_two()); + assert_eq!(deq.len(), N); + } + test::<0>(); + test::<1>(); + test::<2>(); + test::<32>(); + test::<35>(); + + let array = [(); MAXIMUM_ZST_CAPACITY - 1]; + let deq = VecDeque::from(array); + assert!(deq.cap().is_power_of_two()); + assert_eq!(deq.len(), MAXIMUM_ZST_CAPACITY - 1); +} + #[test] fn test_vec_from_vecdeque() { use crate::vec::Vec; diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 8c5125d208263..878d8dc5502df 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -348,7 +348,7 @@ //! provides some helper methods. //! //! Additionally, the return value of this function is [`fmt::Result`] which is a -//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations +//! type alias of [Result]<(), [std::fmt::Error]>. Formatting implementations //! should ensure that they propagate errors from the [`Formatter`] (e.g., when //! calling [`write!`]). However, they should never return errors spuriously. That //! is, a formatting implementation must and may only return an error if the @@ -505,23 +505,19 @@ //! it would internally pass around this structure until it has been determined //! where output should go to. //! -//! [`fmt::Result`]: Result -//! [`Result`]: core::result::Result -//! [`std::fmt::Error`]: Error -//! [`write!`]: core::write -//! [`write`]: core::write -//! [`format!`]: crate::format -//! [`to_string`]: crate::string::ToString -//! [`writeln!`]: core::writeln +//! [`fmt::Result`]: Result "fmt::Result" +//! [Result]: core::result::Result "std::result::Result" +//! [std::fmt::Error]: Error "fmt::Error" +//! [`write`]: write() "fmt::write" +//! [`to_string`]: crate::string::ToString::to_string "ToString::to_string" //! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt //! [`std::io::Write`]: ../../std/io/trait.Write.html -//! [`print!`]: ../../std/macro.print.html -//! [`println!`]: ../../std/macro.println.html -//! [`eprint!`]: ../../std/macro.eprint.html -//! [`eprintln!`]: ../../std/macro.eprintln.html -//! [`format_args!`]: core::format_args -//! [`fmt::Arguments`]: Arguments -//! [`format`]: crate::format +//! [`print!`]: ../../std/macro.print.html "print!" +//! [`println!`]: ../../std/macro.println.html "println!" +//! [`eprint!`]: ../../std/macro.eprint.html "eprint!" +//! [`eprintln!`]: ../../std/macro.eprintln.html "eprintln!" +//! [`fmt::Arguments`]: Arguments "fmt::Arguments" +//! [`format`]: format() "fmt::format" #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 2aed9d03bc09d..72fe84222deac 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -67,6 +67,10 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) )] +#![cfg_attr( + not(bootstrap), + doc(cfg_hide(not(test), not(any(test, bootstrap)), target_has_atomic = "ptr")) +)] #![no_std] #![needs_allocator] #![warn(deprecated_in_future)] @@ -111,6 +115,7 @@ // that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs // from other crates, but since this can only appear for lang items, it doesn't seem worth fixing. #![feature(intra_doc_pointers)] +#![feature(iter_advance_by)] #![feature(iter_zip)] #![feature(lang_items)] #![feature(layout_for_ptr)] @@ -145,6 +150,8 @@ #![feature(associated_type_bounds)] #![feature(slice_group_by)] #![feature(decl_macro)] +#![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] // Allow testing this library #[cfg(test)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0814652a5d47d..81e97805a7214 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -305,6 +305,7 @@ struct RcBox { /// [get_mut]: Rc::get_mut #[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct Rc { ptr: NonNull>, phantom: PhantomData>, @@ -781,9 +782,7 @@ impl Rc { /// Consumes the `Rc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using - /// [`Rc::from_raw`][from_raw]. - /// - /// [from_raw]: Rc::from_raw + /// [`Rc::from_raw`]. /// /// # Examples /// @@ -834,7 +833,7 @@ impl Rc { /// and alignment as `T`. This is trivially true if `U` is `T`. /// Note that if `U` is not `T` but has the same size and alignment, this is /// basically like transmuting references of different types. See - /// [`mem::transmute`][transmute] for more information on what + /// [`mem::transmute`] for more information on what /// restrictions apply in this case. /// /// The user of `from_raw` has to make sure a specific value of `T` is only @@ -844,7 +843,6 @@ impl Rc { /// even if the returned `Rc` is never accessed. /// /// [into_raw]: Rc::into_raw - /// [transmute]: core::mem::transmute /// /// # Examples /// @@ -1086,8 +1084,6 @@ impl Rc { /// assert!(Rc::ptr_eq(&five, &same_five)); /// assert!(!Rc::ptr_eq(&five, &other_five)); /// ``` - /// - /// [`ptr::eq`]: core::ptr::eq pub fn ptr_eq(this: &Self, other: &Self) -> bool { this.ptr.as_ptr() == other.ptr.as_ptr() } @@ -1993,7 +1989,7 @@ impl> ToRcSlice for I { /// `Weak` is a version of [`Rc`] that holds a non-owning reference to the /// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [`Option`]`<`[`Rc`]`>`. +/// pointer, which returns an [Option]<[Rc]\>. /// /// Since a `Weak` reference does not count towards ownership, it will not /// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no @@ -2090,7 +2086,7 @@ impl Weak { /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// - /// [`null`]: core::ptr::null + /// [`null`]: ptr::null #[stable(feature = "rc_as_ptr", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); @@ -2317,8 +2313,6 @@ impl Weak { /// let third = Rc::downgrade(&third_rc); /// assert!(!first.ptr_eq(&third)); /// ``` - /// - /// [`ptr::eq`]: core::ptr::eq #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { @@ -2400,7 +2394,6 @@ impl Default for Weak { /// Constructs a new `Weak`, without allocating any memory. /// Calling [`upgrade`] on the return value always gives [`None`]. /// - /// [`None`]: Option /// [`upgrade`]: Weak::upgrade /// /// # Examples diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 6568d9f9907b9..d88b8e398985a 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -79,7 +79,7 @@ use crate::vec::Vec; /// /// # Examples /// -/// You can create a `String` from [a literal string][`str`] with [`String::from`]: +/// You can create a `String` from [a literal string][`&str`] with [`String::from`]: /// /// [`String::from`]: From::from /// @@ -128,7 +128,7 @@ use crate::vec::Vec; /// println!("The first letter of s is {}", s[0]); // ERROR!!! /// ``` /// -/// [`OsString`]: ../../std/ffi/struct.OsString.html +/// [`OsString`]: ../../std/ffi/struct.OsString.html "ffi::OsString" /// /// Indexing is intended to be a constant-time operation, but UTF-8 encoding /// does not allow us to do this. Furthermore, it's not clear what sort of @@ -141,7 +141,7 @@ use crate::vec::Vec; /// /// # Deref /// -/// `String`s implement [`Deref`]``, and so inherit all of [`str`]'s +/// `String` implements [Deref], and so inherits all of [`str`]'s /// methods. In addition, this means that you can pass a `String` to a /// function which takes a [`&str`] by using an ampersand (`&`): /// @@ -182,7 +182,7 @@ use crate::vec::Vec; /// to explicitly extract the string slice containing the string. The second /// way changes `example_func(&example_string);` to /// `example_func(&*example_string);`. In this case we are dereferencing a -/// `String` to a [`str`][`&str`], then referencing the [`str`][`&str`] back to +/// `String` to a [`str`], then referencing the [`str`] back to /// [`&str`]. The second way is more idiomatic, however both work to do the /// conversion explicitly rather than relying on the implicit conversion. /// @@ -282,12 +282,14 @@ use crate::vec::Vec; /// /// Here, there's no need to allocate more memory inside the loop. /// -/// [`str`]: prim@str -/// [`&str`]: prim@str -/// [`Deref`]: core::ops::Deref +/// [str]: prim@str "str" +/// [`str`]: prim@str "str" +/// [`&str`]: prim@str "&str" +/// [Deref]: core::ops::Deref "ops::Deref" +/// [`Deref`]: core::ops::Deref "ops::Deref" /// [`as_str()`]: String::as_str #[derive(PartialOrd, Eq, Ord)] -#[cfg_attr(not(test), rustc_diagnostic_item = "string_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "String")] #[stable(feature = "rust1", since = "1.0.0")] pub struct String { vec: Vec, @@ -308,10 +310,10 @@ pub struct String { /// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error` /// through the [`utf8_error`] method. /// -/// [`Utf8Error`]: core::str::Utf8Error -/// [`std::str`]: core::str -/// [`&str`]: prim@str -/// [`utf8_error`]: Self::utf8_error +/// [`Utf8Error`]: str::Utf8Error "std::str::Utf8Error" +/// [`std::str`]: core::str "std::str" +/// [`&str`]: prim@str "&str" +/// [`utf8_error`]: FromUtf8Error::utf8_error /// /// # Examples /// @@ -487,8 +489,8 @@ impl String { /// with this error. /// /// [`from_utf8_unchecked`]: String::from_utf8_unchecked - /// [`Vec`]: crate::vec::Vec - /// [`&str`]: prim@str + /// [`Vec`]: crate::vec::Vec "Vec" + /// [`&str`]: prim@str "&str" /// [`into_bytes`]: String::into_bytes #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -524,7 +526,7 @@ impl String { /// it's already valid UTF-8, we don't need a new allocation. This return /// type allows us to handle both cases. /// - /// [`Cow<'a, str>`]: crate::borrow::Cow + /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow" /// /// # Examples /// @@ -625,7 +627,7 @@ impl String { /// conversion requires a memory allocation. /// /// [`from_utf8_lossy`]: String::from_utf8_lossy - /// [`Cow<'a, str>`]: crate::borrow::Cow + /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow" /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER /// /// # Examples @@ -1007,7 +1009,6 @@ impl String { /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// /// fn process_data(data: &str) -> Result { @@ -1023,7 +1024,7 @@ impl String { /// } /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.vec.try_reserve(additional) } @@ -1047,7 +1048,6 @@ impl String { /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// /// fn process_data(data: &str) -> Result { @@ -1063,7 +1063,7 @@ impl String { /// } /// # process_data("rust").expect("why is the test harness OOMing on 4 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.vec.try_reserve_exact(additional) } @@ -1721,11 +1721,11 @@ impl String { unsafe { self.as_mut_vec() }.splice((start, end), replace_with.bytes()); } - /// Converts this `String` into a [`Box`]`<`[`str`]`>`. + /// Converts this `String` into a [Box]<[str]>. /// /// This will drop any excess capacity. /// - /// [`str`]: prim@str + /// [str]: prim@str "str" /// /// # Examples /// @@ -1795,8 +1795,8 @@ impl FromUtf8Error { /// an analogue to `FromUtf8Error`. See its documentation for more details /// on using it. /// - /// [`std::str`]: core::str - /// [`&str`]: prim@str + /// [`std::str`]: core::str "std::str" + /// [`&str`]: prim@str "&str" /// /// # Examples /// @@ -2319,7 +2319,7 @@ impl ops::DerefMut for String { /// /// This alias exists for backwards compatibility, and may be eventually deprecated. /// -/// [`Infallible`]: core::convert::Infallible +/// [`Infallible`]: core::convert::Infallible "convert::Infallible" #[stable(feature = "str_parse_error", since = "1.5.0")] pub type ParseError = core::convert::Infallible; @@ -2606,7 +2606,7 @@ impl<'a> From<&'a str> for Cow<'a, str> { /// assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant")); /// ``` /// - /// [`Borrowed`]: crate::borrow::Cow::Borrowed + /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed" #[inline] fn from(s: &'a str) -> Cow<'a, str> { Cow::Borrowed(s) @@ -2629,7 +2629,7 @@ impl<'a> From for Cow<'a, str> { /// assert_eq!(Cow::from(s), Cow::<'static, str>::Owned(s2)); /// ``` /// - /// [`Owned`]: crate::borrow::Cow::Owned + /// [`Owned`]: crate::borrow::Cow::Owned "borrow::Cow::Owned" #[inline] fn from(s: String) -> Cow<'a, str> { Cow::Owned(s) @@ -2651,7 +2651,7 @@ impl<'a> From<&'a String> for Cow<'a, str> { /// assert_eq!(Cow::from(&s), Cow::Borrowed("eggplant")); /// ``` /// - /// [`Borrowed`]: crate::borrow::Cow::Borrowed + /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed" #[inline] fn from(s: &'a String) -> Cow<'a, str> { Cow::Borrowed(s.as_str()) diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index a066e0b49e25c..6e8da849e64cd 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -99,8 +99,8 @@ macro_rules! acquire { /// first: after all, isn't the point of `Arc` thread safety? The key is /// this: `Arc` makes it thread safe to have multiple ownership of the same /// data, but it doesn't add thread safety to its data. Consider -/// `Arc<`[`RefCell`]`>`. [`RefCell`] isn't [`Sync`], and if `Arc` was always -/// [`Send`], `Arc<`[`RefCell`]`>` would be as well. But then we'd have a problem: +/// Arc<[RefCell\]>. [`RefCell`] isn't [`Sync`], and if `Arc` was always +/// [`Send`], Arc<[RefCell\]> would be as well. But then we'd have a problem: /// [`RefCell`] is not thread safe; it keeps track of the borrowing count using /// non-atomic operations. /// @@ -176,6 +176,7 @@ macro_rules! acquire { /// [deref]: core::ops::Deref /// [downgrade]: Arc::downgrade /// [upgrade]: Weak::upgrade +/// [RefCell\]: core::cell::RefCell /// [`RefCell`]: core::cell::RefCell /// [`std::sync`]: ../../std/sync/index.html /// [`Arc::clone(&from)`]: Arc::clone @@ -206,7 +207,7 @@ macro_rules! acquire { /// /// Sharing a mutable [`AtomicUsize`]: /// -/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize +/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize "sync::atomic::AtomicUsize" /// /// ```no_run /// use std::sync::Arc; @@ -262,7 +263,7 @@ impl Arc { /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the /// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. +/// pointer, which returns an [Option]<[Arc]\>. /// /// Since a `Weak` reference does not count towards ownership, it will not /// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no @@ -476,7 +477,7 @@ impl Arc { /// assert_eq!(*zero, 0) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Arc> { @@ -684,7 +685,7 @@ impl Arc<[T]> { /// assert_eq!(*values, [0, 0, 0]) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit]> { @@ -712,7 +713,7 @@ impl Arc> { /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// @@ -751,7 +752,7 @@ impl Arc<[mem::MaybeUninit]> { /// Calling this when the content is not yet fully initialized /// causes immediate undefined behavior. /// - /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init + /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init /// /// # Examples /// @@ -1086,7 +1087,7 @@ impl Arc { /// assert!(!Arc::ptr_eq(&five, &other_five)); /// ``` /// - /// [`ptr::eq`]: core::ptr::eq + /// [`ptr::eq`]: core::ptr::eq "ptr::eq" pub fn ptr_eq(this: &Self, other: &Self) -> bool { this.ptr.as_ptr() == other.ptr.as_ptr() } @@ -1714,7 +1715,7 @@ impl Weak { /// // assert_eq!("hello", unsafe { &*weak.as_ptr() }); /// ``` /// - /// [`null`]: core::ptr::null + /// [`null`]: core::ptr::null "ptr::null" #[stable(feature = "weak_into_raw", since = "1.45.0")] pub fn as_ptr(&self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); @@ -1806,7 +1807,6 @@ impl Weak { /// [`new`]: Weak::new /// [`into_raw`]: Weak::into_raw /// [`upgrade`]: Weak::upgrade - /// [`forget`]: std::mem::forget #[stable(feature = "weak_into_raw", since = "1.45.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { // See Weak::as_ptr for context on how the input pointer is derived. @@ -1982,7 +1982,7 @@ impl Weak { /// assert!(!first.ptr_eq(&third)); /// ``` /// - /// [`ptr::eq`]: core::ptr::eq + /// [`ptr::eq`]: core::ptr::eq "ptr::eq" #[inline] #[stable(feature = "weak_ptr_eq", since = "1.39.0")] pub fn ptr_eq(&self, other: &Self) -> bool { diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 0bd152f17a670..18e191f2b59a2 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -22,6 +22,7 @@ use core::slice::{self}; /// let iter: std::vec::IntoIter<_> = v.into_iter(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct IntoIter< T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -160,6 +161,29 @@ impl Iterator for IntoIter { (exact, Some(exact)) } + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let step_size = self.len().min(n); + let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size); + if mem::size_of::() == 0 { + // SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound + // effectively results in unsigned pointers representing positions 0..usize::MAX, + // which is valid for ZSTs. + self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T } + } else { + // SAFETY: the min() above ensures that step_size is in bounds + self.ptr = unsafe { self.ptr.add(step_size) }; + } + // SAFETY: the min() above ensures that step_size is in bounds + unsafe { + ptr::drop_in_place(to_drop); + } + if step_size < n { + return Err(step_size); + } + Ok(()) + } + #[inline] fn count(self) -> usize { self.len() @@ -202,6 +226,29 @@ impl DoubleEndedIterator for IntoIter { Some(unsafe { ptr::read(self.end) }) } } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let step_size = self.len().min(n); + if mem::size_of::() == 0 { + // SAFETY: same as for advance_by() + self.end = unsafe { + arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T + } + } else { + // SAFETY: same as for advance_by() + self.end = unsafe { self.end.offset(step_size.wrapping_neg() as isize) }; + } + let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size); + // SAFETY: same as for advance_by() + unsafe { + ptr::drop_in_place(to_drop); + } + if step_size < n { + return Err(step_size); + } + Ok(()) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -219,14 +266,21 @@ unsafe impl TrustedLen for IntoIter {} #[doc(hidden)] #[unstable(issue = "none", feature = "std_internals")] +#[rustc_unsafe_specialization_marker] +pub trait NonDrop {} + // T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr // and thus we can't implement drop-handling -// +#[unstable(issue = "none", feature = "std_internals")] +impl NonDrop for T {} + +#[doc(hidden)] +#[unstable(issue = "none", feature = "std_internals")] // TrustedRandomAccess (without NoCoerce) must not be implemented because -// subtypes/supertypes of `T` might not be `Copy` +// subtypes/supertypes of `T` might not be `NonDrop` unsafe impl TrustedRandomAccessNoCoerce for IntoIter where - T: Copy, + T: NonDrop, { const MAY_HAVE_SIDE_EFFECT: bool = false; } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 2f6887229e7a3..4f18a054a0d98 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1,8 +1,8 @@ //! A contiguous growable array type with heap-allocated contents, written //! `Vec`. //! -//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and -//! `O(1)` pop (from the end). +//! Vectors have *O*(1) indexing, amortized *O*(1) push (to the end) and +//! *O*(1) pop (from the end). //! //! Vectors ensure they never allocate more than `isize::MAX` bytes. //! @@ -296,8 +296,8 @@ mod spec_extend; /// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized /// types inside a `Vec`, it will not allocate space for them. *Note that in this case /// the `Vec` might not report a [`capacity`] of 0*. `Vec` will allocate if and only -/// if [`mem::size_of::`]`() * capacity() > 0`. In general, `Vec`'s allocation -/// details are very subtle — if you intend to allocate memory using a `Vec` +/// if [mem::size_of::\]\() * [capacity]\() > 0. In general, `Vec`'s allocation +/// details are very subtle --- if you intend to allocate memory using a `Vec` /// and use it for something else (either to pass to unsafe code, or to build your /// own memory-backed collection), be sure to deallocate this memory by using /// `from_raw_parts` to recover the `Vec` and then dropping it. @@ -305,8 +305,8 @@ mod spec_extend; /// If a `Vec` *has* allocated memory, then the memory it points to is on the heap /// (as defined by the allocator Rust is configured to use by default), and its /// pointer points to [`len`] initialized, contiguous elements in order (what -/// you would see if you coerced it to a slice), followed by [`capacity`]` - -/// `[`len`] logically uninitialized, contiguous elements. +/// you would see if you coerced it to a slice), followed by [capacity] - [len] +/// logically uninitialized, contiguous elements. /// /// A vector containing the elements `'a'` and `'b'` with capacity 4 can be /// visualized as below. The top part is the `Vec` struct, it contains a @@ -348,7 +348,7 @@ mod spec_extend; /// /// [`push`] and [`insert`] will never (re)allocate if the reported capacity is /// sufficient. [`push`] and [`insert`] *will* (re)allocate if -/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely +/// [len] == [capacity]. That is, the reported capacity is completely /// accurate, and can be relied on. It can even be used to manually free the memory /// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even /// when not necessary. @@ -360,7 +360,7 @@ mod spec_extend; /// /// `vec![x; n]`, `vec![a, b, c, d]`, and /// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec` -/// with exactly the requested capacity. If [`len`]` == `[`capacity`], +/// with exactly the requested capacity. If [len] == [capacity], /// (as is the case for the [`vec!`] macro), then a `Vec` can be converted to /// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements. /// @@ -369,7 +369,7 @@ mod spec_extend; /// scratch space that it may use however it wants. It will generally just do /// whatever is most efficient or otherwise easy to implement. Do not rely on /// removed data to be erased for security purposes. Even if you drop a `Vec`, its -/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory +/// buffer may simply be reused by another allocation. Even if you zero a `Vec`'s memory /// first, that might not actually happen because the optimizer does not consider /// this a side-effect that must be preserved. There is one case which we will /// not break, however: using `unsafe` code to write to the excess capacity, @@ -384,8 +384,10 @@ mod spec_extend; /// [`&str`]: type@str /// [`shrink_to_fit`]: Vec::shrink_to_fit /// [`shrink_to`]: Vec::shrink_to +/// [capacity]: Vec::capacity /// [`capacity`]: Vec::capacity -/// [`mem::size_of::`]: core::mem::size_of +/// [mem::size_of::\]: core::mem::size_of +/// [len]: Vec::len /// [`len`]: Vec::len /// [`push`]: Vec::push /// [`insert`]: Vec::insert @@ -393,7 +395,8 @@ mod spec_extend; /// [`MaybeUninit`]: core::mem::MaybeUninit /// [owned slice]: Box #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Vec")] +#[rustc_insignificant_dtor] pub struct Vec { buf: RawVec, len: usize, @@ -846,7 +849,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// /// fn process_data(data: &[u32]) -> Result, TryReserveError> { @@ -864,7 +866,7 @@ impl Vec { /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve(self.len, additional) } @@ -889,7 +891,6 @@ impl Vec { /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::TryReserveError; /// /// fn process_data(data: &[u32]) -> Result, TryReserveError> { @@ -907,7 +908,7 @@ impl Vec { /// } /// # process_data(&[1, 2, 3]).expect("why is the test harness OOMing on 12 bytes?"); /// ``` - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { self.buf.try_reserve_exact(self.len, additional) } @@ -1268,7 +1269,7 @@ impl Vec { /// /// The removed element is replaced by the last element of the vector. /// - /// This does not preserve ordering, but is O(1). + /// This does not preserve ordering, but is *O*(1). /// /// # Panics /// @@ -1485,7 +1486,15 @@ impl Vec { let mut g = BackshiftOnDrop { v: self, processed_len: 0, deleted_cnt: 0, original_len }; - while g.processed_len < original_len { + // process_one return a bool indicates whether the processing element should be retained. + #[inline(always)] + fn process_one( + f: &mut F, + g: &mut BackshiftOnDrop<'_, T, A>, + ) -> bool + where + F: FnMut(&T) -> bool, + { // SAFETY: Unchecked element must be valid. let cur = unsafe { &mut *g.v.as_mut_ptr().add(g.processed_len) }; if !f(cur) { @@ -1495,9 +1504,9 @@ impl Vec { // SAFETY: We never touch this element again after dropped. unsafe { ptr::drop_in_place(cur) }; // We already advanced the counter. - continue; + return false; } - if g.deleted_cnt > 0 { + if DELETED { // SAFETY: `deleted_cnt` > 0, so the hole slot must not overlap with current element. // We use copy for move, and never touch this element again. unsafe { @@ -1506,6 +1515,19 @@ impl Vec { } } g.processed_len += 1; + return true; + } + + // Stage 1: Nothing was deleted. + while g.processed_len != original_len { + if !process_one::(&mut f, &mut g) { + break; + } + } + + // Stage 2: Some elements were deleted. + while g.processed_len != original_len { + process_one::(&mut f, &mut g); } // All item are processed. This can be optimized to `set_len` by LLVM. @@ -2113,6 +2135,7 @@ impl Vec { /// in order to be able to clone the passed value. /// If you need more flexibility (or want to rely on [`Default`] instead of /// [`Clone`]), use [`Vec::resize_with`]. + /// If you only need to resize to a smaller size, use [`Vec::truncate`]. /// /// # Examples /// @@ -2164,7 +2187,12 @@ impl Vec { /// Copies elements from `src` range to the end of the vector. /// - /// ## Examples + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples /// /// ``` /// let mut vec = vec![0, 1, 2, 3, 4]; diff --git a/library/alloc/src/vec/source_iter_marker.rs b/library/alloc/src/vec/source_iter_marker.rs index e05788d99c0df..6e78534cf5b10 100644 --- a/library/alloc/src/vec/source_iter_marker.rs +++ b/library/alloc/src/vec/source_iter_marker.rs @@ -6,24 +6,14 @@ use super::{AsIntoIter, InPlaceDrop, SpecFromIter, SpecFromIterNested, Vec}; /// Specialization marker for collecting an iterator pipeline into a Vec while reusing the /// source allocation, i.e. executing the pipeline in place. -/// -/// The SourceIter parent trait is necessary for the specializing function to access the allocation -/// which is to be reused. But it is not sufficient for the specialization to be valid. See -/// additional bounds on the impl. #[rustc_unsafe_specialization_marker] -pub(super) trait SourceIterMarker: SourceIter {} +pub(super) trait InPlaceIterableMarker {} -// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of -// Adapter>> (all owned by core/std). Additional bounds -// on the adapter implementations (beyond `impl Trait for Adapter`) only depend on other -// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator). -// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which -// several other specializations already depend on. -impl SourceIterMarker for T where T: SourceIter + InPlaceIterable {} +impl InPlaceIterableMarker for T where T: InPlaceIterable {} impl SpecFromIter for Vec where - I: Iterator + SourceIterMarker, + I: Iterator + SourceIter + InPlaceIterableMarker, { default fn from_iter(mut iterator: I) -> Self { // Additional requirements which cannot expressed via trait bounds. We rely on const eval diff --git a/library/alloc/tests/btree_set_hash.rs b/library/alloc/tests/btree_set_hash.rs index e06a95ded94c7..ab275ac4353ac 100644 --- a/library/alloc/tests/btree_set_hash.rs +++ b/library/alloc/tests/btree_set_hash.rs @@ -1,9 +1,8 @@ +use crate::hash; use std::collections::BTreeSet; #[test] fn test_hash() { - use crate::hash; - let mut x = BTreeSet::new(); let mut y = BTreeSet::new(); @@ -17,3 +16,14 @@ fn test_hash() { assert_eq!(hash(&x), hash(&y)); } + +#[test] +fn test_prefix_free() { + let x = BTreeSet::from([1, 2, 3]); + let y = BTreeSet::::new(); + + // If hashed by iteration alone, `(x, y)` and `(y, x)` would visit the same + // order of elements, resulting in the same hash. But now that we also hash + // the length, they get distinct sequences of hashed data. + assert_ne!(hash(&(&x, &y)), hash(&(&y, &x))); +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index cae4dae708e59..8c57c804ad2dc 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -8,7 +8,6 @@ #![feature(new_uninit)] #![feature(pattern)] #![feature(trusted_len)] -#![feature(try_reserve)] #![feature(try_reserve_kind)] #![feature(unboxed_closures)] #![feature(associated_type_bounds)] @@ -18,6 +17,7 @@ #![feature(binary_heap_retain)] #![feature(binary_heap_as_slice)] #![feature(inplace_iteration)] +#![feature(iter_advance_by)] #![feature(slice_group_by)] #![feature(slice_partition_dedup)] #![feature(vec_spare_capacity)] diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index c2df50b48f55d..00a878c079480 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -970,6 +970,24 @@ fn test_into_iter_leak() { assert_eq!(unsafe { DROPS }, 3); } +#[test] +fn test_into_iter_advance_by() { + let mut i = vec![1, 2, 3, 4, 5].into_iter(); + i.advance_by(0).unwrap(); + i.advance_back_by(0).unwrap(); + assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]); + + i.advance_by(1).unwrap(); + i.advance_back_by(1).unwrap(); + assert_eq!(i.as_slice(), [2, 3, 4]); + + assert_eq!(i.advance_back_by(usize::MAX), Err(3)); + + assert_eq!(i.advance_by(usize::MAX), Err(0)); + + assert_eq!(i.len(), 0); +} + #[test] fn test_from_iter_specialization() { let src: Vec = vec![0usize; 1]; diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs index de4ef7949f344..82c1789c24dad 100644 --- a/library/core/benches/lib.rs +++ b/library/core/benches/lib.rs @@ -15,3 +15,4 @@ mod num; mod ops; mod pattern; mod slice; +mod str; diff --git a/library/core/benches/str.rs b/library/core/benches/str.rs new file mode 100644 index 0000000000000..1527aa0bd6640 --- /dev/null +++ b/library/core/benches/str.rs @@ -0,0 +1,33 @@ +use std::str; +use test::{black_box, Bencher}; + +const LOREM_SHORT: &str = "Lorem ipsum"; + +const LOREM: &str = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. +Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. +Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis. +At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur"; + +const EMOJI: &str = "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗☺😚😙🥲😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😶‍🌫️😏😒🙄😬😮‍💨🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵😵‍💫🤯🤠🥳🥸😎🤓🧐😕😟🙁☹😮😯😲😳🥺😦😧😨😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬😈👿💀☠💩🤡👹👺👻👽👾🤖😺😸😹😻😼😽🙀😿😾🙈🙉🙊💋💌💘💝💖💗💓💞💕💟❣💔❤️‍🔥❤️‍🩹❤🧡💛💚💙💜🤎🖤🤍💯💢💥💫💦💨🕳💣💬👁️‍🗨️🗨🗯💭💤👋🤚🖐✋🖖👌🤌🤏✌🤞🤟🤘🤙👈👉👆🖕👇☝👍👎✊👊🤛🤜👏🙌👐🤲🤝🙏✍💅🤳💪🦾🦿🦵🦶👂🦻👃🧠🫀🫁🦷🦴👀👁👅👄👶🧒👦👧🧑👱👨🧔🧔‍♂️🧔‍♀️👨‍🦰👨‍🦱👨‍🦳👨‍🦲👩👩‍🦰🧑‍🦰👩‍🦱🧑‍🦱👩‍🦳🧑‍🦳👩‍🦲🧑‍🦲👱‍♀️👱‍♂️🧓👴👵🙍🙍‍♂️🙍‍♀️🙎🙎‍♂️🙎‍♀️🙅🙅‍♂️🙅‍♀️🙆🙆‍♂️🙆‍♀️💁💁‍♂️💁‍♀️🙋🙋‍♂️🙋‍♀️🧏🧏‍♂️🧏‍♀️🙇🙇‍♂️🙇‍♀️🤦🤦‍♂️🤦‍♀️🤷🤷‍♂️🤷‍♀️🧑‍⚕️👨‍⚕️👩‍⚕️🧑‍🎓👨‍🎓👩‍🎓🧑‍🏫👨‍🏫👩‍🏫🧑‍⚖️👨‍⚖️👩‍⚖️🧑‍🌾👨‍🌾👩‍🌾🧑‍🍳👨‍🍳👩‍🍳🧑‍🔧👨‍🔧👩‍🔧🧑‍🏭👨‍🏭👩‍🏭🧑‍💼👨‍💼👩‍💼🧑‍🔬👨‍🔬👩‍🔬🧑‍💻👨‍💻👩‍💻🧑‍🎤👨‍🎤👩‍🎤🧑‍🎨👨‍🎨👩‍🎨🧑‍✈️👨‍✈️👩‍✈️🧑‍🚀👨‍🚀👩‍🚀🧑‍🚒👨‍🚒👩‍🚒👮👮‍♂️👮‍♀️🕵🕵️‍♂️🕵️‍♀️💂💂‍♂️💂‍♀️🥷👷👷‍♂️👷‍♀️🤴👸👳👳‍♂️👳‍♀️👲🧕🤵🤵‍♂️🤵‍♀️👰👰‍♂️👰‍♀️🤰🤱👩‍🍼👨‍🍼🧑‍🍼👼🎅🤶🧑‍🎄🦸🦸‍♂️🦸‍♀️🦹🦹‍♂️🦹‍♀️🧙🧙‍♂️🧙‍♀️🧚🧚‍♂️🧚‍♀️🧛🧛‍♂️🧛‍♀️🧜🧜‍♂️🧜‍♀️🧝🧝‍♂️🧝‍♀️🧞🧞‍♂️🧞‍♀️🧟🧟‍♂️🧟‍♀️💆💆‍♂️💆‍♀️💇💇‍♂️💇‍♀️🚶🚶‍♂️🚶‍♀️🧍🧍‍♂️🧍‍♀️🧎🧎‍♂️🧎‍♀️🧑‍🦯👨‍🦯👩‍🦯🧑‍🦼👨‍🦼👩‍🦼🧑‍🦽👨‍🦽👩‍🦽🏃🏃‍♂️🏃‍♀️💃🕺🕴👯👯‍♂️👯‍♀️🧖🧖‍♂️🧖‍♀️🧗🧗‍♂️🧗‍♀️🤺🏇⛷🏂🏌🏌️‍♂️🏌️‍♀️🏄🏄‍♂️🏄‍♀️🚣🚣‍♂️🚣‍♀️🏊🏊‍♂️🏊‍♀️⛹⛹️‍♂️⛹️‍♀️🏋🏋️‍♂️🏋️‍♀️🚴🚴‍♂️🚴‍♀️🚵🚵‍♂️🚵‍♀️🤸🤸‍♂️🤸‍♀️🤼🤼‍♂️🤼‍♀️🤽🤽‍♂️🤽‍♀️🤾🤾‍♂️🤾‍♀️🤹🤹‍♂️🤹‍♀️🧘🧘‍♂️🧘‍♀️🛀🛌🧑‍🤝‍🧑👭👫👬💏👩‍❤️‍💋‍👨👨‍❤️‍💋‍👨👩‍❤️‍💋‍👩💑👩‍❤️‍👨👨‍❤️‍👨👩‍❤️‍👩👪👨‍👩‍👦👨‍👩‍👧👨‍👩‍👧‍👦👨‍👩‍👦‍👦👨‍👩‍👧‍👧👨‍👨‍👦👨‍👨‍👧👨‍👨‍👧‍👦👨‍👨‍👦‍👦👨‍👨‍👧‍👧👩‍👩‍👦👩‍👩‍👧👩‍👩‍👧‍👦👩‍👩‍👦‍👦👩‍👩‍👧‍👧👨‍👦👨‍👦‍👦👨‍👧👨‍👧‍👦👨‍👧‍👧👩‍👦👩‍👦‍👦👩‍👧👩‍👧‍👦👩‍👧‍👧🗣👤👥🫂👣🦰🦱🦳🦲🐵🐒🦍🦧🐶🐕🦮🐕‍🦺🐩🐺🦊🦝🐱🐈🐈‍⬛🦁🐯🐅🐆🐴🐎🦄🦓🦌🦬🐮🐂🐃🐄🐷🐖🐗🐽🐏🐑🐐🐪🐫🦙🦒🐘🦣🦏🦛🐭🐁🐀🐹🐰🐇🐿🦫🦔🦇🐻🐻‍❄️🐨🐼🦥🦦🦨🦘🦡🐾🦃🐔🐓🐣🐤🐥🐦🐧🕊🦅🦆🦢🦉🦤🪶🦩🦚🦜🐸🐊🐢🦎🐍🐲🐉🦕🦖🐳🐋🐬🦭🐟🐠🐡🦈🐙🐚🐌🦋🐛🐜🐝🪲🐞🦗🪳🕷🕸🦂🦟🪰🪱🦠💐🌸💮🏵🌹🥀🌺🌻🌼🌷🌱🪴🌲🌳🌴🌵🌾🌿☘🍀🍁🍂🍃🍇🍈🍉🍊🍋🍌🍍🥭🍎🍏🍐🍑🍒🍓🫐🥝🍅🫒🥥🥑🍆🥔🥕🌽🌶🫑🥒🥬🥦🧄🧅🍄🥜🌰🍞🥐🥖🫓🥨🥯🥞🧇🧀🍖🍗🥩🥓🍔🍟🍕🌭🥪🌮🌯🫔🥙🧆🥚🍳🥘🍲🫕🥣🥗🍿🧈🧂🥫🍱🍘🍙🍚🍛🍜🍝🍠🍢🍣🍤🍥🥮🍡🥟🥠🥡🦀🦞🦐🦑🦪🍦🍧🍨🍩🍪🎂🍰🧁🥧🍫🍬🍭🍮🍯🍼🥛☕🫖🍵🍶🍾🍷🍸🍹🍺🍻🥂🥃🥤🧋🧃🧉🧊🥢🍽🍴🥄🔪🏺🌍🌎🌏🌐🗺🗾🧭🏔⛰🌋🗻🏕🏖🏜🏝🏞🏟🏛🏗🧱🪨🪵🛖🏘🏚🏠🏡🏢🏣🏤🏥🏦🏨🏩🏪🏫🏬🏭🏯🏰💒🗼🗽⛪🕌🛕🕍⛩🕋⛲⛺🌁🌃🏙🌄🌅🌆🌇🌉♨🎠🎡🎢💈🎪🚂🚃🚄🚅🚆🚇🚈🚉🚊🚝🚞🚋🚌🚍🚎🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🛻🚚🚛🚜🏎🏍🛵🦽🦼🛺🚲🛴🛹🛼🚏🛣🛤🛢⛽🚨🚥🚦🛑🚧⚓⛵🛶🚤🛳⛴🛥🚢✈🛩🛫🛬🪂💺🚁🚟🚠🚡🛰🚀🛸🛎🧳⌛⏳⌚⏰⏱⏲🕰🕛🕧🕐🕜🕑🕝🕒🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌡☀🌝🌞🪐⭐🌟🌠🌌☁⛅⛈🌤🌥🌦🌧🌨🌩🌪🌫🌬🌀🌈🌂☂☔⛱⚡❄☃⛄☄🔥💧🌊🎃🎄🎆🎇🧨✨🎈🎉🎊🎋🎍🎎🎏🎐🎑🧧🎀🎁🎗🎟🎫🎖🏆🏅🥇🥈🥉⚽⚾🥎🏀🏐🏈🏉🎾🥏🎳🏏🏑🏒🥍🏓🏸🥊🥋🥅⛳⛸🎣🤿🎽🎿🛷🥌🎯🪀🪁🎱🔮🪄🧿🎮🕹🎰🎲🧩🧸🪅🪆♠♥♦♣♟🃏🀄🎴🎭🖼🎨🧵🪡🧶🪢👓🕶🥽🥼🦺👔👕👖🧣🧤🧥🧦👗👘🥻🩱🩲🩳👙👚👛👜👝🛍🎒🩴👞👟🥾🥿👠👡🩰👢👑👒🎩🎓🧢🪖⛑📿💄💍💎🔇🔈🔉🔊📢📣📯🔔🔕🎼🎵🎶🎙🎚🎛🎤🎧📻🎷🪗🎸🎹🎺🎻🪕🥁"; + +#[bench] +fn str_char_count_lorem(b: &mut Bencher) { + b.iter(|| black_box(LOREM).chars().count()); +} + +#[bench] +fn str_char_count_lorem_short(b: &mut Bencher) { + b.iter(|| black_box(LOREM_SHORT).chars().count()); +} + +#[bench] +fn str_char_count_emoji(b: &mut Bencher) { + b.iter(|| black_box(EMOJI).chars().count()); +} + +#[bench] +fn str_validate_emoji(b: &mut Bencher) { + b.iter(|| str::from_utf8(black_box(EMOJI.as_bytes()))); +} diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index ecdbf09881985..822747dd0e824 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -10,6 +10,7 @@ use crate::{ /// A by-value [array] iterator. #[stable(feature = "array_value_iter", since = "1.51.0")] +#[rustc_insignificant_dtor] pub struct IntoIter { /// This is the array we are iterating over. /// diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 8c33a43ab330e..09329247f9492 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -368,14 +368,14 @@ impl [T; N] { } /// Returns a slice containing the entire array. Equivalent to `&s[..]`. - #[unstable(feature = "array_methods", issue = "76118")] - pub fn as_slice(&self) -> &[T] { + #[stable(feature = "array_as_slice", since = "1.57.0")] + pub const fn as_slice(&self) -> &[T] { self } /// Returns a mutable slice containing the entire array. Equivalent to /// `&mut s[..]`. - #[unstable(feature = "array_methods", issue = "76118")] + #[stable(feature = "array_as_slice", since = "1.57.0")] pub fn as_mut_slice(&mut self) -> &mut [T] { self } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index e56b631dbaf8d..025ad54b539f5 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1303,6 +1303,11 @@ impl Clone for BorrowRef<'_> { /// /// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a Ref across suspend \ + points can cause BorrowErrors" +)] pub struct Ref<'b, T: ?Sized + 'b> { value: &'b T, borrow: BorrowRef<'b>, @@ -1679,6 +1684,11 @@ impl<'b> BorrowRefMut<'b> { /// /// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a RefMut across suspend \ + points can cause BorrowErrors" +)] pub struct RefMut<'b, T: ?Sized + 'b> { value: &'b mut T, borrow: BorrowRefMut<'b>, diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 1e512af48051e..abeeef1a17ee0 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -269,7 +269,7 @@ pub trait AsMut { /// /// [`String`]: ../../std/string/struct.String.html /// [`Vec`]: ../../std/vec/struct.Vec.html -#[rustc_diagnostic_item = "into_trait"] +#[rustc_diagnostic_item = "Into"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { /// Performs the conversion. @@ -358,7 +358,7 @@ pub trait Into: Sized { /// [`String`]: ../../std/string/struct.String.html /// [`from`]: From::from /// [book]: ../../book/ch09-00-error-handling.html -#[rustc_diagnostic_item = "from_trait"] +#[rustc_diagnostic_item = "From"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(on( all(_Self = "&str", T = "std::string::String"), @@ -385,7 +385,7 @@ pub trait From: Sized { /// /// This suffers the same restrictions and reasoning as implementing /// [`Into`], see there for details. -#[rustc_diagnostic_item = "try_into_trait"] +#[rustc_diagnostic_item = "TryInto"] #[stable(feature = "try_from", since = "1.34.0")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. @@ -465,7 +465,7 @@ pub trait TryInto: Sized { /// ``` /// /// [`try_from`]: TryFrom::try_from -#[rustc_diagnostic_item = "try_from_trait"] +#[rustc_diagnostic_item = "TryFrom"] #[stable(feature = "try_from", since = "1.34.0")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 8fa941c42fc21..d10563a40976d 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -270,9 +270,10 @@ pub struct ArgumentV1<'a> { /// of `format_args!(..)` and reduce the scope of the `unsafe` block. #[allow(missing_debug_implementations)] #[doc(hidden)] -#[non_exhaustive] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] -pub struct UnsafeArg; +pub struct UnsafeArg { + _private: (), +} impl UnsafeArg { /// See documentation where `UnsafeArg` is required to know when it is safe to @@ -281,7 +282,7 @@ impl UnsafeArg { #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] #[inline(always)] pub unsafe fn new() -> Self { - Self + Self { _private: () } } } @@ -616,7 +617,7 @@ impl Display for Arguments<'_> { label = "`{Self}` cannot be formatted using `{{:?}}` because it doesn't implement `{Debug}`" )] #[doc(alias = "{:?}")] -#[rustc_diagnostic_item = "debug_trait"] +#[rustc_diagnostic_item = "Debug"] #[cfg_attr(not(bootstrap), rustc_trivial_field_reads)] pub trait Debug { /// Formats the value using the given formatter. @@ -709,7 +710,7 @@ pub use macros::Debug; note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead" )] #[doc(alias = "{}")] -#[rustc_diagnostic_item = "display_trait"] +#[rustc_diagnostic_item = "Display"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Display { /// Formats the value using the given formatter. @@ -1002,7 +1003,7 @@ pub trait UpperHex { /// assert_eq!(&l_ptr[..2], "0x"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "pointer_trait"] +#[rustc_diagnostic_item = "Pointer"] pub trait Pointer { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] @@ -1224,7 +1225,7 @@ unsafe fn getcount(args: &[ArgumentV1<'_>], cnt: &rt::v1::Count) -> Option Result { + pub(crate) fn write(self, f: &mut Formatter<'_>) -> Result { for _ in 0..self.padding { - buf.write_char(self.fill)?; + f.buf.write_char(self.fill)?; } Ok(()) } @@ -1360,7 +1361,7 @@ impl<'a> Formatter<'a> { write_prefix(self, sign, prefix)?; let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; self.buf.write_str(buf)?; - post_padding.write(self.buf)?; + post_padding.write(self)?; self.fill = old_fill; self.align = old_align; Ok(()) @@ -1370,7 +1371,7 @@ impl<'a> Formatter<'a> { let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; write_prefix(self, sign, prefix)?; self.buf.write_str(buf)?; - post_padding.write(self.buf) + post_padding.write(self) } } } @@ -1445,7 +1446,7 @@ impl<'a> Formatter<'a> { let align = rt::v1::Alignment::Left; let post_padding = self.padding(width - chars_count, align)?; self.buf.write_str(s)?; - post_padding.write(self.buf) + post_padding.write(self) } } } @@ -1454,7 +1455,7 @@ impl<'a> Formatter<'a> { /// Write the pre-padding and return the unwritten post-padding. Callers are /// responsible for ensuring post-padding is written after the thing that is /// being padded. - fn padding( + pub(crate) fn padding( &mut self, padding: usize, default: rt::v1::Alignment, @@ -1509,7 +1510,7 @@ impl<'a> Formatter<'a> { } else { let post_padding = self.padding(width - len, align)?; self.write_formatted_parts(&formatted)?; - post_padding.write(self.buf) + post_padding.write(self) }; self.fill = old_fill; self.align = old_align; diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index db45640df48d6..05ca50a97a644 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -305,7 +305,6 @@ macro_rules! impl_Exp { n /= 10; exponent += 1; } - let trailing_zeros = exponent; let (added_precision, subtracted_precision) = match f.precision() { Some(fmt_prec) => { @@ -333,7 +332,7 @@ macro_rules! impl_Exp { n += 1; } } - (n, exponent, trailing_zeros, added_precision) + (n, exponent, exponent, added_precision) }; // 39 digits (worst case u128) + . = 40 diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 3d3c8da678b8b..e5f2886dcafad 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -76,6 +76,11 @@ where self.it.count() } + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.it.advance_by(n) + } + #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where @@ -112,6 +117,11 @@ where { self.it.rfold(init, copy_fold(f)) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.it.advance_back_by(n) + } } #[stable(feature = "iter_copied", since = "1.36.0")] diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs index 815e708f9ec0f..02b5939072ef0 100644 --- a/library/core/src/iter/adapters/cycle.rs +++ b/library/core/src/iter/adapters/cycle.rs @@ -79,6 +79,27 @@ where } } + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + match self.iter.advance_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + + while rem > 0 { + self.iter = self.orig.clone(); + match self.iter.advance_by(rem) { + ret @ Ok(_) => return ret, + Err(0) => return Err(n - rem), + Err(advanced) => rem -= advanced, + } + } + + Ok(()) + } + // No `fold` override, because `fold` doesn't make much sense for `Cycle`, // and we can't do anything better than the default. } diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 3478a0cd40832..84e4618844a61 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -112,6 +112,21 @@ where self.iter.fold(init, enumerate(self.count, fold)) } + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + match self.iter.advance_by(n) { + ret @ Ok(_) => { + self.count += n; + ret + } + ret @ Err(advanced) => { + self.count += advanced; + ret + } + } + } + #[rustc_inherit_overflow_checks] #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item @@ -191,6 +206,13 @@ where let count = self.count + self.iter.len(); self.iter.rfold(init, enumerate(count, fold)) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + // we do not need to update the count since that only tallies the number of items + // consumed from the front. consuming items from the back can never reduce that. + self.iter.advance_back_by(n) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -227,14 +249,14 @@ impl FusedIterator for Enumerate where I: FusedIterator {} unsafe impl TrustedLen for Enumerate where I: TrustedLen {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Enumerate +unsafe impl SourceIter for Enumerate where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index d5f19f127470e..a0afaa326ad63 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -135,15 +135,14 @@ where impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Filter +unsafe impl SourceIter for Filter where - P: FnMut(&I::Item) -> bool, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index 01b7be9d52daf..e0d665c9e12ba 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -129,15 +129,14 @@ where impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for FilterMap +unsafe impl SourceIter for FilterMap where - F: FnMut(I::Item) -> Option, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 48880a4d91a57..351fd569d8acf 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -391,6 +391,41 @@ where init } + + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + loop { + if let Some(ref mut front) = self.frontiter { + match front.advance_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + } + self.frontiter = match self.iter.next() { + Some(iterable) => Some(iterable.into_iter()), + _ => break, + } + } + + self.frontiter = None; + + if let Some(ref mut back) = self.backiter { + match back.advance_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + } + + if rem > 0 { + return Err(n - rem); + } + + self.backiter = None; + + Ok(()) + } } impl DoubleEndedIterator for FlattenCompat @@ -486,6 +521,41 @@ where init } + + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + loop { + if let Some(ref mut back) = self.backiter { + match back.advance_back_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + } + match self.iter.next_back() { + Some(iterable) => self.backiter = Some(iterable.into_iter()), + _ => break, + } + } + + self.backiter = None; + + if let Some(ref mut front) = self.frontiter { + match front.advance_back_by(rem) { + ret @ Ok(_) => return ret, + Err(advanced) => rem -= advanced, + } + } + + if rem > 0 { + return Err(n - rem); + } + + self.frontiter = None; + + Ok(()) + } } trait ConstSizeIntoIterator: IntoIterator { diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs index 36835d12e5685..19839fdfe5bc3 100644 --- a/library/core/src/iter/adapters/inspect.rs +++ b/library/core/src/iter/adapters/inspect.rs @@ -149,15 +149,14 @@ where impl FusedIterator for Inspect where F: FnMut(&I::Item) {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Inspect +unsafe impl SourceIter for Inspect where - F: FnMut(&I::Item), - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs index bd21872e1ad4b..d8bbd424cf258 100644 --- a/library/core/src/iter/adapters/intersperse.rs +++ b/library/core/src/iter/adapters/intersperse.rs @@ -4,7 +4,7 @@ use super::Peekable; /// /// This `struct` is created by [`Iterator::intersperse`]. See its documentation /// for more information. -#[stable(feature = "iter_intersperse", since = "1.56.0")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] #[derive(Debug, Clone)] pub struct Intersperse where @@ -24,7 +24,7 @@ where } } -#[stable(feature = "iter_intersperse", since = "1.56.0")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl Iterator for Intersperse where I: Iterator, @@ -61,7 +61,7 @@ where /// /// This `struct` is created by [`Iterator::intersperse_with`]. See its /// documentation for more information. -#[stable(feature = "iter_intersperse", since = "1.56.0")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub struct IntersperseWith where I: Iterator, @@ -71,7 +71,7 @@ where needs_sep: bool, } -#[stable(feature = "iter_intersperse", since = "1.56.0")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl crate::fmt::Debug for IntersperseWith where I: Iterator + crate::fmt::Debug, @@ -87,7 +87,7 @@ where } } -#[stable(feature = "iter_intersperse", since = "1.56.0")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl crate::clone::Clone for IntersperseWith where I: Iterator + crate::clone::Clone, @@ -113,7 +113,7 @@ where } } -#[stable(feature = "iter_intersperse", since = "1.56.0")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] impl Iterator for IntersperseWith where I: Iterator, diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 763e253e75a51..449650a22f435 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -201,15 +201,14 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Map +unsafe impl SourceIter for Map where - F: FnMut(I::Item) -> B, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs index 793b05fcf9529..1e8d6bf3e00e1 100644 --- a/library/core/src/iter/adapters/map_while.rs +++ b/library/core/src/iter/adapters/map_while.rs @@ -80,15 +80,14 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for MapWhile +unsafe impl SourceIter for MapWhile where - P: FnMut(I::Item) -> Option, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 48e7dcfa7d9a3..9e1f4e425f9e3 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -42,7 +42,7 @@ pub use self::flatten::Flatten; #[stable(feature = "iter_copied", since = "1.36.0")] pub use self::copied::Copied; -#[stable(feature = "iter_intersperse", since = "1.56.0")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::intersperse::{Intersperse, IntersperseWith}; #[stable(feature = "iter_map_while", since = "1.57.0")] @@ -92,9 +92,10 @@ pub use self::zip::zip; /// [`as_inner`]: SourceIter::as_inner #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] +#[rustc_specialization_trait] pub unsafe trait SourceIter { /// A source stage in an iterator pipeline. - type Source: Iterator; + type Source; /// Retrieve the source of an iterator pipeline. /// @@ -200,14 +201,14 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for ResultShunt<'_, I, E> +unsafe impl SourceIter for ResultShunt<'_, I, E> where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut Self::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index 91fa1a9ad351c..20aca323bab79 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -321,14 +321,14 @@ impl Peekable { unsafe impl TrustedLen for Peekable where I: TrustedLen {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Peekable +unsafe impl SourceIter for Peekable where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs index 96705b01f661f..80bfd2231241b 100644 --- a/library/core/src/iter/adapters/scan.rs +++ b/library/core/src/iter/adapters/scan.rs @@ -90,15 +90,14 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Scan +unsafe impl SourceIter for Scan where - I: SourceIter, - F: FnMut(&mut St, I::Item) -> Option, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index c358a6d12b7bc..565fc224f53ca 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -114,6 +114,38 @@ where } self.iter.fold(init, fold) } + + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + + let step_one = self.n.saturating_add(rem); + match self.iter.advance_by(step_one) { + Ok(_) => { + rem -= step_one - self.n; + self.n = 0; + } + Err(advanced) => { + let advanced_without_skip = advanced.saturating_sub(self.n); + self.n = self.n.saturating_sub(advanced); + return Err(advanced_without_skip); + } + } + + // step_one calculation may have saturated + if unlikely(rem > 0) { + return match self.iter.advance_by(rem) { + ret @ Ok(_) => ret, + Err(advanced) => { + rem -= advanced; + Err(n - rem) + } + }; + } + + Ok(()) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -174,20 +206,30 @@ where self.try_rfold(init, ok(fold)).unwrap() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let min = crate::cmp::min(self.len(), n); + return match self.iter.advance_back_by(min) { + ret @ Ok(_) if n <= min => ret, + Ok(_) => Err(min), + _ => panic!("ExactSizeIterator contract violation"), + }; + } } #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Skip where I: FusedIterator {} #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Skip +unsafe impl SourceIter for Skip where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs index 93e29edc8df39..f29661779c056 100644 --- a/library/core/src/iter/adapters/skip_while.rs +++ b/library/core/src/iter/adapters/skip_while.rs @@ -105,15 +105,14 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for SkipWhile +unsafe impl SourceIter for SkipWhile where - P: FnMut(&I::Item) -> bool, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index beda8c32c6bdc..81f6c294fac13 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -111,17 +111,33 @@ where self.try_fold(init, ok(fold)).unwrap() } + + #[inline] + #[rustc_inherit_overflow_checks] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let min = self.n.min(n); + match self.iter.advance_by(min) { + Ok(_) => { + self.n -= min; + if min < n { Err(min) } else { Ok(()) } + } + ret @ Err(advanced) => { + self.n -= advanced; + ret + } + } + } } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Take +unsafe impl SourceIter for Take where - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } @@ -197,6 +213,24 @@ where } } } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let inner_len = self.iter.len(); + let len = self.n; + let remainder = len.saturating_sub(n); + let to_advance = inner_len - remainder; + match self.iter.advance_back_by(to_advance) { + Ok(_) => { + self.n = remainder; + if n > len { + return Err(len); + } + return Ok(()); + } + _ => panic!("ExactSizeIterator contract violation"), + } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs index 93457d20f7c23..ded216da952a3 100644 --- a/library/core/src/iter/adapters/take_while.rs +++ b/library/core/src/iter/adapters/take_while.rs @@ -118,15 +118,14 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for TakeWhile +unsafe impl SourceIter for TakeWhile where - P: FnMut(&I::Item) -> bool, - I: SourceIter, + I: SourceIter, { - type Source = S; + type Source = I::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut I::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.iter) } } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 17697fa0e045a..2b7287a413376 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -414,16 +414,14 @@ where // Arbitrarily selects the left side of the zip iteration as extractable "source" // it would require negative trait bounds to be able to try both #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl SourceIter for Zip +unsafe impl SourceIter for Zip where - A: SourceIter, - B: Iterator, - S: Iterator, + A: SourceIter, { - type Source = S; + type Source = A::Source; #[inline] - unsafe fn as_inner(&mut self) -> &mut S { + unsafe fn as_inner(&mut self) -> &mut A::Source { // SAFETY: unsafe function forwarding to unsafe function with the same requirements unsafe { SourceIter::as_inner(&mut self.a) } } diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index d6f9edaa046c6..dc32df4e2b415 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -39,7 +39,7 @@ //! ``` //! //! An iterator has a method, [`next`], which when called, returns an -//! [`Option`]``. [`next`] will return [`Some(Item)`] as long as there +//! [Option]\. Calling [`next`] will return [`Some(Item)`] as long as there //! are elements, and once they've all been exhausted, will return `None` to //! indicate that iteration is finished. Individual iterators may choose to //! resume iteration, and so calling [`next`] again may or may not eventually @@ -414,7 +414,7 @@ pub use self::adapters::{ Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan, Skip, SkipWhile, Take, TakeWhile, Zip, }; -#[stable(feature = "iter_intersperse", since = "1.56.0")] +#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] pub use self::adapters::{Intersperse, IntersperseWith}; pub(crate) use self::adapters::process_results; diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index f7ed811e44733..06733a1b50b91 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -521,10 +521,12 @@ trait RangeIteratorImpl { // Iterator fn spec_next(&mut self) -> Option; fn spec_nth(&mut self, n: usize) -> Option; + fn spec_advance_by(&mut self, n: usize) -> Result<(), usize>; // DoubleEndedIterator fn spec_next_back(&mut self) -> Option; fn spec_nth_back(&mut self, n: usize) -> Option; + fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>; } impl RangeIteratorImpl for ops::Range { @@ -555,6 +557,22 @@ impl RangeIteratorImpl for ops::Range { None } + #[inline] + default fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> { + let available = if self.start <= self.end { + Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) + } else { + 0 + }; + + let taken = available.min(n); + + self.start = + Step::forward_checked(self.start.clone(), taken).expect("`Step` invariants not upheld"); + + if taken < n { Err(taken) } else { Ok(()) } + } + #[inline] default fn spec_next_back(&mut self) -> Option { if self.start < self.end { @@ -579,6 +597,22 @@ impl RangeIteratorImpl for ops::Range { self.end = self.start.clone(); None } + + #[inline] + default fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let available = if self.start <= self.end { + Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) + } else { + 0 + }; + + let taken = available.min(n); + + self.end = + Step::backward_checked(self.end.clone(), taken).expect("`Step` invariants not upheld"); + + if taken < n { Err(taken) } else { Ok(()) } + } } impl RangeIteratorImpl for ops::Range { @@ -607,6 +641,25 @@ impl RangeIteratorImpl for ops::Range { None } + #[inline] + fn spec_advance_by(&mut self, n: usize) -> Result<(), usize> { + let available = if self.start <= self.end { + Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) + } else { + 0 + }; + + let taken = available.min(n); + + // SAFETY: the conditions above ensure that the count is in bounds. If start <= end + // then steps_between either returns a bound to which we clamp or returns None which + // together with the initial inequality implies more than usize::MAX steps. + // Otherwise 0 is returned which always safe to use. + self.start = unsafe { Step::forward_unchecked(self.start.clone(), taken) }; + + if taken < n { Err(taken) } else { Ok(()) } + } + #[inline] fn spec_next_back(&mut self) -> Option { if self.start < self.end { @@ -631,6 +684,22 @@ impl RangeIteratorImpl for ops::Range { self.end = self.start.clone(); None } + + #[inline] + fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let available = if self.start <= self.end { + Step::steps_between(&self.start, &self.end).unwrap_or(usize::MAX) + } else { + 0 + }; + + let taken = available.min(n); + + // SAFETY: same as the spec_advance_by() implementation + self.end = unsafe { Step::backward_unchecked(self.end.clone(), taken) }; + + if taken < n { Err(taken) } else { Ok(()) } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -672,6 +741,16 @@ impl Iterator for ops::Range { self.next_back() } + #[inline] + fn is_sorted(self) -> bool { + true + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.spec_advance_by(n) + } + #[inline] #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item @@ -745,6 +824,11 @@ impl DoubleEndedIterator for ops::Range { fn nth_back(&mut self, n: usize) -> Option { self.spec_nth_back(n) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.spec_advance_back_by(n) + } } // Safety: @@ -1095,6 +1179,11 @@ impl Iterator for ops::RangeInclusive { fn max(mut self) -> Option { self.next_back() } + + #[inline] + fn is_sorted(self) -> bool { + true + } } #[stable(feature = "inclusive_range", since = "1.26.0")] diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 9a9cf20077096..9a589c1f3b55c 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -103,9 +103,15 @@ pub trait DoubleEndedIterator: Iterator { /// elements the iterator is advanced by before running out of elements (i.e. the length /// of the iterator). Note that `k` is always less than `n`. /// - /// Calling `advance_back_by(0)` does not consume any elements and always returns [`Ok(())`]. + /// Calling `advance_back_by(0)` can do meaningful work, for example [`Flatten`] can advance its + /// outer iterator until it finds an inner iterator that is not empty, which then often + /// allows it to return a more accurate `size_hint()` than in its initial state. + /// `advance_back_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information + /// whether the iterator is or is not exhausted, the latter can be treated as if [`next_back`] + /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`. /// /// [`advance_by`]: Iterator::advance_by + /// [`Flatten`]: crate::iter::Flatten /// [`next_back`]: DoubleEndedIterator::next_back /// /// # Examples diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f884340f4e0bd..8f9b32e775056 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -96,7 +96,7 @@ pub trait Iterator { /// Specifically, `size_hint()` returns a tuple where the first element /// is the lower bound, and the second element is the upper bound. /// - /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`. + /// The second half of the tuple that is returned is an [Option]<[usize]>. /// A [`None`] here means that either there is no known upper bound, or the /// upper bound is larger than [`usize`]. /// @@ -115,11 +115,9 @@ pub trait Iterator { /// That said, the implementation should provide a correct estimation, /// because otherwise it would be a violation of the trait's protocol. /// - /// The default implementation returns `(0, `[`None`]`)` which is correct for any + /// The default implementation returns (0, [None]) which is correct for any /// iterator. /// - /// [`usize`]: type@usize - /// /// # Examples /// /// Basic usage: @@ -248,8 +246,14 @@ pub trait Iterator { /// of elements the iterator is advanced by before running out of elements (i.e. the /// length of the iterator). Note that `k` is always less than `n`. /// - /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`][Ok]. + /// Calling `advance_by(0)` can do meaningful work, for example [`Flatten`] + /// can advance its outer iterator until it finds an inner iterator that is not empty, which + /// then often allows it to return a more accurate `size_hint()` than in its initial state. + /// `advance_by(0)` may either return `Ok()` or `Err(0)`. The former conveys no information + /// whether the iterator is or is not exhausted, the latter can be treated as if [`next`] + /// had returned `None`. Replacing a `Err(0)` with `Ok` is only correct for `n = 0`. /// + /// [`Flatten`]: crate::iter::Flatten /// [`next`]: Iterator::next /// /// # Examples @@ -535,6 +539,8 @@ pub trait Iterator { /// Basic usage: /// /// ``` + /// #![feature(iter_intersperse)] + /// /// let mut a = [0, 1, 2].iter().intersperse(&100); /// assert_eq!(a.next(), Some(&0)); // The first element from `a`. /// assert_eq!(a.next(), Some(&100)); // The separator. @@ -545,8 +551,9 @@ pub trait Iterator { /// ``` /// /// `intersperse` can be very useful to join an iterator's items using a common element: - /// /// ``` + /// #![feature(iter_intersperse)] + /// /// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::(); /// assert_eq!(hello, "Hello World !"); /// ``` @@ -554,7 +561,7 @@ pub trait Iterator { /// [`Clone`]: crate::clone::Clone /// [`intersperse_with`]: Iterator::intersperse_with #[inline] - #[stable(feature = "iter_intersperse", since = "1.56.0")] + #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] fn intersperse(self, separator: Self::Item) -> Intersperse where Self: Sized, @@ -579,6 +586,8 @@ pub trait Iterator { /// Basic usage: /// /// ``` + /// #![feature(iter_intersperse)] + /// /// #[derive(PartialEq, Debug)] /// struct NotClone(usize); /// @@ -595,8 +604,9 @@ pub trait Iterator { /// /// `intersperse_with` can be used in situations where the separator needs /// to be computed: - /// /// ``` + /// #![feature(iter_intersperse)] + /// /// let src = ["Hello", "to", "all", "people", "!!"].iter().copied(); /// /// // The closure mutably borrows its context to generate an item. @@ -609,7 +619,7 @@ pub trait Iterator { /// [`Clone`]: crate::clone::Clone /// [`intersperse`]: Iterator::intersperse #[inline] - #[stable(feature = "iter_intersperse", since = "1.56.0")] + #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")] fn intersperse_with(self, separator: G) -> IntersperseWith where Self: Sized, @@ -864,7 +874,6 @@ pub trait Iterator { /// The returned iterator might panic if the to-be-returned index would /// overflow a [`usize`]. /// - /// [`usize`]: type@usize /// [`zip`]: Iterator::zip /// /// # Examples @@ -1798,10 +1807,11 @@ pub trait Iterator { /// The relative order of partitioned items is not maintained. /// /// # Current implementation + /// /// Current algorithms tries finding the first element for which the predicate evaluates /// to false, and the last element for which it evaluates to true and repeatedly swaps them. /// - /// Time Complexity: *O*(*N*) + /// Time complexity: *O*(*n*) /// /// See also [`is_partitioned()`] and [`partition()`]. /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 265ba9f1bb91b..630876445ba82 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -60,6 +60,30 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] +#![cfg_attr( + not(bootstrap), + doc(cfg_hide( + not(test), + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64", + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr", + target_has_atomic_equal_alignment = "8", + target_has_atomic_equal_alignment = "16", + target_has_atomic_equal_alignment = "32", + target_has_atomic_equal_alignment = "64", + target_has_atomic_equal_alignment = "ptr", + target_has_atomic_load_store = "8", + target_has_atomic_load_store = "16", + target_has_atomic_load_store = "32", + target_has_atomic_load_store = "64", + target_has_atomic_load_store = "ptr", + )) +)] #![no_core] // // Lints: @@ -91,6 +115,7 @@ #![feature(const_maybe_uninit_assume_init)] #![feature(const_option)] #![feature(const_pin)] +#![feature(const_replace)] #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_ptr_read)] @@ -123,7 +148,7 @@ #![feature(const_fn_trait_bound)] #![feature(const_impl_trait)] #![feature(const_mut_refs)] -#![feature(const_panic)] +#![cfg_attr(bootstrap, feature(const_panic))] #![feature(const_precise_live_drops)] #![feature(const_raw_ptr_deref)] #![feature(const_refs_to_cell)] @@ -132,6 +157,7 @@ #![feature(doc_notable_trait)] #![feature(doc_primitive)] #![feature(exhaustive_patterns)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] #![feature(extern_types)] #![feature(fundamental)] #![feature(if_let_guard)] @@ -141,6 +167,8 @@ #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] #![feature(min_specialization)] +#![feature(mixed_integer_ops)] +#![cfg_attr(not(bootstrap), feature(must_not_suspend))] #![feature(negative_impls)] #![feature(never_type)] #![feature(no_core)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index a7ed5bfaf8598..37446bafacb24 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -30,7 +30,7 @@ use crate::hash::Hasher; /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "send_trait")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Send")] #[rustc_on_unimplemented( message = "`{Self}` cannot be sent between threads safely", label = "`{Self}` cannot be sent between threads safely" @@ -459,7 +459,7 @@ pub macro Copy($item:item) { /// [transmute]: crate::mem::transmute /// [nomicon-send-and-sync]: ../../nomicon/send-and-sync.html #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "sync_trait")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Sync")] #[lang = "sync"] #[rustc_on_unimplemented( message = "`{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 2a02545041dcf..12dda61400f2a 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -433,6 +433,28 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_add(self, rhs) } } + /// Checked addition with an unsigned integer. Computes `self + rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option { + let (a, b) = self.overflowing_add_unsigned(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer subtraction. Computes `self - rhs`, returning `None` if /// overflow occurred. /// @@ -479,6 +501,28 @@ macro_rules! int_impl { unsafe { intrinsics::unchecked_sub(self, rhs) } } + /// Checked subtraction with an unsigned integer. Computes `self - rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option { + let (a, b) = self.overflowing_sub_unsigned(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer multiplication. Computes `self * rhs`, returning `None` if /// overflow occurred. /// @@ -543,7 +587,8 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -569,7 +614,8 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { Some(self.div_euclid(rhs)) @@ -595,7 +641,8 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -621,7 +668,8 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) { None } else { Some(self.rem_euclid(rhs)) @@ -822,6 +870,32 @@ macro_rules! int_impl { intrinsics::saturating_add(self, rhs) } + /// Saturating addition with an unsigned integer. Computes `self + rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add_unsigned(self, rhs: $UnsignedT) -> Self { + // Overflow can only happen at the upper bound + // We cannot use `unwrap_or` here because it is not `const` + match self.checked_add_unsigned(rhs) { + Some(x) => x, + None => Self::MAX, + } + } + /// Saturating integer subtraction. Computes `self - rhs`, saturating at the /// numeric bounds instead of overflowing. /// @@ -843,6 +917,32 @@ macro_rules! int_impl { intrinsics::saturating_sub(self, rhs) } + /// Saturating subtraction with an unsigned integer. Computes `self - rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_sub_unsigned(self, rhs: $UnsignedT) -> Self { + // Overflow can only happen at the lower bound + // We cannot use `unwrap_or` here because it is not `const` + match self.checked_sub_unsigned(rhs) { + Some(x) => x, + None => Self::MIN, + } + } + /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` /// instead of overflowing. /// @@ -998,6 +1098,27 @@ macro_rules! int_impl { intrinsics::wrapping_add(self, rhs) } + /// Wrapping (modular) addition with an unsigned integer. Computes + /// `self + rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn wrapping_add_unsigned(self, rhs: $UnsignedT) -> Self { + self.wrapping_add(rhs as Self) + } + /// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the /// boundary of the type. /// @@ -1018,6 +1139,27 @@ macro_rules! int_impl { intrinsics::wrapping_sub(self, rhs) } + /// Wrapping (modular) subtraction with an unsigned integer. Computes + /// `self - rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")] + #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn wrapping_sub_unsigned(self, rhs: $UnsignedT) -> Self { + self.wrapping_sub(rhs as Self) + } + /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at /// the boundary of the type. /// @@ -1368,6 +1510,33 @@ macro_rules! int_impl { (sum as $SelfT, carry) } + /// Calculates `self` + `rhs` with an unsigned `rhs` + /// + /// Returns a tuple of the addition along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_unsigned(2), (3, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_unsigned(3), (", stringify!($SelfT), "::MIN, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { + let rhs = rhs as Self; + let (res, overflowed) = self.overflowing_add(rhs); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow @@ -1419,6 +1588,33 @@ macro_rules! int_impl { (sum as $SelfT, borrow) } + /// Calculates `self` - `rhs` with an unsigned `rhs` + /// + /// Returns a tuple of the subtraction along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_unsigned(2), (-1, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).overflowing_sub_unsigned(3), (", stringify!($SelfT), "::MAX, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_sub_unsigned(self, rhs: $UnsignedT) -> (Self, bool) { + let rhs = rhs as Self; + let (res, overflowed) = self.overflowing_sub(rhs); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates the multiplication of `self` and `rhs`. /// /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow @@ -1466,7 +1662,8 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!((self == Self::MIN) & (rhs == -1)) { (self, true) } else { (self / rhs, false) @@ -1496,7 +1693,8 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { + // Using `&` helps LLVM see that it is the same check made in division. + if unlikely!((self == Self::MIN) & (rhs == -1)) { (self, true) } else { (self.div_euclid(rhs), false) @@ -1527,8 +1725,8 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (0, true) + if unlikely!(rhs == -1) { + (0, self == Self::MIN) } else { (self % rhs, false) } @@ -1558,8 +1756,8 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - if unlikely!(self == Self::MIN && rhs == -1) { - (0, true) + if unlikely!(rhs == -1) { + (0, self == Self::MIN) } else { (self.rem_euclid(rhs), false) } @@ -1849,17 +2047,17 @@ macro_rules! int_impl { #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] /// let b = 3; /// - /// assert_eq!(a.div_floor(b), 2); - /// assert_eq!(a.div_floor(-b), -3); - /// assert_eq!((-a).div_floor(b), -3); - /// assert_eq!((-a).div_floor(-b), 2); + /// assert_eq!(a.unstable_div_floor(b), 2); + /// assert_eq!(a.unstable_div_floor(-b), -3); + /// assert_eq!((-a).unstable_div_floor(b), -3); + /// assert_eq!((-a).unstable_div_floor(-b), 2); /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn div_floor(self, rhs: Self) -> Self { + pub const fn unstable_div_floor(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; if (r > 0 && rhs < 0) || (r < 0 && rhs > 0) { @@ -1884,17 +2082,17 @@ macro_rules! int_impl { #[doc = concat!("let a: ", stringify!($SelfT)," = 8;")] /// let b = 3; /// - /// assert_eq!(a.div_ceil(b), 3); - /// assert_eq!(a.div_ceil(-b), -2); - /// assert_eq!((-a).div_ceil(b), -2); - /// assert_eq!((-a).div_ceil(-b), 3); + /// assert_eq!(a.unstable_div_ceil(b), 3); + /// assert_eq!(a.unstable_div_ceil(-b), -2); + /// assert_eq!((-a).unstable_div_ceil(b), -2); + /// assert_eq!((-a).unstable_div_ceil(-b), 3); /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn div_ceil(self, rhs: Self) -> Self { + pub const fn unstable_div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; if (r > 0 && rhs > 0) || (r < 0 && rhs < 0) { @@ -1919,21 +2117,21 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] - #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")] - #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(-8), 16);")] - #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(-8), 16);")] - #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(8), -16);")] - #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(8), -16);")] - #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").next_multiple_of(-8), -16);")] - #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").next_multiple_of(-8), -24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(8), 24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(-8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(-8), 16);")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").unstable_next_multiple_of(8), -16);")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").unstable_next_multiple_of(8), -16);")] + #[doc = concat!("assert_eq!((-16_", stringify!($SelfT), ").unstable_next_multiple_of(-8), -16);")] + #[doc = concat!("assert_eq!((-23_", stringify!($SelfT), ").unstable_next_multiple_of(-8), -24);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn next_multiple_of(self, rhs: Self) -> Self { + pub const fn unstable_next_multiple_of(self, rhs: Self) -> Self { // This would otherwise fail when calculating `r` when self == T::MIN. if rhs == -1 { return self; @@ -2227,6 +2425,46 @@ macro_rules! int_impl { } } + /// Computes the absolute difference between `self` and `other`. + /// + /// This function always returns the correct answer without overflow or + /// panics by returning an unsigned integer. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_abs_diff)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($UnsignedT), ");")] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($UnsignedT), ");")] + #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").abs_diff(80), 180", stringify!($UnsignedT), ");")] + #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").abs_diff(-120), 20", stringify!($UnsignedT), ");")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.abs_diff(", stringify!($SelfT), "::MAX), ", stringify!($UnsignedT), "::MAX);")] + /// ``` + #[unstable(feature = "int_abs_diff", issue = "89492")] + #[inline] + pub const fn abs_diff(self, other: Self) -> $UnsignedT { + if self < other { + // Converting a non-negative x from signed to unsigned by using + // `x as U` is left unchanged, but a negative x is converted + // to value x + 2^N. Thus if `s` and `o` are binary variables + // respectively indicating whether `self` and `other` are + // negative, we are computing the mathematical value: + // + // (other + o*2^N) - (self + s*2^N) mod 2^N + // other - self + (o-s)*2^N mod 2^N + // other - self mod 2^N + // + // Finally, taking the mod 2^N of the mathematical value of + // `other - self` does not change it as it already is + // in the range [0, 2^N). + (other as $UnsignedT).wrapping_sub(self as $UnsignedT) + } else { + (self as $UnsignedT).wrapping_sub(other as $UnsignedT) + } + } + /// Returns a number representing sign of `self`. /// /// - `0` if the number is zero diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 59b68cbe9c0ce..d5fb98eff575d 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -245,7 +245,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000; #[lang = "u8"] impl u8 { widening_impl! { u8, u16, 8 } - uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", + uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } /// Checks if the value is within the ASCII range. @@ -779,21 +779,21 @@ impl u8 { #[lang = "u16"] impl u16 { widening_impl! { u16, u32, 16 } - uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", + uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "u32"] impl u32 { widening_impl! { u32, u64, 32 } - uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", + uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "u64"] impl u64 { widening_impl! { u64, u128, 64 } - uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", + uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", @@ -802,7 +802,7 @@ impl u64 { #[lang = "u128"] impl u128 { - uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, 16, + uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16, "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48", "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ @@ -816,7 +816,7 @@ impl u128 { #[lang = "usize"] impl usize { widening_impl! { usize, u32, 16 } - uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", + uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } @@ -824,7 +824,7 @@ impl usize { #[lang = "usize"] impl usize { widening_impl! { usize, u64, 32 } - uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", + uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } @@ -833,7 +833,7 @@ impl usize { #[lang = "usize"] impl usize { widening_impl! { usize, u128, 64 } - uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", + uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", @@ -865,23 +865,41 @@ impl usize { #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum FpCategory { - /// "Not a Number", often obtained by dividing by zero. + /// NaN (not a number): this value results from calculations like `(-1.0).sqrt()`. + /// + /// See [the documentation for `f32`](f32) for more information on the unusual properties + /// of NaN. #[stable(feature = "rust1", since = "1.0.0")] Nan, - /// Positive or negative infinity. + /// Positive or negative infinity, which often results from dividing a nonzero number + /// by zero. #[stable(feature = "rust1", since = "1.0.0")] Infinite, /// Positive or negative zero. + /// + /// See [the documentation for `f32`](f32) for more information on the signedness of zeroes. #[stable(feature = "rust1", since = "1.0.0")] Zero, - /// De-normalized floating point representation (less precise than `Normal`). + /// “Subnormal” or “denormal” floating point representation (less precise, relative to + /// their magnitude, than [`Normal`]). + /// + /// Subnormal numbers are larger in magnitude than [`Zero`] but smaller in magnitude than all + /// [`Normal`] numbers. + /// + /// [`Normal`]: Self::Normal + /// [`Zero`]: Self::Zero #[stable(feature = "rust1", since = "1.0.0")] Subnormal, - /// A regular floating point number. + /// A regular floating point number, not any of the exceptional categories. + /// + /// The smallest positive normal numbers are [`f32::MIN_POSITIVE`] and [`f64::MIN_POSITIVE`], + /// and the largest positive normal numbers are [`f32::MAX`] and [`f64::MAX`]. (Unlike signed + /// integers, floating point numbers are symmetric in their range, so negating any of these + /// constants will produce their negative counterpart.) #[stable(feature = "rust1", since = "1.0.0")] Normal, } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index dd9b9330aee2b..e44597279baf2 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -379,7 +379,7 @@ macro_rules! nonzero_unsigned_operations { /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] #[inline] - pub unsafe fn unchecked_add(self, other: $Int) -> $Ty { + pub const unsafe fn unchecked_add(self, other: $Int) -> $Ty { // SAFETY: The caller ensures there is no overflow. unsafe { $Ty::new_unchecked(self.get().unchecked_add(other)) } } @@ -750,7 +750,7 @@ macro_rules! nonzero_unsigned_signed_operations { /// ``` #[unstable(feature = "nonzero_ops", issue = "84186")] #[inline] - pub unsafe fn unchecked_mul(self, other: $Ty) -> $Ty { + pub const unsafe fn unchecked_mul(self, other: $Ty) -> $Ty { // SAFETY: The caller ensures there is no overflow. unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 7523d8ec976dd..25cd582bb67d7 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1,5 +1,5 @@ macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ident, $BITS:expr, $MaxV:expr, + ($SelfT:ty, $ActualT:ident, $SignedT:ident, $BITS:expr, $MaxV:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, $reversed:expr, $le_bytes:expr, $be_bytes:expr, $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { @@ -442,6 +442,29 @@ macro_rules! uint_impl { unsafe { intrinsics::unchecked_add(self, rhs) } } + /// Checked addition with a signed integer. Computes `self + rhs`, + /// returning `None` if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_signed(3), None);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_add_signed(self, rhs: $SignedT) -> Option { + let (a, b) = self.overflowing_add_signed(rhs); + if unlikely!(b) {None} else {Some(a)} + } + /// Checked integer subtraction. Computes `self - rhs`, returning /// `None` if overflow occurred. /// @@ -995,6 +1018,35 @@ macro_rules! uint_impl { intrinsics::saturating_add(self, rhs) } + /// Saturating addition with a signed integer. Computes `self + rhs`, + /// saturating at the numeric bounds instead of overflowing. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(2), 3);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_add_signed(4), ", stringify!($SelfT), "::MAX);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_add_signed(self, rhs: $SignedT) -> Self { + let (res, overflow) = self.overflowing_add(rhs as Self); + if overflow == (rhs < 0) { + res + } else if overflow { + Self::MAX + } else { + 0 + } + } + /// Saturating integer subtraction. Computes `self - rhs`, saturating /// at the numeric bounds instead of overflowing. /// @@ -1111,6 +1163,28 @@ macro_rules! uint_impl { intrinsics::wrapping_add(self, rhs) } + /// Wrapping (modular) addition with a signed integer. Computes + /// `self + rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(2), 3);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_add_signed(4), 1);")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_add_signed(self, rhs: $SignedT) -> Self { + self.wrapping_add(rhs as Self) + } + /// Wrapping (modular) subtraction. Computes `self - rhs`, /// wrapping around at the boundary of the type. /// @@ -1435,6 +1509,32 @@ macro_rules! uint_impl { (c, b | d) } + /// Calculates `self` + `rhs` with a signed `rhs` + /// + /// Returns a tuple of the addition along with a boolean indicating + /// whether an arithmetic overflow would occur. If an overflow would + /// have occurred then the wrapped value is returned. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(mixed_integer_ops)] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(2), (3, false));")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_signed(4), (1, true));")] + /// ``` + #[unstable(feature = "mixed_integer_ops", issue = "87840")] + #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_add_signed(self, rhs: $SignedT) -> (Self, bool) { + let (res, overflowed) = self.overflowing_add(rhs as Self); + (res, overflowed ^ (rhs < 0)) + } + /// Calculates `self` - `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating @@ -1490,6 +1590,33 @@ macro_rules! uint_impl { (c, b | d) } + /// Computes the absolute difference between `self` and `other`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(int_abs_diff)] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($SelfT), ");")] + #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($SelfT), ");")] + /// ``` + #[unstable(feature = "int_abs_diff", issue = "89492")] + #[inline] + pub const fn abs_diff(self, other: Self) -> Self { + if mem::size_of::() == 1 { + // Trick LLVM into generating the psadbw instruction when SSE2 + // is available and this function is autovectorized for u8's. + (self as i32).wrapping_sub(other as i32).abs() as Self + } else { + if self < other { + other - self + } else { + self - other + } + } + } + /// Calculates the multiplication of `self` and `rhs`. /// /// Returns a tuple of the multiplication along with a boolean @@ -1859,12 +1986,12 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_floor(4), 1);")] + #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_floor(4), 1);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[inline(always)] #[rustc_inherit_overflow_checks] - pub const fn div_floor(self, rhs: Self) -> Self { + pub const fn unstable_div_floor(self, rhs: Self) -> Self { self / rhs } @@ -1880,12 +2007,12 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".div_ceil(4), 2);")] + #[doc = concat!("assert_eq!(7_", stringify!($SelfT), ".unstable_div_ceil(4), 2);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[inline] #[rustc_inherit_overflow_checks] - pub const fn div_ceil(self, rhs: Self) -> Self { + pub const fn unstable_div_ceil(self, rhs: Self) -> Self { let d = self / rhs; let r = self % rhs; if r > 0 && rhs > 0 { @@ -1908,15 +2035,15 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_roundings)] - #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".next_multiple_of(8), 16);")] - #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".next_multiple_of(8), 24);")] + #[doc = concat!("assert_eq!(16_", stringify!($SelfT), ".unstable_next_multiple_of(8), 16);")] + #[doc = concat!("assert_eq!(23_", stringify!($SelfT), ".unstable_next_multiple_of(8), 24);")] /// ``` #[unstable(feature = "int_roundings", issue = "88581")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn next_multiple_of(self, rhs: Self) -> Self { + pub const fn unstable_next_multiple_of(self, rhs: Self) -> Self { match self % rhs { 0 => self, r => self + (rhs - r) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 907726f0c345c..3259e142a0c2a 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -47,9 +47,9 @@ //! //! Rust's pointer types must always point to a valid location; there are //! no "null" references. Instead, Rust has *optional* pointers, like -//! the optional owned box, [`Option`]`<`[`Box`]`>`. +//! the optional owned box, [Option]<[Box\]>. //! -//! [`Box`]: ../../std/boxed/struct.Box.html +//! [Box\]: ../../std/boxed/struct.Box.html //! //! The following example uses [`Option`] to create an optional box of //! [`i32`]. Notice that in order to use the inner [`i32`] value, the @@ -111,16 +111,20 @@ //! //! ## Adapters for working with references //! -//! * [`as_ref`] converts from `&Option` to `Option<&T>` -//! * [`as_mut`] converts from `&mut Option` to `Option<&mut T>` -//! * [`as_deref`] converts from `&Option` to `Option<&T::Target>` -//! * [`as_deref_mut`] converts from `&mut Option` to -//! `Option<&mut T::Target>` -//! * [`as_pin_ref`] converts from [`Pin`]`<&Option>` to -//! `Option<`[`Pin`]`<&T>>` -//! * [`as_pin_mut`] converts from [`Pin`]`<&mut Option>` to -//! `Option<`[`Pin`]`<&mut T>>` -//! +//! * [`as_ref`] converts from [&][][Option]\ to [Option]<[&]T> +//! * [`as_mut`] converts from [&mut] [Option]\ to [Option]<[&mut] T> +//! * [`as_deref`] converts from [&][][Option]\ to +//! [Option]<[&]T::[Target]> +//! * [`as_deref_mut`] converts from [&mut] [Option]\ to +//! [Option]<[&mut] T::[Target]> +//! * [`as_pin_ref`] converts from [Pin]<[&][][Option]\> to +//! [Option]<[Pin]<[&]T>> +//! * [`as_pin_mut`] converts from [Pin]<[&mut] [Option]\> to +//! [Option]<[Pin]<[&mut] T>> +//! +//! [&]: reference "shared reference" +//! [&mut]: reference "mutable reference" +//! [Target]: Deref::Target "ops::Deref::Target" //! [`as_deref`]: Option::as_deref //! [`as_deref_mut`]: Option::as_deref_mut //! [`as_mut`]: Option::as_mut @@ -505,7 +509,7 @@ use crate::{ /// The `Option` type. See [the module level documentation](self) for more. #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] -#[rustc_diagnostic_item = "option_type"] +#[rustc_diagnostic_item = "Option"] #[stable(feature = "rust1", since = "1.0.0")] pub enum Option { /// No value @@ -540,8 +544,8 @@ impl Option { /// ``` #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] #[inline] - #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] pub const fn is_some(&self) -> bool { matches!(*self, Some(_)) } @@ -560,8 +564,8 @@ impl Option { #[must_use = "if you intended to assert that this doesn't have a value, consider \ `.and_then(|_| panic!(\"`Option` had a value when expected `None`\"))` instead"] #[inline] - #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] pub const fn is_none(&self) -> bool { !self.is_some() } @@ -603,13 +607,13 @@ impl Option { /// /// # Examples /// - /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. - /// The [`map`] method takes the `self` argument by value, consuming the original, + /// Converts an Option<[String]> into an Option<[usize]>, preserving + /// the original. The [`map`] method takes the `self` argument by value, consuming the original, /// so this technique uses `as_ref` to first take an `Option` to a reference /// to the value inside the original. /// /// [`map`]: Option::map - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// /// ``` /// let text: Option = Some("Hello, world!".to_string()); @@ -649,7 +653,9 @@ impl Option { } } - /// Converts from [`Pin`]`<&Option>` to `Option<`[`Pin`]`<&T>>`. + /// Converts from [Pin]<[&]Option\> to Option<[Pin]<[&]T>>. + /// + /// [&]: reference "shared reference" #[inline] #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_ref(self: Pin<&Self>) -> Option> { @@ -658,7 +664,9 @@ impl Option { unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) } } - /// Converts from [`Pin`]`<&mut Option>` to `Option<`[`Pin`]`<&mut T>>`. + /// Converts from [Pin]<[&mut] Option\> to Option<[Pin]<[&mut] T>>. + /// + /// [&mut]: reference "mutable reference" #[inline] #[stable(feature = "pin", since = "1.33.0")] pub fn as_pin_mut(self: Pin<&mut Self>) -> Option> { @@ -819,9 +827,10 @@ impl Option { /// /// # Examples /// - /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, consuming the original: + /// Converts an Option<[String]> into an Option<[usize]>, consuming + /// the original: /// - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// ``` /// let maybe_some_string = Some(String::from("Hello, World!")); /// // `Option::map` takes self *by value*, consuming `maybe_some_string` @@ -1309,8 +1318,10 @@ impl Option { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn take(&mut self) -> Option { - mem::take(self) + #[rustc_const_unstable(feature = "const_option", issue = "67441")] + pub const fn take(&mut self) -> Option { + // FIXME replace `mem::replace` by `mem::take` when the latter is const ready + mem::replace(self, None) } /// Replaces the actual value in the option by the value given in parameter, @@ -1331,8 +1342,9 @@ impl Option { /// assert_eq!(old, None); /// ``` #[inline] + #[rustc_const_unstable(feature = "const_option", issue = "67441")] #[stable(feature = "option_replace", since = "1.31.0")] - pub fn replace(&mut self, value: T) -> Option { + pub const fn replace(&mut self, value: T) -> Option { mem::replace(self, Some(value)) } @@ -1437,8 +1449,14 @@ impl Option<&T> { /// assert_eq!(copied, Some(12)); /// ``` #[stable(feature = "copied", since = "1.35.0")] - pub fn copied(self) -> Option { - self.map(|&t| t) + #[rustc_const_unstable(feature = "const_option", issue = "67441")] + pub const fn copied(self) -> Option { + // FIXME: this implementation, which sidesteps using `Option::map` since it's not const + // ready yet, should be reverted when possible to avoid code repetition + match self { + Some(&v) => Some(v), + None => None, + } } } @@ -1581,9 +1599,9 @@ impl Option { impl Option> { /// Transposes an `Option` of a [`Result`] into a [`Result`] of an `Option`. /// - /// [`None`] will be mapped to [`Ok`]`(`[`None`]`)`. - /// [`Some`]`(`[`Ok`]`(_))` and [`Some`]`(`[`Err`]`(_))` will be mapped to - /// [`Ok`]`(`[`Some`]`(_))` and [`Err`]`(_)`. + /// [`None`] will be mapped to [Ok]\([None]). + /// [Some]\([Ok]\(\_)) and [Some]\([Err]\(\_)) will be mapped to + /// [Ok]\([Some]\(\_)) and [Err]\(\_). /// /// # Examples /// @@ -1721,13 +1739,13 @@ impl<'a, T> From<&'a Option> for Option<&'a T> { /// /// # Examples /// - /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. - /// The [`map`] method takes the `self` argument by value, consuming the original, - /// so this technique uses `from` to first take an `Option` to a reference + /// Converts an [Option]<[String]> into an [Option]<[usize]>, preserving + /// the original. The [`map`] method takes the `self` argument by value, consuming the original, + /// so this technique uses `from` to first take an [`Option`] to a reference /// to the value inside the original. /// /// [`map`]: Option::map - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// /// ``` /// let s: Option = Some(String::from("Hello, Rustaceans!")); diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 6a1a84bafa330..8b64579216915 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -368,15 +368,15 @@ //! [Vec::push]: ../../std/vec/struct.Vec.html#method.push "Vec::push" //! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc" //! [RefCell]: crate::cell::RefCell "cell::RefCell" -//! [`drop`]: Drop::drop "Drop::drop" +//! [`drop`]: Drop::drop //! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque" //! [`ptr::write`]: crate::ptr::write "ptr::write" //! [`Future`]: crate::future::Future "future::Future" //! [drop-impl]: #drop-implementation //! [drop-guarantee]: #drop-guarantee //! [`poll`]: crate::future::Future::poll "future::Future::poll" -//! [&]: ../../std/primitive.reference.html "shared reference" -//! [&mut]: ../../std/primitive.reference.html "mutable reference" +//! [&]: reference "shared reference" +//! [&mut]: reference "mutable reference" //! [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe" #![stable(feature = "pin", since = "1.33.0")] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 092e6544342b7..c9c2d2e645ace 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -88,7 +88,7 @@ //! ``` //! //! *Note: The actual definition of [`Write`] uses [`io::Result`], which -//! is just a synonym for [`Result`]``.* +//! is just a synonym for [Result].* //! //! This method doesn't produce a value, but the write may //! fail. It's crucial to handle the error case, and *not* write @@ -217,13 +217,13 @@ //! early return of [`Err`] that it provides. //! //! [`expect`]: Result::expect -//! [`Write`]: ../../std/io/trait.Write.html -//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all -//! [`io::Result`]: ../../std/io/type.Result.html +//! [`Write`]: ../../std/io/trait.Write.html "io::Write" +//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all "io::Write::write_all" +//! [`io::Result`]: ../../std/io/type.Result.html "io::Result" //! [`?`]: crate::ops::Try //! [`Ok(T)`]: Ok //! [`Err(E)`]: Err -//! [`io::Error`]: ../../std/io/struct.Error.html +//! [io::Error]: ../../std/io/struct.Error.html "io::Error" //! //! # Method overview //! @@ -329,8 +329,8 @@ //! [`Ok`], or returns the provided default value if the [`Result`] is //! [`Err`] //! * [`map_or_else`] applies the provided function to the contained value -//! of [`Ok`], or applies the provided fallback function to the contained -//! value of [`Err`] +//! of [`Ok`], or applies the provided default fallback function to the +//! contained value of [`Err`] //! //! [`map_or`]: Result::map_or //! [`map_or_else`]: Result::map_or_else @@ -498,7 +498,7 @@ use crate::{convert, fmt, hint}; /// See the [module documentation](self) for details. #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] -#[rustc_diagnostic_item = "result_type"] +#[rustc_diagnostic_item = "Result"] #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { /// Contains the success value @@ -795,8 +795,8 @@ impl Result { } } - /// Maps a `Result` to `U` by applying a fallback function to a - /// contained [`Err`] value, or a default function to a + /// Maps a `Result` to `U` by applying a provided default fallback + /// function to a contained [`Err`] value, or a provided function to a /// contained [`Ok`] value. /// /// This function can be used to unpack a successful result diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index a04e479e8570d..53b8b343238d5 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1556,7 +1556,7 @@ impl [T] { /// /// # Examples /// - /// ```compile_fail + /// ``` /// #![feature(slice_split_at_unchecked)] /// /// let v = [1, 2, 3, 4, 5, 6]; @@ -1581,7 +1581,7 @@ impl [T] { /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] #[inline] - unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { + pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { // SAFETY: Caller has to check that `0 <= mid <= self.len()` unsafe { (self.get_unchecked(..mid), self.get_unchecked(mid..)) } } @@ -1605,7 +1605,7 @@ impl [T] { /// /// # Examples /// - /// ```compile_fail + /// ``` /// #![feature(slice_split_at_unchecked)] /// /// let mut v = [1, 0, 3, 0, 5, 6]; @@ -1621,7 +1621,7 @@ impl [T] { /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] #[inline] - unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + pub unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [T]) { let len = self.len(); let ptr = self.as_mut_ptr(); diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 8a31388fbdbbc..60b39295cafe1 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -6,8 +6,6 @@ //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our //! stable sorting implementation. -// ignore-tidy-undocumented-unsafe - use crate::cmp; use crate::mem::{self, MaybeUninit}; use crate::ptr; @@ -291,6 +289,9 @@ where } else if start_r < end_r { block_l = rem; } else { + // There were the same number of elements to switch on both blocks during the last + // iteration, so there are no remaining elements on either block. Cover the remaining + // items with roughly equally-sized blocks. block_l = rem / 2; block_r = rem - block_l; } @@ -437,6 +438,17 @@ where // Move its remaining out-of-order elements to the far right. debug_assert_eq!(width(l, r), block_l); while start_l < end_l { + // remaining-elements-safety + // SAFETY: while the loop condition holds there are still elements in `offsets_l`, so it + // is safe to point `end_l` to the previous element. + // + // The `ptr::swap` is safe if both its arguments are valid for reads and writes: + // - Per the debug assert above, the distance between `l` and `r` is `block_l` + // elements, so there can be at most `block_l` remaining offsets between `start_l` + // and `end_l`. This means `r` will be moved at most `block_l` steps back, which + // makes the `r.offset` calls valid (at that point `l == r`). + // - `offsets_l` contains valid offsets into `v` collected during the partitioning of + // the last block, so the `l.offset` calls are valid. unsafe { end_l = end_l.offset(-1); ptr::swap(l.offset(*end_l as isize), r.offset(-1)); @@ -449,6 +461,7 @@ where // Move its remaining out-of-order elements to the far left. debug_assert_eq!(width(l, r), block_r); while start_r < end_r { + // SAFETY: See the reasoning in [remaining-elements-safety]. unsafe { end_r = end_r.offset(-1); ptr::swap(l, r.offset(-(*end_r as isize) - 1)); @@ -481,6 +494,8 @@ where // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. + + // SAFETY: `pivot` is a reference to the first element of `v`, so `ptr::read` is safe. let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot }; let pivot = &*tmp; @@ -646,6 +661,12 @@ where if len >= 8 { // Swaps indices so that `v[a] <= v[b]`. + // SAFETY: `len >= 8` so there are at least two elements in the neighborhoods of + // `a`, `b` and `c`. This means the three calls to `sort_adjacent` result in + // corresponding calls to `sort3` with valid 3-item neighborhoods around each + // pointer, which in turn means the calls to `sort2` are done with valid + // references. Thus the `v.get_unchecked` calls are safe, as is the `ptr::swap` + // call. let mut sort2 = |a: &mut usize, b: &mut usize| unsafe { if is_less(v.get_unchecked(*b), v.get_unchecked(*a)) { ptr::swap(a, b); diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index 373a8212425ac..093c9c37b60b4 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -22,7 +22,7 @@ fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { /// bits `10`). #[inline] pub(super) fn utf8_is_cont_byte(byte: u8) -> bool { - (byte & !CONT_MASK) == TAG_CONT_U8 + (byte as i8) < -64 } #[inline] @@ -163,7 +163,7 @@ pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { // %xF4 %x80-8F 2( UTF8-tail ) match w { 2 => { - if next!() & !CONT_MASK != TAG_CONT_U8 { + if next!() as i8 >= -64 { err!(Some(1)) } } @@ -175,7 +175,7 @@ pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { | (0xEE..=0xEF, 0x80..=0xBF) => {} _ => err!(Some(1)), } - if next!() & !CONT_MASK != TAG_CONT_U8 { + if next!() as i8 >= -64 { err!(Some(2)) } } @@ -184,10 +184,10 @@ pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { (0xF0, 0x90..=0xBF) | (0xF1..=0xF3, 0x80..=0xBF) | (0xF4, 0x80..=0x8F) => {} _ => err!(Some(1)), } - if next!() & !CONT_MASK != TAG_CONT_U8 { + if next!() as i8 >= -64 { err!(Some(2)) } - if next!() & !CONT_MASK != TAG_CONT_U8 { + if next!() as i8 >= -64 { err!(Some(3)) } } @@ -258,8 +258,6 @@ pub fn utf8_char_width(b: u8) -> usize { /// Mask of the value bits of a continuation byte. const CONT_MASK: u8 = 0b0011_1111; -/// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte. -const TAG_CONT_U8: u8 = 0b1000_0000; // truncate `&str` to length at most equal to `max` // return `true` if it were truncated, and the new str. diff --git a/library/core/src/stream/stream/mod.rs b/library/core/src/stream/stream/mod.rs index e37902dae1f2d..d102619b8e5ec 100644 --- a/library/core/src/stream/stream/mod.rs +++ b/library/core/src/stream/stream/mod.rs @@ -52,7 +52,7 @@ pub trait Stream { /// Specifically, `size_hint()` returns a tuple where the first element /// is the lower bound, and the second element is the upper bound. /// - /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`. + /// The second half of the tuple that is returned is an [Option]<[usize]>. /// A [`None`] here means that either there is no known upper bound, or the /// upper bound is larger than [`usize`]. /// @@ -71,7 +71,7 @@ pub trait Stream { /// That said, the implementation should provide a correct estimation, /// because otherwise it would be a violation of the trait's protocol. /// - /// The default implementation returns `(0, `[`None`]`)` which is correct for any + /// The default implementation returns (0, [None]) which is correct for any /// stream. #[inline] fn size_hint(&self) -> (usize, Option) { diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 2507046099632..57416aeb7018f 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -30,9 +30,10 @@ impl Poll { /// /// # Examples /// - /// Converts a `Poll<`[`String`]`>` into an `Poll<`[`usize`]`>`, consuming the original: + /// Converts a Poll<[String]> into a Poll<[usize]>, consuming + /// the original: /// - /// [`String`]: ../../std/string/struct.String.html + /// [String]: ../../std/string/struct.String.html "String" /// ``` /// # use core::task::Poll; /// let poll_some_string = Poll::Ready(String::from("Hello, World!")); diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 35b740cd74372..d1533b8d67a6b 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1049,11 +1049,16 @@ impl fmt::Debug for Duration { /// `divisor` must not be above 100_000_000. It also should be a power /// of 10, everything else doesn't make sense. `fractional_part` has /// to be less than `10 * divisor`! + /// + /// A prefix and postfix may be added. The whole thing is padded + /// to the formatter's `width`, if specified. fn fmt_decimal( f: &mut fmt::Formatter<'_>, mut integer_part: u64, mut fractional_part: u32, mut divisor: u32, + prefix: &str, + postfix: &str, ) -> fmt::Result { // Encode the fractional part into a temporary buffer. The buffer // only need to hold 9 elements, because `fractional_part` has to @@ -1114,48 +1119,91 @@ impl fmt::Debug for Duration { // set, we only use all digits up to the last non-zero one. let end = f.precision().map(|p| crate::cmp::min(p, 9)).unwrap_or(pos); - // If we haven't emitted a single fractional digit and the precision - // wasn't set to a non-zero value, we don't print the decimal point. - if end == 0 { - write!(f, "{}", integer_part) - } else { - // SAFETY: We are only writing ASCII digits into the buffer and it was - // initialized with '0's, so it contains valid UTF8. - let s = unsafe { crate::str::from_utf8_unchecked(&buf[..end]) }; + // This closure emits the formatted duration without emitting any + // padding (padding is calculated below). + let emit_without_padding = |f: &mut fmt::Formatter<'_>| { + write!(f, "{}{}", prefix, integer_part)?; + + // Write the decimal point and the fractional part (if any). + if end > 0 { + // SAFETY: We are only writing ASCII digits into the buffer and + // it was initialized with '0's, so it contains valid UTF8. + let s = unsafe { crate::str::from_utf8_unchecked(&buf[..end]) }; + + // If the user request a precision > 9, we pad '0's at the end. + let w = f.precision().unwrap_or(pos); + write!(f, ".{:0 9, we pad '0's at the end. - let w = f.precision().unwrap_or(pos); - write!(f, "{}.{:0 { + // No `width` specified. There's no need to calculate the + // length of the output in this case, just emit it. + emit_without_padding(f) + } + Some(requested_w) => { + // A `width` was specified. Calculate the actual width of + // the output in order to calculate the required padding. + // It consists of 4 parts: + // 1. The prefix: is either "+" or "", so we can just use len(). + // 2. The postfix: can be "µs" so we have to count UTF8 characters. + let mut actual_w = prefix.len() + postfix.chars().count(); + // 3. The integer part: + if let Some(log) = integer_part.checked_log10() { + // integer_part is > 0, so has length log10(x)+1 + actual_w += 1 + log as usize; + } else { + // integer_part is 0, so has length 1. + actual_w += 1; + } + // 4. The fractional part (if any): + if end > 0 { + let frac_part_w = f.precision().unwrap_or(pos); + actual_w += 1 + frac_part_w; + } + + if requested_w <= actual_w { + // Output is already longer than `width`, so don't pad. + emit_without_padding(f) + } else { + // We need to add padding. Use the `Formatter::padding` helper function. + let default_align = crate::fmt::rt::v1::Alignment::Left; + let post_padding = f.padding(requested_w - actual_w, default_align)?; + emit_without_padding(f)?; + post_padding.write(f) + } + } } } // Print leading '+' sign if requested - if f.sign_plus() { - write!(f, "+")?; - } + let prefix = if f.sign_plus() { "+" } else { "" }; if self.secs > 0 { - fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10)?; - f.write_str("s") + fmt_decimal(f, self.secs, self.nanos, NANOS_PER_SEC / 10, prefix, "s") } else if self.nanos >= NANOS_PER_MILLI { fmt_decimal( f, (self.nanos / NANOS_PER_MILLI) as u64, self.nanos % NANOS_PER_MILLI, NANOS_PER_MILLI / 10, - )?; - f.write_str("ms") + prefix, + "ms", + ) } else if self.nanos >= NANOS_PER_MICRO { fmt_decimal( f, (self.nanos / NANOS_PER_MICRO) as u64, self.nanos % NANOS_PER_MICRO, NANOS_PER_MICRO / 10, - )?; - f.write_str("µs") + prefix, + "µs", + ) } else { - fmt_decimal(f, self.nanos as u64, 0, 1)?; - f.write_str("ns") + fmt_decimal(f, self.nanos as u64, 0, 1, prefix, "ns") } } } diff --git a/library/core/tests/fmt/num.rs b/library/core/tests/fmt/num.rs index 275a1d062cafb..b958422d14f84 100644 --- a/library/core/tests/fmt/num.rs +++ b/library/core/tests/fmt/num.rs @@ -146,6 +146,7 @@ fn test_format_int_exp_precision() { assert_eq!(format!("{:.1000e}", 1), format!("1.{}e0", "0".repeat(1000))); //test zero precision assert_eq!(format!("{:.0e}", 1), format!("1e0",)); + assert_eq!(format!("{:.0e}", 35), format!("4e1",)); //test padding with precision (and sign) assert_eq!(format!("{:+10.3e}", 1), " +1.000e0"); diff --git a/library/core/tests/iter/adapters/flatten.rs b/library/core/tests/iter/adapters/flatten.rs index aaac39c297933..4ae50a2f06681 100644 --- a/library/core/tests/iter/adapters/flatten.rs +++ b/library/core/tests/iter/adapters/flatten.rs @@ -58,6 +58,23 @@ fn test_flatten_try_folds() { assert_eq!(iter.next_back(), Some(35)); } +#[test] +fn test_flatten_advance_by() { + let mut it = once(0..10).chain(once(10..30)).chain(once(30..40)).flatten(); + it.advance_by(5).unwrap(); + assert_eq!(it.next(), Some(5)); + it.advance_by(9).unwrap(); + assert_eq!(it.next(), Some(15)); + it.advance_back_by(4).unwrap(); + assert_eq!(it.next_back(), Some(35)); + it.advance_back_by(9).unwrap(); + assert_eq!(it.next_back(), Some(25)); + + assert_eq!(it.advance_by(usize::MAX), Err(9)); + assert_eq!(it.advance_back_by(usize::MAX), Err(0)); + assert_eq!(it.size_hint(), (0, Some(0))); +} + #[test] fn test_flatten_non_fused_outer() { let mut iter = NonFused::new(once(0..2)).flatten(); diff --git a/library/core/tests/iter/range.rs b/library/core/tests/iter/range.rs index 44adc3c58d249..6b4cf33efe1ff 100644 --- a/library/core/tests/iter/range.rs +++ b/library/core/tests/iter/range.rs @@ -285,6 +285,29 @@ fn test_range_step() { assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); } +#[test] +fn test_range_advance_by() { + let mut r = 0..usize::MAX; + r.advance_by(0).unwrap(); + r.advance_back_by(0).unwrap(); + + assert_eq!(r.len(), usize::MAX); + + r.advance_by(1).unwrap(); + r.advance_back_by(1).unwrap(); + + assert_eq!((r.start, r.end), (1, usize::MAX - 1)); + + assert_eq!(r.advance_by(usize::MAX), Err(usize::MAX - 2)); + + let mut r = 0u128..u128::MAX; + + r.advance_by(usize::MAX).unwrap(); + r.advance_back_by(usize::MAX).unwrap(); + + assert_eq!((r.start, r.end), (0u128 + usize::MAX as u128, u128::MAX - usize::MAX as u128)); +} + #[test] fn test_range_inclusive_step() { assert_eq!((0..=50).step_by(10).collect::>(), [0, 10, 20, 30, 40, 50]); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index cd3aed4cd28f8..0673564dd5c4a 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -48,6 +48,7 @@ #![feature(int_log)] #![feature(iter_advance_by)] #![feature(iter_partition_in_place)] +#![feature(iter_intersperse)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] #![feature(const_mut_refs)] diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index d2d655ea2c750..0ad85bf6d943d 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -294,33 +294,33 @@ macro_rules! int_module { fn test_div_floor() { let a: $T = 8; let b = 3; - assert_eq!(a.div_floor(b), 2); - assert_eq!(a.div_floor(-b), -3); - assert_eq!((-a).div_floor(b), -3); - assert_eq!((-a).div_floor(-b), 2); + assert_eq!(a.unstable_div_floor(b), 2); + assert_eq!(a.unstable_div_floor(-b), -3); + assert_eq!((-a).unstable_div_floor(b), -3); + assert_eq!((-a).unstable_div_floor(-b), 2); } #[test] fn test_div_ceil() { let a: $T = 8; let b = 3; - assert_eq!(a.div_ceil(b), 3); - assert_eq!(a.div_ceil(-b), -2); - assert_eq!((-a).div_ceil(b), -2); - assert_eq!((-a).div_ceil(-b), 3); + assert_eq!(a.unstable_div_ceil(b), 3); + assert_eq!(a.unstable_div_ceil(-b), -2); + assert_eq!((-a).unstable_div_ceil(b), -2); + assert_eq!((-a).unstable_div_ceil(-b), 3); } #[test] fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!((16 as $T).next_multiple_of(-8), 16); - assert_eq!((23 as $T).next_multiple_of(-8), 16); - assert_eq!((-16 as $T).next_multiple_of(8), -16); - assert_eq!((-23 as $T).next_multiple_of(8), -16); - assert_eq!((-16 as $T).next_multiple_of(-8), -16); - assert_eq!((-23 as $T).next_multiple_of(-8), -24); - assert_eq!(MIN.next_multiple_of(-1), MIN); + assert_eq!((16 as $T).unstable_next_multiple_of(8), 16); + assert_eq!((23 as $T).unstable_next_multiple_of(8), 24); + assert_eq!((16 as $T).unstable_next_multiple_of(-8), 16); + assert_eq!((23 as $T).unstable_next_multiple_of(-8), 16); + assert_eq!((-16 as $T).unstable_next_multiple_of(8), -16); + assert_eq!((-23 as $T).unstable_next_multiple_of(8), -16); + assert_eq!((-16 as $T).unstable_next_multiple_of(-8), -16); + assert_eq!((-23 as $T).unstable_next_multiple_of(-8), -24); + assert_eq!(MIN.unstable_next_multiple_of(-1), MIN); } #[test] diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 49f8f1f13fad4..35ec88c6af7d6 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -208,19 +208,19 @@ macro_rules! uint_module { #[test] fn test_div_floor() { - assert_eq!((8 as $T).div_floor(3), 2); + assert_eq!((8 as $T).unstable_div_floor(3), 2); } #[test] fn test_div_ceil() { - assert_eq!((8 as $T).div_ceil(3), 3); + assert_eq!((8 as $T).unstable_div_ceil(3), 3); } #[test] fn test_next_multiple_of() { - assert_eq!((16 as $T).next_multiple_of(8), 16); - assert_eq!((23 as $T).next_multiple_of(8), 24); - assert_eq!(MAX.next_multiple_of(1), MAX); + assert_eq!((16 as $T).unstable_next_multiple_of(8), 16); + assert_eq!((23 as $T).unstable_next_multiple_of(8), 24); + assert_eq!(MAX.unstable_next_multiple_of(1), MAX); } #[test] diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index cd8fdebe36a05..8995f96b1238a 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -367,6 +367,19 @@ fn option_const() { const IS_NONE: bool = OPTION.is_none(); assert!(!IS_NONE); + + const COPIED: Option = OPTION.as_ref().copied(); + assert_eq!(COPIED, OPTION); +} + +#[test] +const fn option_const_mut() { + // test that the methods of `Option` that take mutable references are usable in a const context + + let mut option: Option = Some(32); + + let _take = option.take(); + let _replace = option.replace(42); } #[test] diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs index f14639e0d589f..fe2d2f2412daa 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -313,6 +313,34 @@ fn debug_formatting_precision_two() { assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s"); } +#[test] +fn debug_formatting_padding() { + assert_eq!("0ns ", format!("{:<9?}", Duration::new(0, 0))); + assert_eq!(" 0ns", format!("{:>9?}", Duration::new(0, 0))); + assert_eq!(" 0ns ", format!("{:^9?}", Duration::new(0, 0))); + assert_eq!("123ns ", format!("{:<9.0?}", Duration::new(0, 123))); + assert_eq!(" 123ns", format!("{:>9.0?}", Duration::new(0, 123))); + assert_eq!(" 123ns ", format!("{:^9.0?}", Duration::new(0, 123))); + assert_eq!("123.0ns ", format!("{:<9.1?}", Duration::new(0, 123))); + assert_eq!(" 123.0ns", format!("{:>9.1?}", Duration::new(0, 123))); + assert_eq!(" 123.0ns ", format!("{:^9.1?}", Duration::new(0, 123))); + assert_eq!("7.1µs ", format!("{:<9?}", Duration::new(0, 7_100))); + assert_eq!(" 7.1µs", format!("{:>9?}", Duration::new(0, 7_100))); + assert_eq!(" 7.1µs ", format!("{:^9?}", Duration::new(0, 7_100))); + assert_eq!("999.123456ms", format!("{:<9?}", Duration::new(0, 999_123_456))); + assert_eq!("999.123456ms", format!("{:>9?}", Duration::new(0, 999_123_456))); + assert_eq!("999.123456ms", format!("{:^9?}", Duration::new(0, 999_123_456))); + assert_eq!("5s ", format!("{:<9?}", Duration::new(5, 0))); + assert_eq!(" 5s", format!("{:>9?}", Duration::new(5, 0))); + assert_eq!(" 5s ", format!("{:^9?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:<9.12?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:>9.12?}", Duration::new(5, 0))); + assert_eq!("5.000000000000s", format!("{:^9.12?}", Duration::new(5, 0))); + + // default alignment is left: + assert_eq!("5s ", format!("{:9?}", Duration::new(5, 0))); +} + #[test] fn debug_formatting_precision_high() { assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs"); diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 4580f9a7758f3..ac75ce7f22110 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -44,6 +44,7 @@ pub unsafe extern "C-unwind" fn __rust_start_panic(_payload: *mut &mut dyn BoxMe libc::abort(); } } else if #[cfg(any(target_os = "hermit", + target_os = "solid_asp3", all(target_vendor = "fortanix", target_env = "sgx") ))] { unsafe fn abort() -> ! { diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index ac7d8c18e3e02..b5d0ca2572c93 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -45,6 +45,7 @@ cfg_if::cfg_if! { } else if #[cfg(any( all(target_family = "windows", target_env = "gnu"), target_os = "psp", + target_os = "solid_asp3", all(target_family = "unix", not(target_os = "espidf")), all(target_vendor = "fortanix", target_env = "sgx"), ))] { diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 1b051b0d0f6e5..6bc445c6f2b07 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -15,7 +15,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.99", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.103", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.44" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } @@ -72,6 +72,7 @@ panic_immediate_abort = ["core/panic_immediate_abort"] # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = ["std_detect/std_detect_file_io"] std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] +std_detect_env_override = ["std_detect/std_detect_env_override"] [package.metadata.fortanix-sgx] # Maximum possible number of threads when testing diff --git a/library/std/build.rs b/library/std/build.rs index 726157c1f1a41..cc7184d57f178 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -27,6 +27,7 @@ fn main() { || target.contains("wasm32") || target.contains("asmjs") || target.contains("espidf") + || target.contains("solid") { // These platforms don't have any special requirements. } else { diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 36077a42b48ac..528bb1bf6e9f9 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -203,8 +203,9 @@ use crate::sys; /// } /// ``` -#[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "HashMap")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct HashMap { base: base::HashMap, } @@ -624,14 +625,13 @@ where /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, isize> = HashMap::new(); /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); /// ``` #[inline] - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.base.try_reserve(additional).map_err(map_try_reserve_error) } @@ -1257,9 +1257,10 @@ impl<'a, K, V> IterMut<'a, K, V> { /// An owning iterator over the entries of a `HashMap`. /// /// This `struct` is created by the [`into_iter`] method on [`HashMap`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: crate::iter::IntoIterator /// /// # Example /// diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 3b61acd122e2e..dcfe322095082 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -107,7 +107,7 @@ use super::map::{map_try_reserve_error, RandomState}; /// [`HashMap`]: crate::collections::HashMap /// [`RefCell`]: crate::cell::RefCell /// [`Cell`]: crate::cell::Cell -#[cfg_attr(not(test), rustc_diagnostic_item = "hashset_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "HashSet")] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashSet { base: base::HashSet, @@ -423,13 +423,12 @@ where /// # Examples /// /// ``` - /// #![feature(try_reserve)] /// use std::collections::HashSet; /// let mut set: HashSet = HashSet::new(); /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); /// ``` #[inline] - #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] + #[stable(feature = "try_reserve", since = "1.57.0")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { self.base.try_reserve(additional).map_err(map_try_reserve_error) } @@ -1237,9 +1236,10 @@ pub struct Iter<'a, K: 'a> { /// An owning iterator over the items of a `HashSet`. /// /// This `struct` is created by the [`into_iter`] method on [`HashSet`] -/// (provided by the `IntoIterator` trait). See its documentation for more. +/// (provided by the [`IntoIterator`] trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// [`IntoIterator`]: crate::iter::IntoIterator /// /// # Examples /// diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index 71645aadb1d88..a19c3431989c0 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -97,11 +97,11 @@ //! //! ## Sequences //! -//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | -//! |----------------|----------------|-----------------|----------------|--------|----------------| -//! | [`Vec`] | O(1) | O(n-i)* | O(n-i) | O(m)* | O(n-i) | -//! | [`VecDeque`] | O(1) | O(min(i, n-i))* | O(min(i, n-i)) | O(m)* | O(min(i, n-i)) | -//! | [`LinkedList`] | O(min(i, n-i)) | O(min(i, n-i)) | O(min(i, n-i)) | O(1) | O(min(i, n-i)) | +//! | | get(i) | insert(i) | remove(i) | append | split_off(i) | +//! |----------------|------------------------|-------------------------|------------------------|-----------|------------------------| +//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) | +//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) | +//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) | //! //! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and //! [`VecDeque`] is generally going to be faster than [`LinkedList`]. @@ -110,10 +110,10 @@ //! //! For Sets, all operations have the cost of the equivalent Map operation. //! -//! | | get | insert | remove | range | append | -//! |--------------|-----------|-----------|-----------|-----------|--------| -//! | [`HashMap`] | O(1)~ | O(1)~* | O(1)~ | N/A | N/A | -//! | [`BTreeMap`] | O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) | O(n+m) | +//! | | get | insert | remove | range | append | +//! |--------------|---------------|---------------|---------------|---------------|--------------| +//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A | +//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(*n*+*m*) | //! //! # Correct and Efficient Usage of Collections //! @@ -217,7 +217,7 @@ //! contents by-value. This is great when the collection itself is no longer //! needed, and the values are needed elsewhere. Using `extend` with `into_iter` //! is the main way that contents of one collection are moved into another. -//! `extend` automatically calls `into_iter`, and takes any `T: `[`IntoIterator`]. +//! `extend` automatically calls `into_iter`, and takes any T: [IntoIterator]. //! Calling `collect` on an iterator itself is also a great way to convert one //! collection into another. Both of these methods should internally use the //! capacity management tools discussed in the previous section to do this as @@ -396,7 +396,7 @@ //! assert_eq!(map.keys().next().unwrap().b, "baz"); //! ``` //! -//! [`IntoIterator`]: crate::iter::IntoIterator +//! [IntoIterator]: crate::iter::IntoIterator "iter::IntoIterator" #![stable(feature = "rust1", since = "1.0.0")] @@ -420,7 +420,7 @@ pub use self::hash_map::HashMap; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_set::HashSet; -#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] +#[stable(feature = "try_reserve", since = "1.57.0")] pub use alloc_crate::collections::TryReserveError; #[unstable( feature = "try_reserve_kind", diff --git a/library/std/src/error.rs b/library/std/src/error.rs index cc4ea27e57e8d..6ae0bc47a9462 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -595,7 +595,7 @@ impl Error for char::ParseCharError { } } -#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] +#[stable(feature = "try_reserve", since = "1.57.0")] impl Error for alloc::collections::TryReserveError {} #[unstable(feature = "duration_checked_float", issue = "83400")] diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 3b9175503080c..fe1f28f00c403 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -29,18 +29,18 @@ use crate::sys_common::memchr; /// type is a static guarantee that the underlying bytes contain no interior 0 /// bytes ("nul characters") and that the final byte is 0 ("nul terminator"). /// -/// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former +/// `CString` is to &[CStr] as [`String`] is to &[str]: the former /// in each pair are owned strings; the latter are borrowed /// references. /// /// # Creating a `CString` /// /// A `CString` is created from either a byte slice or a byte vector, -/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for +/// or anything that implements [Into]<[Vec]<[u8]>> (for /// example, you can build a `CString` straight out of a [`String`] or -/// a [`&str`], since both implement that trait). +/// a &[str], since both implement that trait). /// -/// The [`CString::new`] method will actually check that the provided `&[u8]` +/// The [`CString::new`] method will actually check that the provided &[[u8]] /// does not have 0 bytes in the middle, and return an error if it /// finds one. /// @@ -55,7 +55,7 @@ use crate::sys_common::memchr; /// /// # Extracting a slice of the whole C string /// -/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a +/// Alternatively, you can obtain a &[[u8]] slice from a /// `CString` with the [`CString::as_bytes`] method. Slices produced in this /// way do *not* contain the trailing nul terminator. This is useful /// when you will be calling an extern function that takes a `*const @@ -64,7 +64,7 @@ use crate::sys_common::memchr; /// You can of course get the slice's length with its /// [`len`][slice::len] method. /// -/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you +/// If you need a &[[u8]] slice *with* the nul terminator, you /// can use [`CString::as_bytes_with_nul`] instead. /// /// Once you have the kind of slice you need (with or without a nul @@ -73,9 +73,8 @@ use crate::sys_common::memchr; /// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// -/// [`&str`]: prim@str +/// [str]: prim@str "str" /// [`Deref`]: ops::Deref -/// [`&CStr`]: CStr /// /// # Examples /// @@ -120,12 +119,12 @@ pub struct CString { /// Representation of a borrowed C string. /// /// This type represents a borrowed reference to a nul-terminated -/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]` +/// array of bytes. It can be constructed safely from a &[[u8]] /// slice, or unsafely from a raw `*const c_char`. It can then be -/// converted to a Rust [`&str`] by performing UTF-8 validation, or +/// converted to a Rust &[str] by performing UTF-8 validation, or /// into an owned [`CString`]. /// -/// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former +/// `&CStr` is to [`CString`] as &[str] is to [`String`]: the former /// in each pair are borrowed references; the latter are owned /// strings. /// @@ -183,7 +182,7 @@ pub struct CString { /// println!("string: {}", my_string_safe()); /// ``` /// -/// [`&str`]: prim@str +/// [str]: prim@str "str" #[derive(Hash)] #[cfg_attr(not(test), rustc_diagnostic_item = "CStr")] #[stable(feature = "rust1", since = "1.0.0")] @@ -410,6 +409,8 @@ impl CString { /// Creates a C-compatible string by consuming a byte vector, /// without checking for interior 0 bytes. /// + /// Trailing 0 byte will be appended by this function. + /// /// This method is equivalent to [`CString::new`] except that no runtime /// assertion is made that `v` contains no 0 bytes, and it requires an /// actual byte vector, not anything that can be converted to one with Into. @@ -682,7 +683,7 @@ impl CString { unsafe { ptr::read(&this.inner) } } - /// Converts a [`Vec`]`` to a [`CString`] without checking the + /// Converts a [Vec]<[u8]> to a [`CString`] without checking the /// invariants on the given [`Vec`]. /// /// # Safety @@ -705,7 +706,7 @@ impl CString { Self { inner: v.into_boxed_slice() } } - /// Attempts to converts a [`Vec`]`` to a [`CString`]. + /// Attempts to converts a [Vec]<[u8]> to a [`CString`]. /// /// Runtime checks are present to ensure there is only one nul byte in the /// [`Vec`], its last element. @@ -793,7 +794,7 @@ impl fmt::Debug for CString { #[stable(feature = "cstring_into", since = "1.7.0")] impl From for Vec { - /// Converts a [`CString`] into a [`Vec`]``. + /// Converts a [`CString`] into a [Vec]<[u8]>. /// /// The conversion consumes the [`CString`], and removes the terminating NUL byte. #[inline] @@ -867,7 +868,7 @@ impl From> for Box { #[stable(feature = "c_string_from_box", since = "1.18.0")] impl From> for CString { - /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. + /// Converts a [Box]<[CStr]> into a [`CString`] without copying or allocating. #[inline] fn from(s: Box) -> CString { s.into_c_string() @@ -876,7 +877,7 @@ impl From> for CString { #[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")] impl From> for CString { - /// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without + /// Converts a [Vec]<[NonZeroU8]> into a [`CString`] without /// copying nor checking for inner null bytes. #[inline] fn from(v: Vec) -> CString { @@ -906,7 +907,7 @@ impl Clone for Box { #[stable(feature = "box_from_c_string", since = "1.20.0")] impl From for Box { - /// Converts a [`CString`] into a [`Box`]`` without copying or allocating. + /// Converts a [`CString`] into a [Box]<[CStr]> without copying or allocating. #[inline] fn from(s: CString) -> Box { s.into_boxed_c_str() @@ -942,7 +943,7 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { - /// Converts a [`CString`] into an [`Arc`]`` without copying or allocating. + /// Converts a [`CString`] into an [Arc]<[CStr]> without copying or allocating. #[inline] fn from(s: CString) -> Arc { let arc: Arc<[u8]> = Arc::from(s.into_inner()); @@ -961,7 +962,7 @@ impl From<&CStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts a [`CString`] into an [`Rc`]`` without copying or allocating. + /// Converts a [`CString`] into an [Rc]<[CStr]> without copying or allocating. #[inline] fn from(s: CString) -> Rc { let rc: Rc<[u8]> = Rc::from(s.into_inner()); @@ -1355,13 +1356,13 @@ impl CStr { unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } } - /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. + /// Yields a &[str] slice if the `CStr` contains valid UTF-8. /// /// If the contents of the `CStr` are valid UTF-8 data, this - /// function will return the corresponding [`&str`] slice. Otherwise, + /// function will return the corresponding &[str] slice. Otherwise, /// it will return an error with details of where UTF-8 validation failed. /// - /// [`&str`]: prim@str + /// [str]: prim@str "str" /// /// # Examples /// @@ -1380,20 +1381,19 @@ impl CStr { str::from_utf8(self.to_bytes()) } - /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`. + /// Converts a `CStr` into a [Cow]<[str]>. /// /// If the contents of the `CStr` are valid UTF-8 data, this - /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` - /// with the corresponding [`&str`] slice. Otherwise, it will + /// function will return a [Cow]::[Borrowed]\(&[str]) + /// with the corresponding &[str] slice. Otherwise, it will /// replace any invalid UTF-8 sequences with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a - /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. + /// [Cow]::[Owned]\(&[str]) with the result. /// - /// [`str`]: primitive@str - /// [`&str`]: primitive@str - /// [`Borrowed`]: Cow::Borrowed - /// [`Owned`]: Cow::Owned - /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER + /// [str]: prim@str "str" + /// [Borrowed]: Cow::Borrowed + /// [Owned]: Cow::Owned + /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER" /// /// # Examples /// @@ -1426,7 +1426,7 @@ impl CStr { String::from_utf8_lossy(self.to_bytes()) } - /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. + /// Converts a [Box]<[CStr]> into a [`CString`] without copying or allocating. /// /// # Examples /// diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index fe4e3af91ad0a..82a76aa73c583 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -43,8 +43,8 @@ //! terminator, so the buffer length is really `len+1` characters. //! Rust strings don't have a nul terminator; their length is always //! stored and does not need to be calculated. While in Rust -//! accessing a string's length is a `O(1)` operation (because the -//! length is stored); in C it is an `O(length)` operation because the +//! accessing a string's length is an *O*(1) operation (because the +//! length is stored); in C it is an *O*(*n*) operation because the //! length needs to be computed by scanning the string for the nul //! terminator. //! @@ -64,15 +64,15 @@ //! string: it is nul-terminated, and has no internal nul characters. //! Rust code can create a [`CString`] out of a normal string (provided //! that the string doesn't have nul characters in the middle), and -//! then use a variety of methods to obtain a raw `*mut `[`u8`] that can +//! then use a variety of methods to obtain a raw \*mut [u8] that can //! then be passed as an argument to functions which use the C //! conventions for strings. //! //! * **From C to Rust:** [`CStr`] represents a borrowed C string; it -//! is what you would use to wrap a raw `*const `[`u8`] that you got from +//! is what you would use to wrap a raw \*const [u8] that you got from //! a C function. A [`CStr`] is guaranteed to be a nul-terminated array //! of bytes. Once you have a [`CStr`], you can convert it to a Rust -//! [`&str`][`str`] if it's valid UTF-8, or lossily convert it by adding +//! &[str] if it's valid UTF-8, or lossily convert it by adding //! replacement characters. //! //! [`OsString`] and [`OsStr`] are useful when you need to transfer @@ -86,9 +86,9 @@ //! library, various APIs that transfer strings to/from the operating //! system use [`OsString`] instead of plain strings. For example, //! [`env::var_os()`] is used to query environment variables; it -//! returns an [`Option`]`<`[`OsString`]`>`. If the environment variable -//! exists you will get a [`Some`]`(os_string)`, which you can *then* try to -//! convert to a Rust string. This yields a [`Result`], so that +//! returns an [Option]<[OsString]>. If the environment variable +//! exists you will get a [Some]\(os_string), which you can +//! *then* try to convert to a Rust string. This yields a [`Result`], so that //! your code can detect errors in case the environment variable did //! not in fact contain valid Unicode data. //! @@ -102,44 +102,44 @@ //! ## On Unix //! //! On Unix, [`OsStr`] implements the -//! `std::os::unix::ffi::`[`OsStrExt`][unix.OsStrExt] trait, which +//! std::os::unix::ffi::[OsStrExt][unix.OsStrExt] trait, which //! augments it with two methods, [`from_bytes`] and [`as_bytes`]. //! These do inexpensive conversions from and to UTF-8 byte slices. //! //! Additionally, on Unix [`OsString`] implements the -//! `std::os::unix::ffi::`[`OsStringExt`][unix.OsStringExt] trait, +//! std::os::unix::ffi::[OsStringExt][unix.OsStringExt] trait, //! which provides [`from_vec`] and [`into_vec`] methods that consume //! their arguments, and take or produce vectors of [`u8`]. //! //! ## On Windows //! //! On Windows, [`OsStr`] implements the -//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait, +//! std::os::windows::ffi::[OsStrExt][windows.OsStrExt] trait, //! which provides an [`encode_wide`] method. This provides an //! iterator that can be [`collect`]ed into a vector of [`u16`]. //! //! Additionally, on Windows [`OsString`] implements the -//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt] +//! std::os::windows:ffi::[OsStringExt][windows.OsStringExt] //! trait, which provides a [`from_wide`] method. The result of this //! method is an [`OsString`] which can be round-tripped to a Windows //! string losslessly. //! //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value //! [Unicode code point]: https://www.unicode.org/glossary/#code_point -//! [`env::set_var()`]: crate::env::set_var -//! [`env::var_os()`]: crate::env::var_os -//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt -//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec -//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec -//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt -//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes -//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes -//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt -//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt -//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide -//! [`collect`]: crate::iter::Iterator::collect -//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt -//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide +//! [`env::set_var()`]: crate::env::set_var "env::set_var" +//! [`env::var_os()`]: crate::env::var_os "env::var_os" +//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt "os::unix::ffi::OsStringExt" +//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec "os::unix::ffi::OsStringExt::from_vec" +//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec "os::unix::ffi::OsStringExt::into_vec" +//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt" +//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes "os::unix::ffi::OsStrExt::from_bytes" +//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes "os::unix::ffi::OsStrExt::as_bytes" +//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt" +//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt "os::windows::ffi::OsStrExt" +//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide "os::windows::ffi::OsStrExt::encode_wide" +//! [`collect`]: crate::iter::Iterator::collect "iter::Iterator::collect" +//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt "os::windows::ffi::OsStringExt" +//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide "os::windows::ffi::OsStringExt::from_wide" #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 21f354caf6ae9..7e70901076cda 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -33,7 +33,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// of this is that `OsString` instances are *not* `NUL` terminated; in order /// to pass to e.g., Unix system call, you should create a [`CStr`]. /// -/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former +/// `OsString` is to &[OsStr] as [`String`] is to &[str]: the former /// in each pair are owned strings; the latter are borrowed /// references. /// @@ -47,18 +47,18 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// # Creating an `OsString` /// /// **From a Rust string**: `OsString` implements -/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to +/// [From]<[String]>, so you can use my_string.[into]\() to /// create an `OsString` from a normal Rust string. /// /// **From slices:** Just like you can start with an empty Rust -/// [`String`] and then [`String::push_str`] `&str` +/// [`String`] and then [`String::push_str`] some &[str] /// sub-string slices into it, you can create an empty `OsString` with /// the [`OsString::new`] method and then push string slices into it with the /// [`OsString::push`] method. /// /// # Extracting a borrowed reference to the whole OS string /// -/// You can use the [`OsString::as_os_str`] method to get an `&`[`OsStr`] from +/// You can use the [`OsString::as_os_str`] method to get an &[OsStr] from /// an `OsString`; this is effectively a borrowed reference to the /// whole string. /// @@ -67,10 +67,9 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// See the [module's toplevel documentation about conversions][conversions] for a discussion on /// the traits which `OsString` implements for [conversions] from/to native representations. /// -/// [`&OsStr`]: OsStr -/// [`&str`]: str /// [`CStr`]: crate::ffi::CStr /// [conversions]: super#conversions +/// [into]: Into::into #[cfg_attr(not(test), rustc_diagnostic_item = "OsString")] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { @@ -86,13 +85,12 @@ impl crate::sealed::Sealed for OsString {} /// This type represents a borrowed reference to a string in the operating system's preferred /// representation. /// -/// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed -/// references; the latter are owned strings. +/// `&OsStr` is to [`OsString`] as &[str] is to [`String`]: the +/// former in each pair are borrowed references; the latter are owned strings. /// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on /// the traits which `OsStr` implements for [conversions] from/to native representations. /// -/// [`&str`]: str /// [conversions]: super#conversions #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] #[stable(feature = "rust1", since = "1.0.0")] @@ -162,9 +160,7 @@ impl OsString { self.inner.into_string().map_err(|buf| OsString { inner: buf }) } - /// Extends the string with the given [`&OsStr`] slice. - /// - /// [`&OsStr`]: OsStr + /// Extends the string with the given &[OsStr] slice. /// /// # Examples /// @@ -563,12 +559,10 @@ impl OsStr { unsafe { &mut *(inner as *mut Slice as *mut OsStr) } } - /// Yields a [`&str`] slice if the `OsStr` is valid Unicode. + /// Yields a &[str] slice if the `OsStr` is valid Unicode. /// /// This conversion may entail doing a check for UTF-8 validity. /// - /// [`&str`]: str - /// /// # Examples /// /// ``` @@ -583,7 +577,7 @@ impl OsStr { self.inner.to_str() } - /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`. + /// Converts an `OsStr` to a [Cow]<[str]>. /// /// Any non-Unicode sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. @@ -701,7 +695,7 @@ impl OsStr { self.inner.inner.len() } - /// Converts a [`Box`]`` into an [`OsString`] without copying or allocating. + /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or allocating. #[stable(feature = "into_boxed_os_str", since = "1.20.0")] pub fn into_os_string(self: Box) -> OsString { let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) }; @@ -870,7 +864,7 @@ impl From> for Box { #[stable(feature = "os_string_from_box", since = "1.18.0")] impl From> for OsString { - /// Converts a [`Box`]`<`[`OsStr`]`>` into an [`OsString`] without copying or + /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or /// allocating. #[inline] fn from(boxed: Box) -> OsString { @@ -880,7 +874,7 @@ impl From> for OsString { #[stable(feature = "box_from_os_string", since = "1.20.0")] impl From for Box { - /// Converts an [`OsString`] into a [`Box`]`` without copying or allocating. + /// Converts an [`OsString`] into a [Box]<[OsStr]> without copying or allocating. #[inline] fn from(s: OsString) -> Box { s.into_boxed_os_str() @@ -897,7 +891,7 @@ impl Clone for Box { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { - /// Converts an [`OsString`] into an [`Arc`]`` without copying or allocating. + /// Converts an [`OsString`] into an [Arc]<[OsStr]> without copying or allocating. #[inline] fn from(s: OsString) -> Arc { let arc = s.inner.into_arc(); @@ -916,7 +910,7 @@ impl From<&OsStr> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts an [`OsString`] into an [`Rc`]`` without copying or allocating. + /// Converts an [`OsString`] into an [Rc]<[OsStr]> without copying or allocating. #[inline] fn from(s: OsString) -> Rc { let rc = s.inner.into_rc(); diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index bdb172907ffed..e999c84f80d47 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -106,7 +106,7 @@ pub struct Metadata(fs_imp::FileAttr); /// Iterator over the entries in a directory. /// /// This iterator is returned from the [`read_dir`] function of this module and -/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`] +/// will yield instances of [io::Result]<[DirEntry]>. Through a [`DirEntry`] /// information like the entry's path and possibly other metadata can be /// learned. /// @@ -200,10 +200,9 @@ pub struct DirBuilder { /// Indicates how large a buffer to pre-allocate before reading the entire file. fn initial_buffer_size(file: &File) -> usize { - // Allocate one extra byte so the buffer doesn't need to grow before the - // final `read` call at the end of the file. Don't worry about `usize` - // overflow because reading will fail regardless in that case. - file.metadata().map(|m| m.len() as usize + 1).unwrap_or(0) + // Don't worry about `usize` overflow because reading will fail regardless + // in that case. + file.metadata().map(|m| m.len() as usize).unwrap_or(0) } /// Read the entire contents of a file into a bytes vector. @@ -786,17 +785,17 @@ impl OpenOptions { /// If a file is opened with both read and append access, beware that after /// opening, and after every write, the position for reading may be set at the /// end of the file. So, before writing, save the current position (using - /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read. + /// [seek]\([SeekFrom]::[Current]\(0))), and restore it before the next read. /// /// ## Note /// /// This function doesn't create the file if it doesn't exist. Use the /// [`OpenOptions::create`] method to do so. /// - /// [`write()`]: Write::write - /// [`flush()`]: Write::flush - /// [`seek`]: Seek::seek - /// [`Current`]: SeekFrom::Current + /// [`write()`]: Write::write "io::Write::write" + /// [`flush()`]: Write::flush "io::Write::flush" + /// [seek]: Seek::seek "io::Seek::seek" + /// [Current]: SeekFrom::Current "io::SeekFrom::Current" /// /// # Examples /// @@ -2043,7 +2042,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// Returns an iterator over the entries within a directory. /// -/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. +/// The iterator will yield instances of [io::Result]<[DirEntry]>. /// New errors may be encountered after an iterator is initially constructed. /// Entries for the current and parent directories (typically `.` and `..`) are /// skipped. diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 32d194d961652..869ac1ec8596c 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -15,7 +15,7 @@ use crate::io::{ /// *repeated* read calls to the same file or network socket. It does not /// help when reading very large amounts at once, or reading just one or a few /// times. It also provides no advantage when reading from a source that is -/// already in memory, like a [`Vec`]``. +/// already in memory, like a [Vec]\. /// /// When the `BufReader` is dropped, the contents of its buffer will be /// discarded. Creating multiple instances of a `BufReader` on the same @@ -347,7 +347,7 @@ where impl Seek for BufReader { /// Seek to an offset, in bytes, in the underlying reader. /// - /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the + /// The position used for seeking with [SeekFrom::Current]\(_) is the /// position the underlying reader would be at if the `BufReader` had no /// internal buffer. /// @@ -360,11 +360,11 @@ impl Seek for BufReader { /// /// See [`std::io::Seek`] for more details. /// - /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` + /// Note: In the edge case where you're seeking with [SeekFrom::Current]\(n) /// where `n` minus the internal buffer length overflows an `i64`, two /// seeks will be performed instead of one. If the second seek returns /// [`Err`], the underlying reader will be left at the same position it would - /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. + /// have if you called `seek` with [SeekFrom::Current]\(0). /// /// [`std::io::Seek`]: Seek fn seek(&mut self, pos: SeekFrom) -> io::Result { diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index df60af7c36a3e..ebbda7c1bf2a0 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -18,7 +18,7 @@ use crate::ptr; /// *repeated* write calls to the same file or network socket. It does not /// help when writing very large amounts at once, or writing just one or a few /// times. It also provides no advantage when writing to a destination that is -/// in memory, like a [`Vec`]``. +/// in memory, like a [Vec]\. /// /// It is critical to call [`flush`] before `BufWriter` is dropped. Though /// dropping will attempt to flush the contents of the buffer, any errors diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index ae0cea985d77c..980b2531192e8 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -12,13 +12,13 @@ use core::convert::TryInto; /// [`Seek`] implementation. /// /// `Cursor`s are used with in-memory buffers, anything implementing -/// [`AsRef`]`<[u8]>`, to allow them to implement [`Read`] and/or [`Write`], +/// [AsRef]<\[u8]>, to allow them to implement [`Read`] and/or [`Write`], /// allowing these buffers to be used anywhere you might use a reader or writer /// that does actual I/O. /// /// The standard library implements some I/O traits on various types which -/// are commonly used as a buffer, like `Cursor<`[`Vec`]`>` and -/// `Cursor<`[`&[u8]`][bytes]`>`. +/// are commonly used as a buffer, like Cursor<[Vec]\> and +/// Cursor<[&\[u8\]][bytes]>. /// /// # Examples /// @@ -26,7 +26,7 @@ use core::convert::TryInto; /// code, but use an in-memory buffer in our tests. We can do this with /// `Cursor`: /// -/// [bytes]: crate::slice +/// [bytes]: crate::slice "slice" /// [`File`]: crate::fs::File /// /// ```no_run @@ -292,12 +292,7 @@ where SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n), SeekFrom::Current(n) => (self.pos, n), }; - let new_pos = if offset >= 0 { - base_pos.checked_add(offset as u64) - } else { - base_pos.checked_sub((offset.wrapping_neg()) as u64) - }; - match new_pos { + match base_pos.checked_add_signed(offset) { Some(n) => { self.pos = n; Ok(self.pos) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 4a35d36a9def7..b4e49ca89d76b 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -362,22 +362,18 @@ where // Because we're extending the buffer with uninitialized data for trusted // readers, we need to make sure to truncate that if any of this panics. fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { - read_to_end_with_reservation(r, buf, |_| 32) -} - -fn read_to_end_with_reservation( - r: &mut R, - buf: &mut Vec, - mut reservation_size: F, -) -> Result -where - R: Read + ?Sized, - F: FnMut(&R) -> usize, -{ let start_len = buf.len(); + let start_cap = buf.capacity(); let mut g = Guard { len: buf.len(), buf }; loop { - if g.len == g.buf.len() { + // If we've read all the way up to the capacity, reserve more space. + if g.len == g.buf.capacity() { + g.buf.reserve(32); + } + + // Initialize any excess capacity and adjust the length so we can write + // to it. + if g.buf.len() < g.buf.capacity() { unsafe { // FIXME(danielhenrymantilla): #42788 // @@ -387,7 +383,6 @@ where // - Only the standard library gets to soundly "ignore" this, // based on its privileged knowledge of unstable rustc // internals; - g.buf.reserve(reservation_size(r)); let capacity = g.buf.capacity(); g.buf.set_len(capacity); r.initializer().initialize(&mut g.buf[g.len..]); @@ -404,9 +399,30 @@ where assert!(n <= buf.len()); g.len += n; } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), } + + if g.len == g.buf.capacity() && g.buf.capacity() == start_cap { + // The buffer might be an exact fit. Let's read into a probe buffer + // and see if it returns `Ok(0)`. If so, we've avoided an + // unnecessary doubling of the capacity. But if not, append the + // probe buffer to the primary buffer and let its capacity grow. + let mut probe = [0u8; 32]; + + loop { + match r.read(&mut probe) { + Ok(0) => return Ok(g.len - start_len), + Ok(n) => { + g.buf.extend_from_slice(&probe[..n]); + g.len += n; + break; + } + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e), + } + } + } } } @@ -854,8 +870,8 @@ pub trait Read { /// Transforms this `Read` instance to an [`Iterator`] over its bytes. /// - /// The returned type implements [`Iterator`] where the `Item` is - /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`. + /// The returned type implements [`Iterator`] where the [`Item`] is + /// [Result]<[u8], [io::Error]>. /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`] /// otherwise. EOF is mapped to returning [`None`] from this iterator. /// @@ -863,9 +879,10 @@ pub trait Read { /// /// [`File`]s implement `Read`: /// - /// [`File`]: crate::fs::File - /// [`Result`]: crate::result::Result - /// [`io::Error`]: self::Error + /// [`Item`]: Iterator::Item + /// [`File`]: crate::fs::File "fs::File" + /// [Result]: crate::result::Result "Result" + /// [io::Error]: self::Error "io::Error" /// /// ```no_run /// use std::io; @@ -2191,13 +2208,13 @@ pub trait BufRead: Read { /// `byte`. /// /// The iterator returned from this function will return instances of - /// [`io::Result`]`<`[`Vec`]`>`. Each vector returned will *not* have + /// [io::Result]<[Vec]\>. Each vector returned will *not* have /// the delimiter byte at the end. /// /// This function will yield errors whenever [`read_until`] would have /// also yielded an error. /// - /// [`io::Result`]: self::Result + /// [io::Result]: self::Result "io::Result" /// [`read_until`]: BufRead::read_until /// /// # Examples @@ -2228,10 +2245,10 @@ pub trait BufRead: Read { /// Returns an iterator over the lines of this reader. /// /// The iterator returned from this function will yield instances of - /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline + /// [io::Result]<[String]>. Each string returned will *not* have a newline /// byte (the `0xA` byte) or `CRLF` (`0xD`, `0xA` bytes) at the end. /// - /// [`io::Result`]: self::Result + /// [io::Result]: self::Result "io::Result" /// /// # Examples /// @@ -2583,13 +2600,6 @@ impl Read for Take { unsafe fn initializer(&self) -> Initializer { self.inner.initializer() } - - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - // Pass in a reservation_size closure that respects the current value - // of limit for each read. If we hit the read limit, this prevents the - // final zero-byte read from allocating again. - read_to_end_with_reservation(self, buf, |self_| cmp::min(self_.limit, 32) as usize) - } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 1beb72a9a5072..58b2d1d14c927 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -362,24 +362,12 @@ impl<'a> Read for ExampleSliceReader<'a> { fn test_read_to_end_capacity() -> io::Result<()> { let input = &b"foo"[..]; - // read_to_end() generally needs to over-allocate, both for efficiency - // and so that it can distinguish EOF. Assert that this is the case - // with this simple ExampleSliceReader struct, which uses the default - // implementation of read_to_end. Even though vec1 is allocated with - // exactly enough capacity for the read, read_to_end will allocate more - // space here. + // read_to_end() takes care not to over-allocate when a buffer is the + // exact size needed. let mut vec1 = Vec::with_capacity(input.len()); ExampleSliceReader { slice: input }.read_to_end(&mut vec1)?; assert_eq!(vec1.len(), input.len()); - assert!(vec1.capacity() > input.len(), "allocated more"); - - // However, std::io::Take includes an implementation of read_to_end - // that will not allocate when the limit has already been reached. In - // this case, vec2 never grows. - let mut vec2 = Vec::with_capacity(input.len()); - ExampleSliceReader { slice: input }.take(input.len() as u64).read_to_end(&mut vec2)?; - assert_eq!(vec2.len(), input.len()); - assert_eq!(vec2.capacity(), input.len(), "did not allocate more"); + assert_eq!(vec1.capacity(), input.len(), "did not allocate more"); Ok(()) } diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index a8812f197d82d..2f3520ae7a5a5 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -19,7 +19,7 @@ pub struct Empty; /// Constructs a new handle to an empty reader. /// -/// All reads from the returned reader will return [`Ok`]`(0)`. +/// All reads from the returned reader will return [Ok]\(0). /// /// # Examples /// diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f69baba9e733f..b16436a18f0af 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -195,6 +195,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] +#![cfg_attr(not(bootstrap), doc(cfg_hide(not(test), not(any(test, bootstrap)))))] // Don't link to std. We are std. #![no_std] #![warn(deprecated_in_future)] @@ -263,6 +264,7 @@ #![feature(custom_test_frameworks)] #![feature(decl_macro)] #![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] #![feature(doc_keyword)] #![feature(doc_masked)] #![feature(doc_notable_trait)] @@ -297,6 +299,8 @@ #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(min_specialization)] +#![feature(mixed_integer_ops)] +#![cfg_attr(not(bootstrap), feature(must_not_suspend))] #![feature(needs_panic_runtime)] #![feature(negative_impls)] #![feature(never_type)] @@ -330,7 +334,6 @@ #![feature(total_cmp)] #![feature(trace_macros)] #![feature(try_blocks)] -#![feature(try_reserve)] #![feature(try_reserve_kind)] #![feature(unboxed_closures)] #![feature(unwrap_infallible)] @@ -520,20 +523,20 @@ pub mod task { pub use alloc::task::*; } -// Platform-abstraction modules +// The runtime entry point and a few unstable public functions used by the +// compiler #[macro_use] -mod sys_common; +pub mod rt; + +// Platform-abstraction modules mod sys; +mod sys_common; pub mod alloc; // Private support modules mod panicking; -// The runtime entry point and a few unstable public functions used by the -// compiler -pub mod rt; - #[path = "../../backtrace/src/lib.rs"] #[allow(dead_code, unused_attributes)] mod backtrace_rs; diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index 43d930677fad3..f4ebcd53a25f7 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -765,15 +765,15 @@ impl hash::Hash for SocketAddrV6 { /// /// * [`SocketAddr`]: [`to_socket_addrs`] is the identity function. /// -/// * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`, -/// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: +/// * [`SocketAddrV4`], [`SocketAddrV6`], ([IpAddr], [u16]), +/// ([Ipv4Addr], [u16]), ([Ipv6Addr], [u16]): /// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// -/// * `(`[`&str`]`, `[`u16`]`)`: [`&str`] should be either a string representation +/// * (&[str], [u16]): &[str] should be either a string representation /// of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host /// name. [`u16`] is the port number. /// -/// * [`&str`]: the string should be either a string representation of a +/// * &[str]: the string should be either a string representation of a /// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like /// `:` pair where `` is a [`u16`] value. /// @@ -789,11 +789,10 @@ impl hash::Hash for SocketAddrV6 { /// Addresses returned by the operating system that are not IP addresses are /// silently ignored. /// -/// [`FromStr`]: crate::str::FromStr -/// [`&str`]: str -/// [`TcpStream`]: crate::net::TcpStream +/// [`FromStr`]: crate::str::FromStr "std::str::FromStr" +/// [`TcpStream`]: crate::net::TcpStream "net::TcpStream" /// [`to_socket_addrs`]: ToSocketAddrs::to_socket_addrs -/// [`UdpSocket`]: crate::net::UdpSocket +/// [`UdpSocket`]: crate::net::UdpSocket "net::UdpSocket" /// /// # Examples /// @@ -872,7 +871,7 @@ pub trait ToSocketAddrs { #[stable(feature = "rust1", since = "1.0.0")] type Iter: Iterator; - /// Converts this object to an iterator of resolved `SocketAddr`s. + /// Converts this object to an iterator of resolved [`SocketAddr`]s. /// /// The returned iterator might not actually yield any values depending on the /// outcome of any resolution performed. diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 9cf7ba9d57401..c05a32742ba1e 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -340,6 +340,30 @@ impl IpAddr { } } + /// Returns [`true`] if this address is in a range designated for benchmarking. + /// + /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and + /// [`Ipv6Addr::is_benchmarking()`] for more details. + /// + /// # Examples + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; + /// + /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true); + /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true); + /// ``` + #[unstable(feature = "ip", issue = "27709")] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + match self { + IpAddr::V4(ip) => ip.is_benchmarking(), + IpAddr::V6(ip) => ip.is_benchmarking(), + } + } + /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] /// otherwise. /// @@ -1449,6 +1473,28 @@ impl Ipv6Addr { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } + /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). + /// + /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`. + /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`. + /// + /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180 + /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752 + /// + /// ``` + /// #![feature(ip)] + /// + /// use std::net::Ipv6Addr; + /// + /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false); + /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true); + /// ``` + #[unstable(feature = "ip", issue = "27709")] + #[inline] + pub const fn is_benchmarking(&self) -> bool { + (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0) + } + /// Returns [`true`] if the address is a globally routable unicast address. /// /// The following return false: @@ -1589,7 +1635,7 @@ impl Ipv6Addr { /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d` /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`. /// - /// [IPv4 address]: Ipv4Addr + /// [`IPv4` address]: Ipv4Addr /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1 diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index dbfab9dde404e..babc854cd1d33 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -224,6 +224,7 @@ fn ip_properties() { let global: u8 = 1 << 2; let multicast: u8 = 1 << 3; let doc: u8 = 1 << 4; + let benchmarking: u8 = 1 << 5; if ($mask & unspec) == unspec { assert!(ip!($s).is_unspecified()); @@ -254,6 +255,12 @@ fn ip_properties() { } else { assert!(!ip!($s).is_documentation()); } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } }}; } @@ -262,6 +269,7 @@ fn ip_properties() { let global: u8 = 1 << 2; let multicast: u8 = 1 << 3; let doc: u8 = 1 << 4; + let benchmarking: u8 = 1 << 5; check!("0.0.0.0", unspec); check!("0.0.0.1"); @@ -280,9 +288,9 @@ fn ip_properties() { check!("239.255.255.255", global | multicast); check!("255.255.255.255"); // make sure benchmarking addresses are not global - check!("198.18.0.0"); - check!("198.18.54.2"); - check!("198.19.255.255"); + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); // make sure addresses reserved for protocol assignment are not global check!("192.0.0.0"); check!("192.0.0.255"); @@ -313,6 +321,7 @@ fn ip_properties() { check!("ff08::", multicast); check!("ff0e::", global | multicast); check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("2001:2::ac32:23ff:21", global | benchmarking); check!("102:304:506:708:90a:b0c:d0e:f10", global); } @@ -467,21 +476,22 @@ fn ipv6_properties() { assert_eq!(&ip!($s).octets(), octets); assert_eq!(Ipv6Addr::from(*octets), ip!($s)); - let unspecified: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let unique_local: u16 = 1 << 2; - let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_global: u16 = 1 << 7; - let documentation: u16 = 1 << 8; - let multicast_interface_local: u16 = 1 << 9; - let multicast_link_local: u16 = 1 << 10; - let multicast_realm_local: u16 = 1 << 11; - let multicast_admin_local: u16 = 1 << 12; - let multicast_site_local: u16 = 1 << 13; - let multicast_organization_local: u16 = 1 << 14; - let multicast_global: u16 = 1 << 15; - let multicast: u16 = multicast_interface_local + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let benchmarking: u32 = 1 << 16; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; + let multicast: u32 = multicast_interface_local | multicast_admin_local | multicast_global | multicast_link_local @@ -524,6 +534,11 @@ fn ipv6_properties() { } else { assert!(!ip!($s).is_documentation()); } + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } if ($mask & multicast) != 0 { assert!(ip!($s).multicast_scope().is_some()); assert!(ip!($s).is_multicast()); @@ -562,20 +577,21 @@ fn ipv6_properties() { } } - let unspecified: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let unique_local: u16 = 1 << 2; - let global: u16 = 1 << 3; - let unicast_link_local: u16 = 1 << 4; - let unicast_global: u16 = 1 << 7; - let documentation: u16 = 1 << 8; - let multicast_interface_local: u16 = 1 << 9; - let multicast_link_local: u16 = 1 << 10; - let multicast_realm_local: u16 = 1 << 11; - let multicast_admin_local: u16 = 1 << 12; - let multicast_site_local: u16 = 1 << 13; - let multicast_organization_local: u16 = 1 << 14; - let multicast_global: u16 = 1 << 15; + let unspecified: u32 = 1 << 0; + let loopback: u32 = 1 << 1; + let unique_local: u32 = 1 << 2; + let global: u32 = 1 << 3; + let unicast_link_local: u32 = 1 << 4; + let unicast_global: u32 = 1 << 7; + let documentation: u32 = 1 << 8; + let benchmarking: u32 = 1 << 16; + let multicast_interface_local: u32 = 1 << 9; + let multicast_link_local: u32 = 1 << 10; + let multicast_realm_local: u32 = 1 << 11; + let multicast_admin_local: u32 = 1 << 12; + let multicast_site_local: u32 = 1 << 13; + let multicast_organization_local: u32 = 1 << 14; + let multicast_global: u32 = 1 << 15; check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); @@ -671,6 +687,12 @@ fn ipv6_properties() { documentation ); + check!( + "2001:2::ac32:23ff:21", + &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21], + global | unicast_global | benchmarking + ); + check!( "102:304:506:708:90a:b0c:d0e:f10", &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], @@ -874,6 +896,9 @@ fn ipv6_const() { const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); assert!(!IS_DOCUMENTATION); + const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global(); assert!(!IS_UNICAST_GLOBAL); diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index d814e9b25ba9a..a0c77b648fe05 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -44,16 +44,16 @@ mod udp; pub enum Shutdown { /// The reading portion of the [`TcpStream`] should be shut down. /// - /// All currently blocked and future [reads] will return [`Ok`]`(0)`. + /// All currently blocked and future [reads] will return [Ok]\(0). /// - /// [reads]: crate::io::Read + /// [reads]: crate::io::Read "io::Read" #[stable(feature = "rust1", since = "1.0.0")] Read, /// The writing portion of the [`TcpStream`] should be shut down. /// /// All currently blocked and future [writes] will return an error. /// - /// [writes]: crate::io::Write + /// [writes]: crate::io::Write "io::Write" #[stable(feature = "rust1", since = "1.0.0")] Write, /// Both the reading and the writing portions of the [`TcpStream`] should be shut down. diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 069a5376a441c..90c30313dbbda 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -138,6 +138,8 @@ pub mod redox; #[cfg(target_os = "solaris")] pub mod solaris; +#[cfg(target_os = "solid_asp3")] +pub mod solid; #[cfg(target_os = "vxworks")] pub mod vxworks; diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 1e220ea30ab95..30eeac14b43f5 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -46,6 +46,7 @@ macro_rules! type_alias { } type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8; +#[doc(cfg(all()))] #[cfg(any( all( target_os = "linux", @@ -88,6 +89,7 @@ type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8; all(target_os = "fuchsia", target_arch = "aarch64") ))]} type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8; +#[doc(cfg(all()))] #[cfg(not(any( all( target_os = "linux", @@ -136,12 +138,16 @@ type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; } type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; } type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; } type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32; +#[doc(cfg(all()))] #[cfg(any(target_pointer_width = "32", windows))] } type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32; +#[doc(cfg(all()))] #[cfg(any(target_pointer_width = "32", windows))] } type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64; +#[doc(cfg(all()))] #[cfg(all(target_pointer_width = "64", not(windows)))] } type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64; +#[doc(cfg(all()))] #[cfg(all(target_pointer_width = "64", not(windows)))] } type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; } type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; } diff --git a/library/std/src/os/solid/ffi.rs b/library/std/src/os/solid/ffi.rs new file mode 100644 index 0000000000000..aaa2070a6abe9 --- /dev/null +++ b/library/std/src/os/solid/ffi.rs @@ -0,0 +1,41 @@ +//! SOLID-specific extension to the primitives in the `std::ffi` module +//! +//! # Examples +//! +//! ``` +//! use std::ffi::OsString; +//! use std::os::solid::ffi::OsStringExt; +//! +//! let bytes = b"foo".to_vec(); +//! +//! // OsStringExt::from_vec +//! let os_string = OsString::from_vec(bytes); +//! assert_eq!(os_string.to_str(), Some("foo")); +//! +//! // OsStringExt::into_vec +//! let bytes = os_string.into_vec(); +//! assert_eq!(bytes, b"foo"); +//! ``` +//! +//! ``` +//! use std::ffi::OsStr; +//! use std::os::solid::ffi::OsStrExt; +//! +//! let bytes = b"foo"; +//! +//! // OsStrExt::from_bytes +//! let os_str = OsStr::from_bytes(bytes); +//! assert_eq!(os_str.to_str(), Some("foo")); +//! +//! // OsStrExt::as_bytes +//! let bytes = os_str.as_bytes(); +//! assert_eq!(bytes, b"foo"); +//! ``` + +#![stable(feature = "rust1", since = "1.0.0")] + +#[path = "../unix/ffi/os_str.rs"] +mod os_str; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::os_str::{OsStrExt, OsStringExt}; diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs new file mode 100644 index 0000000000000..33cc5a015b5dc --- /dev/null +++ b/library/std/src/os/solid/io.rs @@ -0,0 +1,113 @@ +//! SOLID-specific extensions to general I/O primitives + +#![deny(unsafe_op_in_unsafe_fn)] +#![unstable(feature = "solid_ext", issue = "none")] + +use crate::net; +use crate::sys; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; + +/// Raw file descriptors. +pub type RawFd = i32; + +/// A trait to extract the raw SOLID Sockets file descriptor from an underlying +/// object. +pub trait AsRawFd { + /// Extracts the raw file descriptor. + /// + /// This method does **not** pass ownership of the raw file descriptor + /// to the caller. The descriptor is only guaranteed to be valid while + /// the original object has not yet been destroyed. + fn as_raw_fd(&self) -> RawFd; +} + +/// A trait to express the ability to construct an object from a raw file +/// descriptor. +pub trait FromRawFd { + /// Constructs a new instance of `Self` from the given raw file + /// descriptor. + /// + /// This function **consumes ownership** of the specified file + /// descriptor. The returned object will take responsibility for closing + /// it when the object goes out of scope. + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_fd(fd: RawFd) -> Self; +} + +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + fn into_raw_fd(self) -> RawFd; +} + +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl AsRawFd for RawFd { + #[inline] + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl IntoRawFd for RawFd { + #[inline] + fn into_raw_fd(self) -> RawFd { + self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl FromRawFd for RawFd { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} + +macro_rules! impl_as_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "rust1", since = "1.0.0")] + impl AsRawFd for net::$t { + #[inline] + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } + } + )*}; +} +impl_as_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_from_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "from_raw_os", since = "1.1.0")] + impl FromRawFd for net::$t { + #[inline] + unsafe fn from_raw_fd(fd: RawFd) -> net::$t { + let socket = sys::net::Socket::from_inner(fd); + net::$t::from_inner(sys_common::net::$t::from_inner(socket)) + } + } + )*}; +} +impl_from_raw_fd! { TcpStream TcpListener UdpSocket } + +macro_rules! impl_into_raw_fd { + ($($t:ident)*) => {$( + #[stable(feature = "into_raw_os", since = "1.4.0")] + impl IntoRawFd for net::$t { + #[inline] + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } + } + )*}; +} +impl_into_raw_fd! { TcpStream TcpListener UdpSocket } diff --git a/library/std/src/os/solid/mod.rs b/library/std/src/os/solid/mod.rs new file mode 100644 index 0000000000000..4328ba7c34022 --- /dev/null +++ b/library/std/src/os/solid/mod.rs @@ -0,0 +1,17 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod ffi; +pub mod io; + +/// A prelude for conveniently writing platform-specific code. +/// +/// Includes all extension traits, and some important type definitions. +#[stable(feature = "rust1", since = "1.0.0")] +pub mod prelude { + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::ffi::{OsStrExt, OsStringExt}; + #[doc(no_inline)] + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +} diff --git a/library/std/src/os/windows/raw.rs b/library/std/src/os/windows/raw.rs index 5014e008eb599..0ef3adade5c83 100644 --- a/library/std/src/os/windows/raw.rs +++ b/library/std/src/os/windows/raw.rs @@ -7,8 +7,10 @@ use crate::os::raw::c_void; #[stable(feature = "raw_ext", since = "1.1.0")] pub type HANDLE = *mut c_void; #[cfg(target_pointer_width = "32")] +#[doc(cfg(all()))] #[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u32; #[cfg(target_pointer_width = "64")] +#[doc(cfg(all()))] #[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u64; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 2a9c361c18afc..a45ecf6ea8c63 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1231,20 +1231,59 @@ impl PathBuf { let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false); // in the special case of `C:` on Windows, do *not* add a separator + let comps = self.components(); + + if comps.prefix_len() > 0 + && comps.prefix_len() == comps.path.len() + && comps.prefix.unwrap().is_drive() { - let comps = self.components(); - if comps.prefix_len() > 0 - && comps.prefix_len() == comps.path.len() - && comps.prefix.unwrap().is_drive() - { - need_sep = false - } + need_sep = false } // absolute `path` replaces `self` if path.is_absolute() || path.prefix().is_some() { self.as_mut_vec().truncate(0); + // verbatim paths need . and .. removed + } else if comps.prefix_verbatim() { + let mut buf: Vec<_> = comps.collect(); + for c in path.components() { + match c { + Component::RootDir => { + buf.truncate(1); + buf.push(c); + } + Component::CurDir => (), + Component::ParentDir => { + if let Some(Component::Normal(_)) = buf.last() { + buf.pop(); + } + } + _ => buf.push(c), + } + } + + let mut res = OsString::new(); + let mut need_sep = false; + + for c in buf { + if need_sep && c != Component::RootDir { + res.push(MAIN_SEP_STR); + } + res.push(c.as_os_str()); + + need_sep = match c { + Component::RootDir => false, + Component::Prefix(prefix) => { + !prefix.parsed.is_drive() && prefix.parsed.len() > 0 + } + _ => true, + } + } + + self.inner = res; + return; + // `path` has a root but no prefix, e.g., `\windows` (Windows only) } else if path.has_root() { let prefix_len = self.components().prefix_remaining(); @@ -2552,7 +2591,7 @@ impl Path { /// Returns an iterator over the entries within a directory. /// - /// The iterator will yield instances of [`io::Result`]`<`[`fs::DirEntry`]`>`. New + /// The iterator will yield instances of [io::Result]<[fs::DirEntry]>. New /// errors may be encountered after an iterator is initially constructed. /// /// This is an alias to [`fs::read_dir`]. diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index ce23cf6cd21b9..3973a6829d3d3 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1262,6 +1262,15 @@ pub fn test_push() { tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one + + tp!(r"\\?\C:\bar", "../foo", r"\\?\C:\foo"); + tp!(r"\\?\C:\bar", "../../foo", r"\\?\C:\foo"); + tp!(r"\\?\C:\", "../foo", r"\\?\C:\foo"); + tp!(r"\\?\C:", r"D:\foo/./", r"D:\foo/./"); + tp!(r"\\?\C:", r"\\?\D:\foo\.\", r"\\?\D:\foo\.\"); + tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo"); + tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo"); + tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo"); } } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c9b21fcf9c6d2..5c68400114d49 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1907,7 +1907,7 @@ impl Child { /// [platform-specific behavior]: #platform-specific-behavior #[stable(feature = "rust1", since = "1.0.0")] pub fn exit(code: i32) -> ! { - crate::sys_common::rt::cleanup(); + crate::rt::cleanup(); crate::sys::os::exit(code) } diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 893167e373015..4d72aff011684 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -13,11 +13,93 @@ issue = "none" )] #![doc(hidden)] +#![deny(unsafe_op_in_unsafe_fn)] +#![allow(unused_macros)] + +use crate::ffi::CString; // Re-export some of our utilities which are expected by other crates. pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count}; pub use core::panicking::panic_display; +use crate::sync::Once; +use crate::sys; +use crate::sys_common::thread_info; +use crate::thread::Thread; + +// Prints to the "panic output", depending on the platform this may be: +// - the standard error output +// - some dedicated platform specific output +// - nothing (so this macro is a no-op) +macro_rules! rtprintpanic { + ($($t:tt)*) => { + if let Some(mut out) = crate::sys::stdio::panic_output() { + let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); + } + } +} + +macro_rules! rtabort { + ($($t:tt)*) => { + { + rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*)); + crate::sys::abort_internal(); + } + } +} + +macro_rules! rtassert { + ($e:expr) => { + if !$e { + rtabort!(concat!("assertion failed: ", stringify!($e))); + } + }; +} + +macro_rules! rtunwrap { + ($ok:ident, $e:expr) => { + match $e { + $ok(v) => v, + ref err => { + let err = err.as_ref().map(drop); // map Ok/Some which might not be Debug + rtabort!(concat!("unwrap failed: ", stringify!($e), " = {:?}"), err) + } + } + }; +} + +// One-time runtime initialization. +// Runs before `main`. +// SAFETY: must be called only once during runtime initialization. +// NOTE: this is not guaranteed to run, for example when Rust code is called externally. +#[cfg_attr(test, allow(dead_code))] +unsafe fn init(argc: isize, argv: *const *const u8) { + unsafe { + sys::init(argc, argv); + + let main_guard = sys::thread::guard::init(); + // Next, set up the current Thread with the guard information we just + // created. Note that this isn't necessary in general for new threads, + // but we just do this to name the main thread and to give it correct + // info about the stack bounds. + let thread = Thread::new(Some(rtunwrap!(Ok, CString::new("main")))); + thread_info::set(main_guard, thread); + } +} + +// One-time runtime cleanup. +// Runs after `main` or at program exit. +// NOTE: this is not guaranteed to run, for example when the program aborts. +pub(crate) fn cleanup() { + static CLEANUP: Once = Once::new(); + CLEANUP.call_once(|| unsafe { + // Flush stdout and disable buffering. + crate::io::cleanup(); + // SAFETY: Only called once during runtime cleanup. + sys::cleanup(); + }); +} + // To reduce the generated code of the new `lang_start`, this function is doing // the real work. #[cfg(not(test))] @@ -26,7 +108,7 @@ fn lang_start_internal( argc: isize, argv: *const *const u8, ) -> Result { - use crate::{mem, panic, sys, sys_common}; + use crate::{mem, panic}; let rt_abort = move |e| { mem::forget(e); rtabort!("initialization or cleanup bug"); @@ -42,14 +124,14 @@ fn lang_start_internal( // prevent libstd from accidentally introducing a panic to these functions. Another is from // user code from `main` or, more nefariously, as described in e.g. issue #86030. // SAFETY: Only called once during runtime initialization. - panic::catch_unwind(move || unsafe { sys_common::rt::init(argc, argv) }).map_err(rt_abort)?; + panic::catch_unwind(move || unsafe { init(argc, argv) }).map_err(rt_abort)?; let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize) .map_err(move |e| { mem::forget(e); rtprintpanic!("drop of the panic payload panicked"); sys::abort_internal() }); - panic::catch_unwind(sys_common::rt::cleanup).map_err(rt_abort)?; + panic::catch_unwind(cleanup).map_err(rt_abort)?; ret_code } diff --git a/library/std/src/sync/mpsc/shared.rs b/library/std/src/sync/mpsc/shared.rs index 0c32e636a5633..8487a5f8b50d3 100644 --- a/library/std/src/sync/mpsc/shared.rs +++ b/library/std/src/sync/mpsc/shared.rs @@ -248,7 +248,11 @@ impl Packet { // Returns true if blocking should proceed. fn decrement(&self, token: SignalToken) -> StartResult { unsafe { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!( + self.to_wake.load(Ordering::SeqCst), + 0, + "This is a known bug in the Rust standard library. See https://github.com/rust-lang/rust/issues/39364" + ); let ptr = token.cast_to_usize(); self.to_wake.store(ptr, Ordering::SeqCst); diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index e1d6324c17e33..57f1dcca30e0a 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -162,7 +162,7 @@ use crate::sys_common::mutex as sys; /// assert_eq!(*res_mutex.lock().unwrap(), 800); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")] pub struct Mutex { inner: sys::MovableMutex, poison: poison::Flag, @@ -188,6 +188,12 @@ unsafe impl Sync for Mutex {} /// [`lock`]: Mutex::lock /// [`try_lock`]: Mutex::try_lock #[must_use = "if unused the Mutex will immediately unlock"] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a MutexGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`" +)] #[stable(feature = "rust1", since = "1.0.0")] pub struct MutexGuard<'a, T: ?Sized + 'a> { lock: &'a Mutex, diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index e50d62d817376..2f4395ceefd13 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -95,6 +95,12 @@ unsafe impl Sync for RwLock {} /// [`read`]: RwLock::read /// [`try_read`]: RwLock::try_read #[must_use = "if unused the RwLock will immediately unlock"] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a RwLockReadGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`" +)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { lock: &'a RwLock, @@ -115,6 +121,12 @@ unsafe impl Sync for RwLockReadGuard<'_, T> {} /// [`write`]: RwLock::write /// [`try_write`]: RwLock::try_write #[must_use = "if unused the RwLock will immediately unlock"] +#[cfg_attr( + not(bootstrap), + must_not_suspend = "holding a RwLockWriteGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Future's to not implement `Send`" +)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { lock: &'a RwLock, diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs index 8be25f84999d2..81b21fbbb1656 100644 --- a/library/std/src/sys/hermit/thread.rs +++ b/library/std/src/sys/hermit/thread.rs @@ -97,7 +97,7 @@ impl Thread { } } -pub fn available_concurrency() -> io::Result { +pub fn available_parallelism() -> io::Result { unsupported() } diff --git a/library/std/src/sys/itron/abi.rs b/library/std/src/sys/itron/abi.rs new file mode 100644 index 0000000000000..f99ee4fa897ea --- /dev/null +++ b/library/std/src/sys/itron/abi.rs @@ -0,0 +1,155 @@ +//! ABI for μITRON derivatives +pub type int_t = crate::os::raw::c_int; +pub type uint_t = crate::os::raw::c_uint; +pub type bool_t = int_t; + +/// Kernel object ID +pub type ID = int_t; + +/// The current task. +pub const TSK_SELF: ID = 0; + +/// Relative time +pub type RELTIM = u32; + +/// Timeout (a valid `RELTIM` value or `TMO_FEVR`) +pub type TMO = u32; + +/// The infinite timeout value +pub const TMO_FEVR: TMO = TMO::MAX; + +/// The maximum valid value of `RELTIM` +pub const TMAX_RELTIM: RELTIM = 4_000_000_000; + +/// System time +pub type SYSTIM = u64; + +/// Error code type +pub type ER = int_t; + +/// Error code type, `ID` on success +pub type ER_ID = int_t; + +/// Task or interrupt priority +pub type PRI = int_t; + +/// The special value of `PRI` representing the current task's priority. +pub const TPRI_SELF: PRI = 0; + +/// Object attributes +pub type ATR = uint_t; + +/// Use the priority inheritance protocol +#[cfg(target_os = "solid_asp3")] +pub const TA_INHERIT: ATR = 0x02; + +/// Activate the task on creation +pub const TA_ACT: ATR = 0x01; + +/// The maximum count of a semaphore +pub const TMAX_MAXSEM: uint_t = uint_t::MAX; + +/// Callback parameter +pub type EXINF = isize; + +/// Task entrypoint +pub type TASK = Option; + +// Error codes +pub const E_OK: ER = 0; +pub const E_SYS: ER = -5; +pub const E_NOSPT: ER = -9; +pub const E_RSFN: ER = -10; +pub const E_RSATR: ER = -11; +pub const E_PAR: ER = -17; +pub const E_ID: ER = -18; +pub const E_CTX: ER = -25; +pub const E_MACV: ER = -26; +pub const E_OACV: ER = -27; +pub const E_ILUSE: ER = -28; +pub const E_NOMEM: ER = -33; +pub const E_NOID: ER = -34; +pub const E_NORES: ER = -35; +pub const E_OBJ: ER = -41; +pub const E_NOEXS: ER = -42; +pub const E_QOVR: ER = -43; +pub const E_RLWAI: ER = -49; +pub const E_TMOUT: ER = -50; +pub const E_DLT: ER = -51; +pub const E_CLS: ER = -52; +pub const E_RASTER: ER = -53; +pub const E_WBLK: ER = -57; +pub const E_BOVR: ER = -58; +pub const E_COMM: ER = -65; + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CSEM { + pub sematr: ATR, + pub isemcnt: uint_t, + pub maxsem: uint_t, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CMTX { + pub mtxatr: ATR, + pub ceilpri: PRI, +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub struct T_CTSK { + pub tskatr: ATR, + pub exinf: EXINF, + pub task: TASK, + pub itskpri: PRI, + pub stksz: usize, + pub stk: *mut u8, +} + +extern "C" { + #[link_name = "__asp3_acre_tsk"] + pub fn acre_tsk(pk_ctsk: *const T_CTSK) -> ER_ID; + #[link_name = "__asp3_get_tid"] + pub fn get_tid(p_tskid: *mut ID) -> ER; + #[link_name = "__asp3_dly_tsk"] + pub fn dly_tsk(dlytim: RELTIM) -> ER; + #[link_name = "__asp3_ter_tsk"] + pub fn ter_tsk(tskid: ID) -> ER; + #[link_name = "__asp3_del_tsk"] + pub fn del_tsk(tskid: ID) -> ER; + #[link_name = "__asp3_get_pri"] + pub fn get_pri(tskid: ID, p_tskpri: *mut PRI) -> ER; + #[link_name = "__asp3_rot_rdq"] + pub fn rot_rdq(tskpri: PRI) -> ER; + #[link_name = "__asp3_slp_tsk"] + pub fn slp_tsk() -> ER; + #[link_name = "__asp3_tslp_tsk"] + pub fn tslp_tsk(tmout: TMO) -> ER; + #[link_name = "__asp3_wup_tsk"] + pub fn wup_tsk(tskid: ID) -> ER; + #[link_name = "__asp3_unl_cpu"] + pub fn unl_cpu() -> ER; + #[link_name = "__asp3_dis_dsp"] + pub fn dis_dsp() -> ER; + #[link_name = "__asp3_ena_dsp"] + pub fn ena_dsp() -> ER; + #[link_name = "__asp3_sns_dsp"] + pub fn sns_dsp() -> bool_t; + #[link_name = "__asp3_get_tim"] + pub fn get_tim(p_systim: *mut SYSTIM) -> ER; + #[link_name = "__asp3_acre_mtx"] + pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID; + #[link_name = "__asp3_del_mtx"] + pub fn del_mtx(tskid: ID) -> ER; + #[link_name = "__asp3_loc_mtx"] + pub fn loc_mtx(mtxid: ID) -> ER; + #[link_name = "__asp3_ploc_mtx"] + pub fn ploc_mtx(mtxid: ID) -> ER; + #[link_name = "__asp3_tloc_mtx"] + pub fn tloc_mtx(mtxid: ID, tmout: TMO) -> ER; + #[link_name = "__asp3_unl_mtx"] + pub fn unl_mtx(mtxid: ID) -> ER; + pub fn exd_tsk() -> ER; +} diff --git a/library/std/src/sys/itron/condvar.rs b/library/std/src/sys/itron/condvar.rs new file mode 100644 index 0000000000000..dac4b8abfc47f --- /dev/null +++ b/library/std/src/sys/itron/condvar.rs @@ -0,0 +1,294 @@ +//! POSIX conditional variable implementation based on user-space wait queues. +use super::{abi, error::expect_success_aborting, spin::SpinMutex, task, time::with_tmos_strong}; +use crate::{mem::replace, ptr::NonNull, sys::mutex::Mutex, time::Duration}; + +// The implementation is inspired by the queue-based implementation shown in +// Andrew D. Birrell's paper "Implementing Condition Variables with Semaphores" + +pub struct Condvar { + waiters: SpinMutex, +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +pub type MovableCondvar = Condvar; + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) } + } + + pub unsafe fn init(&mut self) {} + + pub unsafe fn notify_one(&self) { + self.waiters.with_locked(|waiters| { + if let Some(task) = waiters.pop_front() { + // Unpark the task + match unsafe { abi::wup_tsk(task) } { + // The task already has a token. + abi::E_QOVR => {} + // Can't undo the effect; abort the program on failure + er => { + expect_success_aborting(er, &"wup_tsk"); + } + } + } + }); + } + + pub unsafe fn notify_all(&self) { + self.waiters.with_locked(|waiters| { + while let Some(task) = waiters.pop_front() { + // Unpark the task + match unsafe { abi::wup_tsk(task) } { + // The task already has a token. + abi::E_QOVR => {} + // Can't undo the effect; abort the program on failure + er => { + expect_success_aborting(er, &"wup_tsk"); + } + } + } + }); + } + + pub unsafe fn wait(&self, mutex: &Mutex) { + // Construct `Waiter`. + let mut waiter = waiter_queue::Waiter::new(); + let waiter = NonNull::from(&mut waiter); + + self.waiters.with_locked(|waiters| unsafe { + waiters.insert(waiter); + }); + + unsafe { mutex.unlock() }; + + // Wait until `waiter` is removed from the queue + loop { + // Park the current task + expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk"); + + if !self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) { + break; + } + } + + unsafe { mutex.lock() }; + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + // Construct and pin `Waiter` + let mut waiter = waiter_queue::Waiter::new(); + let waiter = NonNull::from(&mut waiter); + + self.waiters.with_locked(|waiters| unsafe { + waiters.insert(waiter); + }); + + unsafe { mutex.unlock() }; + + // Park the current task and do not wake up until the timeout elapses + // or the task gets woken up by `notify_*` + match with_tmos_strong(dur, |tmo| { + let er = unsafe { abi::tslp_tsk(tmo) }; + if er == 0 { + // We were unparked. Are we really dequeued? + if self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) { + // No we are not. Continue waiting. + return abi::E_TMOUT; + } + } + er + }) { + abi::E_TMOUT => {} + er => { + expect_success_aborting(er, &"tslp_tsk"); + } + } + + // Remove `waiter` from `self.waiters`. If `waiter` is still in + // `waiters`, it means we woke up because of a timeout. Otherwise, + // we woke up because of `notify_*`. + let success = self.waiters.with_locked(|waiters| unsafe { !waiters.remove(waiter) }); + + unsafe { mutex.lock() }; + success + } + + pub unsafe fn destroy(&self) {} +} + +mod waiter_queue { + use super::*; + + pub struct WaiterQueue { + head: Option, + } + + #[derive(Copy, Clone)] + struct ListHead { + first: NonNull, + last: NonNull, + } + + unsafe impl Send for ListHead {} + unsafe impl Sync for ListHead {} + + pub struct Waiter { + // These fields are only accessed through `&[mut] WaiterQueue`. + /// The waiting task's ID. Will be zeroed when the task is woken up + /// and removed from a queue. + task: abi::ID, + priority: abi::PRI, + prev: Option>, + next: Option>, + } + + unsafe impl Send for Waiter {} + unsafe impl Sync for Waiter {} + + impl Waiter { + #[inline] + pub fn new() -> Self { + let task = task::current_task_id(); + let priority = task::task_priority(abi::TSK_SELF); + + // Zeroness of `Waiter::task` indicates whether the `Waiter` is + // linked to a queue or not. This invariant is important for + // the correctness. + debug_assert_ne!(task, 0); + + Self { task, priority, prev: None, next: None } + } + } + + impl WaiterQueue { + #[inline] + pub const fn new() -> Self { + Self { head: None } + } + + /// # Safety + /// + /// - The caller must own `*waiter_ptr`. The caller will lose the + /// ownership until `*waiter_ptr` is removed from `self`. + /// + /// - `*waiter_ptr` must be valid until it's removed from the queue. + /// + /// - `*waiter_ptr` must not have been previously inserted to a `WaiterQueue`. + /// + pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull) { + unsafe { + let waiter = waiter_ptr.as_mut(); + + debug_assert!(waiter.prev.is_none()); + debug_assert!(waiter.next.is_none()); + + if let Some(head) = &mut self.head { + // Find the insertion position and insert `waiter` + let insert_after = { + let mut cursor = head.last; + loop { + if waiter.priority <= cursor.as_ref().priority { + // `cursor` and all previous waiters have the same or higher + // priority than `current_task_priority`. Insert the new + // waiter right after `cursor`. + break Some(cursor); + } + cursor = if let Some(prev) = cursor.as_ref().prev { + prev + } else { + break None; + }; + } + }; + + if let Some(mut insert_after) = insert_after { + // Insert `waiter` after `insert_after` + let insert_before = insert_after.as_ref().prev; + + waiter.prev = Some(insert_after); + insert_after.as_mut().next = Some(waiter_ptr); + + waiter.next = insert_before; + if let Some(mut insert_before) = insert_before { + insert_before.as_mut().prev = Some(waiter_ptr); + } + } else { + // Insert `waiter` to the front + waiter.next = Some(head.first); + head.first.as_mut().prev = Some(waiter_ptr); + head.first = waiter_ptr; + } + } else { + // `waiter` is the only element + self.head = Some(ListHead { first: waiter_ptr, last: waiter_ptr }); + } + } + } + + /// Given a `Waiter` that was previously inserted to `self`, remove + /// it from `self` if it's still there. + #[inline] + pub unsafe fn remove(&mut self, mut waiter_ptr: NonNull) -> bool { + unsafe { + let waiter = waiter_ptr.as_mut(); + if waiter.task != 0 { + let head = self.head.as_mut().unwrap(); + + match (waiter.prev, waiter.next) { + (Some(mut prev), Some(mut next)) => { + prev.as_mut().next = Some(next); + next.as_mut().next = Some(prev); + } + (None, Some(mut next)) => { + head.first = next; + next.as_mut().next = None; + } + (Some(mut prev), None) => { + prev.as_mut().next = None; + head.last = prev; + } + (None, None) => { + self.head = None; + } + } + + waiter.task = 0; + + true + } else { + false + } + } + } + + /// Given a `Waiter` that was previously inserted to `self`, return a + /// flag indicating whether it's still in `self`. + #[inline] + pub unsafe fn is_queued(&self, waiter: NonNull) -> bool { + unsafe { waiter.as_ref().task != 0 } + } + + pub fn pop_front(&mut self) -> Option { + unsafe { + let head = self.head.as_mut()?; + let waiter = head.first.as_mut(); + + // Get the ID + let id = replace(&mut waiter.task, 0); + + // Unlink the waiter + if let Some(mut next) = waiter.next { + head.first = next; + next.as_mut().prev = None; + } else { + self.head = None; + } + + Some(id) + } + } + } +} diff --git a/library/std/src/sys/itron/error.rs b/library/std/src/sys/itron/error.rs new file mode 100644 index 0000000000000..830c60d329e4e --- /dev/null +++ b/library/std/src/sys/itron/error.rs @@ -0,0 +1,159 @@ +use crate::{fmt, io::ErrorKind}; + +use super::abi; + +/// Wraps a μITRON error code. +#[derive(Debug, Copy, Clone)] +pub struct ItronError { + er: abi::ER, +} + +impl ItronError { + /// Construct `ItronError` from the specified error code. Returns `None` if the + /// error code does not represent a failure or warning. + #[inline] + pub fn new(er: abi::ER) -> Option { + if er < 0 { Some(Self { er }) } else { None } + } + + /// Returns `Ok(er)` if `er` represents a success or `Err(_)` otherwise. + #[inline] + pub fn err_if_negative(er: abi::ER) -> Result { + if let Some(error) = Self::new(er) { Err(error) } else { Ok(er) } + } + + /// Get the raw error code. + #[inline] + pub fn as_raw(&self) -> abi::ER { + self.er + } +} + +impl fmt::Display for ItronError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Allow the platforms to extend `error_name` + if let Some(name) = crate::sys::error::error_name(self.er) { + write!(f, "{} ({})", name, self.er) + } else { + write!(f, "{}", self.er) + } + } +} + +/// Describe the specified μITRON error code. Returns `None` if it's an +/// undefined error code. +pub fn error_name(er: abi::ER) -> Option<&'static str> { + match er { + // Success + er if er >= 0 => None, + + // μITRON 4.0 + abi::E_SYS => Some("system error"), + abi::E_NOSPT => Some("unsupported function"), + abi::E_RSFN => Some("reserved function code"), + abi::E_RSATR => Some("reserved attribute"), + abi::E_PAR => Some("parameter error"), + abi::E_ID => Some("invalid ID number"), + abi::E_CTX => Some("context error"), + abi::E_MACV => Some("memory access violation"), + abi::E_OACV => Some("object access violation"), + abi::E_ILUSE => Some("illegal service call use"), + abi::E_NOMEM => Some("insufficient memory"), + abi::E_NOID => Some("no ID number available"), + abi::E_OBJ => Some("object state error"), + abi::E_NOEXS => Some("non-existent object"), + abi::E_QOVR => Some("queue overflow"), + abi::E_RLWAI => Some("forced release from waiting"), + abi::E_TMOUT => Some("polling failure or timeout"), + abi::E_DLT => Some("waiting object deleted"), + abi::E_CLS => Some("waiting object state changed"), + abi::E_WBLK => Some("non-blocking code accepted"), + abi::E_BOVR => Some("buffer overflow"), + + // The TOPPERS third generation kernels + abi::E_NORES => Some("insufficient system resources"), + abi::E_RASTER => Some("termination request raised"), + abi::E_COMM => Some("communication failure"), + + _ => None, + } +} + +pub fn decode_error_kind(er: abi::ER) -> ErrorKind { + match er { + // Success + er if er >= 0 => ErrorKind::Uncategorized, + + // μITRON 4.0 + // abi::E_SYS + abi::E_NOSPT => ErrorKind::Unsupported, // Some("unsupported function"), + abi::E_RSFN => ErrorKind::InvalidInput, // Some("reserved function code"), + abi::E_RSATR => ErrorKind::InvalidInput, // Some("reserved attribute"), + abi::E_PAR => ErrorKind::InvalidInput, // Some("parameter error"), + abi::E_ID => ErrorKind::NotFound, // Some("invalid ID number"), + // abi::E_CTX + abi::E_MACV => ErrorKind::PermissionDenied, // Some("memory access violation"), + abi::E_OACV => ErrorKind::PermissionDenied, // Some("object access violation"), + // abi::E_ILUSE + abi::E_NOMEM => ErrorKind::OutOfMemory, // Some("insufficient memory"), + abi::E_NOID => ErrorKind::OutOfMemory, // Some("no ID number available"), + // abi::E_OBJ + abi::E_NOEXS => ErrorKind::NotFound, // Some("non-existent object"), + // abi::E_QOVR + abi::E_RLWAI => ErrorKind::Interrupted, // Some("forced release from waiting"), + abi::E_TMOUT => ErrorKind::TimedOut, // Some("polling failure or timeout"), + // abi::E_DLT + // abi::E_CLS + // abi::E_WBLK + // abi::E_BOVR + + // The TOPPERS third generation kernels + abi::E_NORES => ErrorKind::OutOfMemory, // Some("insufficient system resources"), + // abi::E_RASTER + // abi::E_COMM + _ => ErrorKind::Uncategorized, + } +} + +/// Similar to `ItronError::err_if_negative(er).expect()` except that, while +/// panicking, it prints the message to `panic_output` and aborts the program +/// instead. This ensures the error message is not obscured by double +/// panicking. +/// +/// This is useful for diagnosing creation failures of synchronization +/// primitives that are used by `std`'s internal mechanisms. Such failures +/// are common when the system is mis-configured to provide a too-small pool for +/// kernel objects. +#[inline] +pub fn expect_success(er: abi::ER, msg: &&str) -> abi::ER { + match ItronError::err_if_negative(er) { + Ok(x) => x, + Err(e) => fail(e, msg), + } +} + +/// Similar to `ItronError::err_if_negative(er).expect()` but aborts instead. +/// +/// Use this where panicking is not allowed or the effect of the failure +/// would be persistent. +#[inline] +pub fn expect_success_aborting(er: abi::ER, msg: &&str) -> abi::ER { + match ItronError::err_if_negative(er) { + Ok(x) => x, + Err(e) => fail_aborting(e, msg), + } +} + +#[cold] +pub fn fail(e: impl fmt::Display, msg: &&str) -> ! { + if crate::thread::panicking() { + fail_aborting(e, msg) + } else { + panic!("{} failed: {}", *msg, e) + } +} + +#[cold] +pub fn fail_aborting(e: impl fmt::Display, msg: &&str) -> ! { + rtabort!("{} failed: {}", *msg, e) +} diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs new file mode 100644 index 0000000000000..e01f595ac54ab --- /dev/null +++ b/library/std/src/sys/itron/mutex.rs @@ -0,0 +1,183 @@ +//! Mutex implementation backed by μITRON mutexes. Assumes `acre_mtx` and +//! `TA_INHERIT` are available. +use super::{ + abi, + error::{expect_success, expect_success_aborting, fail, ItronError}, + spin::SpinIdOnceCell, +}; +use crate::cell::UnsafeCell; + +pub struct Mutex { + /// The ID of the underlying mutex object + mtx: SpinIdOnceCell<()>, +} + +pub type MovableMutex = Mutex; + +/// Create a mutex object. This function never panics. +fn new_mtx() -> Result { + ItronError::err_if_negative(unsafe { + abi::acre_mtx(&abi::T_CMTX { + // Priority inheritance mutex + mtxatr: abi::TA_INHERIT, + // Unused + ceilpri: 0, + }) + }) +} + +impl Mutex { + pub const fn new() -> Mutex { + Mutex { mtx: SpinIdOnceCell::new() } + } + + pub unsafe fn init(&mut self) { + // Initialize `self.mtx` eagerly + let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx")); + unsafe { self.mtx.set_unchecked((id, ())) }; + } + + /// Get the inner mutex's ID, which is lazily created. + fn raw(&self) -> abi::ID { + match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) { + Ok((id, ())) => id, + Err(e) => fail(e, &"acre_mtx"), + } + } + + pub unsafe fn lock(&self) { + let mtx = self.raw(); + expect_success(unsafe { abi::loc_mtx(mtx) }, &"loc_mtx"); + } + + pub unsafe fn unlock(&self) { + let mtx = unsafe { self.mtx.get_unchecked().0 }; + expect_success_aborting(unsafe { abi::unl_mtx(mtx) }, &"unl_mtx"); + } + + pub unsafe fn try_lock(&self) -> bool { + let mtx = self.raw(); + match unsafe { abi::ploc_mtx(mtx) } { + abi::E_TMOUT => false, + er => { + expect_success(er, &"ploc_mtx"); + true + } + } + } + + pub unsafe fn destroy(&self) { + if let Some(mtx) = self.mtx.get().map(|x| x.0) { + expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx"); + } + } +} + +pub(super) struct MutexGuard<'a>(&'a Mutex); + +impl<'a> MutexGuard<'a> { + #[inline] + pub(super) fn lock(x: &'a Mutex) -> Self { + unsafe { x.lock() }; + Self(x) + } +} + +impl Drop for MutexGuard<'_> { + #[inline] + fn drop(&mut self) { + unsafe { self.0.unlock() }; + } +} + +// All empty stubs because this platform does not yet support threads, so lock +// acquisition always succeeds. +pub struct ReentrantMutex { + /// The ID of the underlying mutex object + mtx: abi::ID, + /// The lock count. + count: UnsafeCell, +} + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { + ReentrantMutex { mtx: 0, count: UnsafeCell::new(0) } + } + + pub unsafe fn init(&mut self) { + self.mtx = expect_success( + unsafe { + abi::acre_mtx(&abi::T_CMTX { + // Priority inheritance mutex + mtxatr: abi::TA_INHERIT, + // Unused + ceilpri: 0, + }) + }, + &"acre_mtx", + ); + } + + pub unsafe fn lock(&self) { + match unsafe { abi::loc_mtx(self.mtx) } { + abi::E_OBJ => { + // Recursive lock + unsafe { + let count = &mut *self.count.get(); + if let Some(new_count) = count.checked_add(1) { + *count = new_count; + } else { + // counter overflow + rtabort!("lock count overflow"); + } + } + } + er => { + expect_success(er, &"loc_mtx"); + } + } + } + + pub unsafe fn unlock(&self) { + unsafe { + let count = &mut *self.count.get(); + if *count > 0 { + *count -= 1; + return; + } + } + + expect_success_aborting(unsafe { abi::unl_mtx(self.mtx) }, &"unl_mtx"); + } + + pub unsafe fn try_lock(&self) -> bool { + let er = unsafe { abi::ploc_mtx(self.mtx) }; + if er == abi::E_OBJ { + // Recursive lock + unsafe { + let count = &mut *self.count.get(); + if let Some(new_count) = count.checked_add(1) { + *count = new_count; + } else { + // counter overflow + rtabort!("lock count overflow"); + } + } + true + } else if er == abi::E_TMOUT { + // Locked by another thread + false + } else { + expect_success(er, &"ploc_mtx"); + // Top-level lock by the current thread + true + } + } + + pub unsafe fn destroy(&self) { + expect_success_aborting(unsafe { abi::del_mtx(self.mtx) }, &"del_mtx"); + } +} diff --git a/library/std/src/sys/itron/spin.rs b/library/std/src/sys/itron/spin.rs new file mode 100644 index 0000000000000..d0149d1f037db --- /dev/null +++ b/library/std/src/sys/itron/spin.rs @@ -0,0 +1,164 @@ +use super::abi; +use crate::{ + cell::UnsafeCell, + convert::TryFrom, + mem::MaybeUninit, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, +}; + +/// A mutex implemented by `dis_dsp` (for intra-core synchronization) and a +/// spinlock (for inter-core synchronization). +pub struct SpinMutex { + locked: AtomicBool, + data: UnsafeCell, +} + +impl SpinMutex { + #[inline] + pub const fn new(x: T) -> Self { + Self { locked: AtomicBool::new(false), data: UnsafeCell::new(x) } + } + + /// Acquire a lock. + #[inline] + pub fn with_locked(&self, f: impl FnOnce(&mut T) -> R) -> R { + struct SpinMutexGuard<'a>(&'a AtomicBool); + + impl Drop for SpinMutexGuard<'_> { + #[inline] + fn drop(&mut self) { + self.0.store(false, Ordering::Release); + unsafe { abi::ena_dsp() }; + } + } + + let _guard; + if unsafe { abi::sns_dsp() } == 0 { + let er = unsafe { abi::dis_dsp() }; + debug_assert!(er >= 0); + + // Wait until the current processor acquires a lock. + while self.locked.swap(true, Ordering::Acquire) {} + + _guard = SpinMutexGuard(&self.locked); + } + + f(unsafe { &mut *self.data.get() }) + } +} + +/// `OnceCell<(abi::ID, T)>` implemented by `dis_dsp` (for intra-core +/// synchronization) and a spinlock (for inter-core synchronization). +/// +/// It's assumed that `0` is not a valid ID, and all kernel +/// object IDs fall into range `1..=usize::MAX`. +pub struct SpinIdOnceCell { + id: AtomicUsize, + spin: SpinMutex<()>, + extra: UnsafeCell>, +} + +const ID_UNINIT: usize = 0; + +impl SpinIdOnceCell { + #[inline] + pub const fn new() -> Self { + Self { + id: AtomicUsize::new(ID_UNINIT), + extra: UnsafeCell::new(MaybeUninit::uninit()), + spin: SpinMutex::new(()), + } + } + + #[inline] + pub fn get(&self) -> Option<(abi::ID, &T)> { + match self.id.load(Ordering::Acquire) { + ID_UNINIT => None, + id => Some((id as abi::ID, unsafe { (&*self.extra.get()).assume_init_ref() })), + } + } + + #[inline] + pub fn get_mut(&mut self) -> Option<(abi::ID, &mut T)> { + match *self.id.get_mut() { + ID_UNINIT => None, + id => Some((id as abi::ID, unsafe { (&mut *self.extra.get()).assume_init_mut() })), + } + } + + #[inline] + pub unsafe fn get_unchecked(&self) -> (abi::ID, &T) { + (self.id.load(Ordering::Acquire) as abi::ID, unsafe { + (&*self.extra.get()).assume_init_ref() + }) + } + + /// Assign the content without checking if it's already initialized or + /// being initialized. + pub unsafe fn set_unchecked(&self, (id, extra): (abi::ID, T)) { + debug_assert!(self.get().is_none()); + + // Assumption: A positive `abi::ID` fits in `usize`. + debug_assert!(id >= 0); + debug_assert!(usize::try_from(id).is_ok()); + let id = id as usize; + + unsafe { *self.extra.get() = MaybeUninit::new(extra) }; + self.id.store(id, Ordering::Release); + } + + /// Gets the contents of the cell, initializing it with `f` if + /// the cell was empty. If the cell was empty and `f` failed, an + /// error is returned. + /// + /// Warning: `f` must not perform a blocking operation, which + /// includes panicking. + #[inline] + pub fn get_or_try_init(&self, f: F) -> Result<(abi::ID, &T), E> + where + F: FnOnce() -> Result<(abi::ID, T), E>, + { + // Fast path + if let Some(x) = self.get() { + return Ok(x); + } + + self.initialize(f)?; + + debug_assert!(self.get().is_some()); + + // Safety: The inner value has been initialized + Ok(unsafe { self.get_unchecked() }) + } + + fn initialize(&self, f: F) -> Result<(), E> + where + F: FnOnce() -> Result<(abi::ID, T), E>, + { + self.spin.with_locked(|_| { + if self.id.load(Ordering::Relaxed) == ID_UNINIT { + let (initialized_id, initialized_extra) = f()?; + + // Assumption: A positive `abi::ID` fits in `usize`. + debug_assert!(initialized_id >= 0); + debug_assert!(usize::try_from(initialized_id).is_ok()); + let initialized_id = initialized_id as usize; + + // Store the initialized contents. Use the release ordering to + // make sure the write is visible to the callers of `get`. + unsafe { *self.extra.get() = MaybeUninit::new(initialized_extra) }; + self.id.store(initialized_id, Ordering::Release); + } + Ok(()) + }) + } +} + +impl Drop for SpinIdOnceCell { + #[inline] + fn drop(&mut self) { + if self.get_mut().is_some() { + unsafe { (&mut *self.extra.get()).assume_init_drop() }; + } + } +} diff --git a/library/std/src/sys/itron/task.rs b/library/std/src/sys/itron/task.rs new file mode 100644 index 0000000000000..94beb50a2541b --- /dev/null +++ b/library/std/src/sys/itron/task.rs @@ -0,0 +1,44 @@ +use super::{ + abi, + error::{fail, fail_aborting, ItronError}, +}; + +use crate::mem::MaybeUninit; + +/// Get the ID of the task in Running state. Panics on failure. +#[inline] +pub fn current_task_id() -> abi::ID { + try_current_task_id().unwrap_or_else(|e| fail(e, &"get_tid")) +} + +/// Get the ID of the task in Running state. Aborts on failure. +#[inline] +pub fn current_task_id_aborting() -> abi::ID { + try_current_task_id().unwrap_or_else(|e| fail_aborting(e, &"get_tid")) +} + +/// Get the ID of the task in Running state. +#[inline] +pub fn try_current_task_id() -> Result { + unsafe { + let mut out = MaybeUninit::uninit(); + ItronError::err_if_negative(abi::get_tid(out.as_mut_ptr()))?; + Ok(out.assume_init()) + } +} + +/// Get the specified task's priority. Panics on failure. +#[inline] +pub fn task_priority(task: abi::ID) -> abi::PRI { + try_task_priority(task).unwrap_or_else(|e| fail(e, &"get_pri")) +} + +/// Get the specified task's priority. +#[inline] +pub fn try_task_priority(task: abi::ID) -> Result { + unsafe { + let mut out = MaybeUninit::uninit(); + ItronError::err_if_negative(abi::get_pri(task, out.as_mut_ptr()))?; + Ok(out.assume_init()) + } +} diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs new file mode 100644 index 0000000000000..4feb9c5a6d740 --- /dev/null +++ b/library/std/src/sys/itron/thread.rs @@ -0,0 +1,352 @@ +//! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and +//! `exd_tsk` are available. +use super::{ + abi, + error::{expect_success, expect_success_aborting, ItronError}, + task, + time::dur2reltims, +}; +use crate::{ + cell::UnsafeCell, + convert::TryFrom, + ffi::CStr, + hint, io, + mem::ManuallyDrop, + sync::atomic::{AtomicUsize, Ordering}, + sys::thread_local_dtor::run_dtors, + time::Duration, +}; + +pub struct Thread { + inner: ManuallyDrop>, + + /// The ID of the underlying task. + task: abi::ID, +} + +/// State data shared between a parent thread and child thread. It's dropped on +/// a transition to one of the final states. +struct ThreadInner { + /// This field is used on thread creation to pass a closure from + /// `Thread::new` to the created task. + start: UnsafeCell>>, + + /// A state machine. Each transition is annotated with `[...]` in the + /// source code. + /// + /// ```text + /// + ///