uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
os: windows-latest-xl
- name: i686-mingw-1
env:
- RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
+ RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
SCRIPT: make ci-mingw-subset-1
CUSTOM_MINGW: 1
os: windows-latest-xl
- name: i686-mingw-2
env:
- RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
+ RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
SCRIPT: make ci-mingw-subset-2
CUSTOM_MINGW: 1
os: windows-latest-xl
- name: x86_64-mingw-1
env:
SCRIPT: make ci-mingw-subset-1
- RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
CUSTOM_MINGW: 1
os: windows-latest-xl
- name: x86_64-mingw-2
env:
SCRIPT: make ci-mingw-subset-2
- RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
CUSTOM_MINGW: 1
os: windows-latest-xl
- name: dist-x86_64-msvc
os: windows-latest-xl
- name: dist-i686-mingw
env:
- RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
+ RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
SCRIPT: python x.py dist
CUSTOM_MINGW: 1
DIST_REQUIRE_ALL_TOOLS: 1
- name: dist-x86_64-mingw
env:
SCRIPT: python x.py dist
- RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
CUSTOM_MINGW: 1
DIST_REQUIRE_ALL_TOOLS: 1
os: windows-latest-xl
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
[submodule "src/llvm-project"]
path = src/llvm-project
url = https://github.com/rust-lang/llvm-project.git
- branch = rustc/14.0-2022-06-20
+ branch = rustc/15.0-2022-08-09
[submodule "src/doc/embedded-book"]
path = src/doc/embedded-book
url = https://github.com/rust-embedded/book.git
"url 2.2.2",
]
-[[package]]
-name = "annotate-snippets"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5"
-
[[package]]
name = "annotate-snippets"
version = "0.9.1"
[[package]]
name = "anyhow"
-version = "1.0.51"
+version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
+checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
[[package]]
name = "array_tool"
"cargo-util",
"clap",
"crates-io",
- "crossbeam-utils",
"curl",
"curl-sys",
"env_logger 0.9.0",
"libgit2-sys",
"log",
"memchr",
- "num_cpus",
"opener",
"openssl",
"os_info",
name = "cargo-miri"
version = "0.1.0"
dependencies = [
+ "cargo_metadata 0.15.0",
"directories",
"rustc-workspace-hack",
"rustc_version",
"termcolor",
"toml_edit",
"url 2.2.2",
+ "winapi",
]
[[package]]
[[package]]
name = "cc"
-version = "1.0.69"
+version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
+checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
dependencies = [
"jobserver",
]
[[package]]
name = "clippy"
-version = "0.1.64"
+version = "0.1.65"
dependencies = [
"clippy_lints",
"clippy_utils",
[[package]]
name = "clippy_lints"
-version = "0.1.64"
+version = "0.1.65"
dependencies = [
"cargo_metadata 0.14.0",
"clippy_utils",
[[package]]
name = "clippy_utils"
-version = "0.1.64"
+version = "0.1.65"
dependencies = [
"arrayvec",
"if_chain",
[[package]]
name = "compiler_builtins"
-version = "0.1.73"
+version = "0.1.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71b72fde1d7792ca3bd654f7c3ea4508f9e4d0c826e24179eabb7fcc97a90bc3"
+checksum = "413b6b13f725a46cdec40364e0c1d564a22cf0aaac5f1e267a129d956478a6b4"
dependencies = [
"cc",
"rustc-std-workspace-core",
"getopts",
"glob",
"lazy_static",
+ "lazycell",
"libc",
"miow",
"regex",
name = "html-checker"
version = "0.1.0"
dependencies = [
+ "rayon",
"walkdir",
]
[[package]]
name = "libc"
-version = "0.2.126"
+version = "0.2.129"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+checksum = "64de3cc433455c14174d42e554d4027ee631c4d046d43e3ecc6efc4636cdc7a7"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "os_info"
-version = "3.4.0"
+version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62"
+checksum = "5209b2162b2c140df493a93689e04f8deab3a67634f5bc7a553c0a98e5b8d399"
dependencies = [
"log",
"serde",
name = "rustc_errors"
version = "0.0.0"
dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
"atty",
"rustc_data_structures",
"rustc_error_messages",
name = "rustc_macros"
version = "0.1.0"
dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
"fluent-bundle",
"fluent-syntax",
"proc-macro2",
"rustc_session",
"rustc_span",
"rustc_target",
+ "rustc_transmute",
"smallvec",
"tracing",
]
"tracing",
]
+[[package]]
+name = "rustc_transmute"
+version = "0.1.0"
+dependencies = [
+ "itertools",
+ "rustc_data_structures",
+ "rustc_infer",
+ "rustc_macros",
+ "rustc_middle",
+ "rustc_span",
+ "rustc_target",
+ "tracing",
+]
+
[[package]]
name = "rustc_ty_utils"
version = "0.0.0"
"rustc_attr",
"rustc_data_structures",
"rustc_errors",
+ "rustc_feature",
"rustc_graphviz",
"rustc_hir",
"rustc_hir_pretty",
name = "rustfmt-nightly"
version = "1.5.1"
dependencies = [
- "annotate-snippets 0.9.1",
+ "annotate-snippets",
"anyhow",
"bytecount",
"cargo_metadata 0.14.0",
| Platform / Architecture | x86 | x86_64 |
|---------------------------------------------|-----|--------|
| Windows (7, 8, 10, ...) | ✓ | ✓ |
-| Linux (kernel 2.6.32, glibc 2.11 or later) | ✓ | ✓ |
+| Linux (kernel 3.2, glibc 2.17 or later) | ✓ | ✓ |
| macOS (10.7 Lion or later) | (\*) | ✓ |
(\*): Apple dropped support for running 32-bit binaries starting from macOS 10.15 and iOS 11.
+Version 1.63.0 (2022-08-11)
+==========================
+
+Language
+--------
+- [Remove migrate borrowck mode for pre-NLL errors.][95565]
+- [Modify MIR building to drop repeat expressions with length zero.][95953]
+- [Remove label/lifetime shadowing warnings.][96296]
+- [Allow explicit generic arguments in the presence of `impl Trait` args.][96868]
+- [Make `cenum_impl_drop_cast` warnings deny-by-default.][97652]
+- [Prevent unwinding when `-C panic=abort` is used regardless of declared ABI.][96959]
+- [lub: don't bail out due to empty binders.][97867]
+
+Compiler
+--------
+- [Stabilize the `bundle` native library modifier,][95818] also removing the
+ deprecated `static-nobundle` linking kind.
+- [Add Apple WatchOS compile targets\*.][95243]
+- [Add a Windows application manifest to rustc-main.][96737]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+ information on Rust's tiered platform support.
+
+Libraries
+---------
+- [Implement `Copy`, `Clone`, `PartialEq` and `Eq` for `core::fmt::Alignment`.][94530]
+- [Extend `ptr::null` and `null_mut` to all thin (including extern) types.][94954]
+- [`impl Read and Write for VecDeque<u8>`.][95632]
+- [STD support for the Nintendo 3DS.][95897]
+- [Make write/print macros eagerly drop temporaries.][96455]
+- [Implement internal traits that enable `[OsStr]::join`.][96881]
+- [Implement `Hash` for `core::alloc::Layout`.][97034]
+- [Add capacity documentation for `OsString`.][97202]
+- [Put a bound on collection misbehavior.][97316]
+- [Make `std::mem::needs_drop` accept `?Sized`.][97675]
+- [`impl Termination for Infallible` and then make the `Result` impls of `Termination` more generic.][97803]
+- [Document Rust's stance on `/proc/self/mem`.][97837]
+
+Stabilized APIs
+---------------
+
+- [`array::from_fn`]
+- [`Box::into_pin`]
+- [`BinaryHeap::try_reserve`]
+- [`BinaryHeap::try_reserve_exact`]
+- [`OsString::try_reserve`]
+- [`OsString::try_reserve_exact`]
+- [`PathBuf::try_reserve`]
+- [`PathBuf::try_reserve_exact`]
+- [`Path::try_exists`]
+- [`Ref::filter_map`]
+- [`RefMut::filter_map`]
+- [`NonNull::<[T]>::len`][`NonNull::<slice>::len`]
+- [`ToOwned::clone_into`]
+- [`Ipv6Addr::to_ipv4_mapped`]
+- [`unix::io::AsFd`]
+- [`unix::io::BorrowedFd<'fd>`]
+- [`unix::io::OwnedFd`]
+- [`windows::io::AsHandle`]
+- [`windows::io::BorrowedHandle<'handle>`]
+- [`windows::io::OwnedHandle`]
+- [`windows::io::HandleOrInvalid`]
+- [`windows::io::HandleOrNull`]
+- [`windows::io::InvalidHandleError`]
+- [`windows::io::NullHandleError`]
+- [`windows::io::AsSocket`]
+- [`windows::io::BorrowedSocket<'handle>`]
+- [`windows::io::OwnedSocket`]
+- [`thread::scope`]
+- [`thread::Scope`]
+- [`thread::ScopedJoinHandle`]
+
+These APIs are now usable in const contexts:
+
+- [`array::from_ref`]
+- [`slice::from_ref`]
+- [`intrinsics::copy`]
+- [`intrinsics::copy_nonoverlapping`]
+- [`<*const T>::copy_to`]
+- [`<*const T>::copy_to_nonoverlapping`]
+- [`<*mut T>::copy_to`]
+- [`<*mut T>::copy_to_nonoverlapping`]
+- [`<*mut T>::copy_from`]
+- [`<*mut T>::copy_from_nonoverlapping`]
+- [`str::from_utf8`]
+- [`Utf8Error::error_len`]
+- [`Utf8Error::valid_up_to`]
+- [`Condvar::new`]
+- [`Mutex::new`]
+- [`RwLock::new`]
+
+Cargo
+-----
+- [Stabilize the `--config path` command-line argument.][cargo/10755]
+- [Expose rust-version in the environment as `CARGO_PKG_RUST_VERSION`.][cargo/10713]
+
+Compatibility Notes
+-------------------
+
+- [`#[link]` attributes are now checked more strictly,][96885] which may introduce
+ errors for invalid attribute arguments that were previously ignored.
+
+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.
+
+- [Prepare Rust for LLVM opaque pointers.][94214]
+
+[94214]: https://github.com/rust-lang/rust/pull/94214/
+[94530]: https://github.com/rust-lang/rust/pull/94530/
+[94954]: https://github.com/rust-lang/rust/pull/94954/
+[95243]: https://github.com/rust-lang/rust/pull/95243/
+[95565]: https://github.com/rust-lang/rust/pull/95565/
+[95632]: https://github.com/rust-lang/rust/pull/95632/
+[95818]: https://github.com/rust-lang/rust/pull/95818/
+[95897]: https://github.com/rust-lang/rust/pull/95897/
+[95953]: https://github.com/rust-lang/rust/pull/95953/
+[96296]: https://github.com/rust-lang/rust/pull/96296/
+[96455]: https://github.com/rust-lang/rust/pull/96455/
+[96737]: https://github.com/rust-lang/rust/pull/96737/
+[96868]: https://github.com/rust-lang/rust/pull/96868/
+[96881]: https://github.com/rust-lang/rust/pull/96881/
+[96885]: https://github.com/rust-lang/rust/pull/96885/
+[96959]: https://github.com/rust-lang/rust/pull/96959/
+[97034]: https://github.com/rust-lang/rust/pull/97034/
+[97202]: https://github.com/rust-lang/rust/pull/97202/
+[97316]: https://github.com/rust-lang/rust/pull/97316/
+[97652]: https://github.com/rust-lang/rust/pull/97652/
+[97675]: https://github.com/rust-lang/rust/pull/97675/
+[97803]: https://github.com/rust-lang/rust/pull/97803/
+[97837]: https://github.com/rust-lang/rust/pull/97837/
+[97867]: https://github.com/rust-lang/rust/pull/97867/
+[cargo/10713]: https://github.com/rust-lang/cargo/pull/10713/
+[cargo/10755]: https://github.com/rust-lang/cargo/pull/10755/
+
+[`array::from_fn`]: https://doc.rust-lang.org/stable/std/array/fn.from_fn.html
+[`Box::into_pin`]: https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.into_pin
+[`BinaryHeap::try_reserve_exact`]: https://doc.rust-lang.org/stable/alloc/collections/binary_heap/struct.BinaryHeap.html#method.try_reserve_exact
+[`BinaryHeap::try_reserve`]: https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.try_reserve
+[`OsString::try_reserve`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.try_reserve
+[`OsString::try_reserve_exact`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.try_reserve_exact
+[`PathBuf::try_reserve`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.try_reserve
+[`PathBuf::try_reserve_exact`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.try_reserve_exact
+[`Path::try_exists`]: https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.try_exists
+[`Ref::filter_map`]: https://doc.rust-lang.org/stable/std/cell/struct.Ref.html#method.filter_map
+[`RefMut::filter_map`]: https://doc.rust-lang.org/stable/std/cell/struct.RefMut.html#method.filter_map
+[`NonNull::<slice>::len`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.len
+[`ToOwned::clone_into`]: https://doc.rust-lang.org/stable/std/borrow/trait.ToOwned.html#method.clone_into
+[`Ipv6Addr::to_ipv4_mapped`]: https://doc.rust-lang.org/stable/std/net/struct.Ipv6Addr.html#method.to_ipv4_mapped
+[`unix::io::AsFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsFd.html
+[`unix::io::BorrowedFd<'fd>`]: https://doc.rust-lang.org/stable/std/os/unix/io/struct.BorrowedFd.html
+[`unix::io::OwnedFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/struct.OwnedFd.html
+[`windows::io::AsHandle`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsHandle.html
+[`windows::io::BorrowedHandle<'handle>`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.BorrowedHandle.html
+[`windows::io::OwnedHandle`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html
+[`windows::io::HandleOrInvalid`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.HandleOrInvalid.html
+[`windows::io::HandleOrNull`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.HandleOrNull.html
+[`windows::io::InvalidHandleError`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.InvalidHandleError.html
+[`windows::io::NullHandleError`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.NullHandleError.html
+[`windows::io::AsSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsSocket.html
+[`windows::io::BorrowedSocket<'handle>`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.BorrowedSocket.html
+[`windows::io::OwnedSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedSocket.html
+[`thread::scope`]: https://doc.rust-lang.org/stable/std/thread/fn.scope.html
+[`thread::Scope`]: https://doc.rust-lang.org/stable/std/thread/struct.Scope.html
+[`thread::ScopedJoinHandle`]: https://doc.rust-lang.org/stable/std/thread/struct.ScopedJoinHandle.html
+
+[`array::from_ref`]: https://doc.rust-lang.org/stable/std/array/fn.from_ref.html
+[`slice::from_ref`]: https://doc.rust-lang.org/stable/std/slice/fn.from_ref.html
+[`intrinsics::copy`]: https://doc.rust-lang.org/stable/std/intrinsics/fn.copy.html
+[`intrinsics::copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/intrinsics/fn.copy_nonoverlapping.html
+[`<*const T>::copy_to`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to
+[`<*const T>::copy_to_nonoverlapping`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to_nonoverlapping
+[`<*mut T>::copy_to`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to-1
+[`<*mut T>::copy_to_nonoverlapping`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to_nonoverlapping-1
+[`<*mut T>::copy_from`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_from
+[`<*mut T>::copy_from_nonoverlapping`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_from_nonoverlapping
+[`str::from_utf8`]: https://doc.rust-lang.org/stable/std/str/fn.from_utf8.html
+[`Utf8Error::error_len`]: https://doc.rust-lang.org/stable/std/str/struct.Utf8Error.html#method.error_len
+[`Utf8Error::valid_up_to`]: https://doc.rust-lang.org/stable/std/str/struct.Utf8Error.html#method.valid_up_to
+[`Condvar::new`]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html#method.new
+[`Mutex::new`]: https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html#method.new
+[`RwLock::new`]: https://doc.rust-lang.org/stable/std/sync/struct.RwLock.html#method.new
+
+Version 1.62.1 (2022-07-19)
+==========================
+
+Rust 1.62.1 addresses a few recent regressions in the compiler and standard
+library, and also mitigates a CPU vulnerability on Intel SGX.
+
+* [The compiler fixed unsound function coercions involving `impl Trait` return types.][98608]
+* [The compiler fixed an incremental compilation bug with `async fn` lifetimes.][98890]
+* [Windows added a fallback for overlapped I/O in synchronous reads and writes.][98950]
+* [The `x86_64-fortanix-unknown-sgx` target added a mitigation for the
+ MMIO stale data vulnerability][98126], advisory [INTEL-SA-00615].
+
+[98608]: https://github.com/rust-lang/rust/issues/98608
+[98890]: https://github.com/rust-lang/rust/issues/98890
+[98950]: https://github.com/rust-lang/rust/pull/98950
+[98126]: https://github.com/rust-lang/rust/pull/98126
+[INTEL-SA-00615]: https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html
+
Version 1.62.0 (2022-06-30)
==========================
// FIXME: Implement all operations in DoubleDouble, and delete these
// semantics.
// FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackS<F>(F);
+pub struct FallbackS<F>(#[allow(unused)] F);
type Fallback<F> = ieee::IeeeFloat<FallbackS<F>>;
impl<F: Float> ieee::Semantics for FallbackS<F> {
// Forbid any conversion to/from bits.
// truncate the mantissa. The result of that second conversion
// may be inexact, but should never underflow.
// FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackExtendedS<F>(F);
+pub struct FallbackExtendedS<F>(#[allow(unused)] F);
type FallbackExtended<F> = ieee::IeeeFloat<FallbackExtendedS<F>>;
impl<F: Float> ieee::Semantics for FallbackExtendedS<F> {
// Forbid any conversion to/from bits.
#![feature(rustc_attrs)]
#![cfg_attr(test, feature(test))]
#![feature(strict_provenance)]
-#![feature(ptr_const_cast)]
use smallvec::SmallVec;
/// A "Lifetime" is an annotation of the scope in which variable
/// can be used, e.g. `'a` in `&'a i32`.
-#[derive(Clone, Encodable, Decodable, Copy)]
+#[derive(Clone, Encodable, Decodable, Copy, PartialEq, Eq)]
pub struct Lifetime {
pub id: NodeId,
pub ident: Ident,
pub tokens: Option<LazyTokenStream>,
}
-// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr, 104);
-
impl Expr {
/// Returns `true` if this expression would be valid somewhere that expects a value;
/// for example, an `if` condition.
///
/// The `PathSegment` represents the method name and its generic arguments
/// (within the angle brackets).
- /// The first element of the vector of an `Expr` is the expression that evaluates
- /// to the object on which the method is being called on (the receiver),
- /// and the remaining elements are the rest of the arguments.
- /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
- /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
+ /// The standalone `Expr` is the receiver expression.
+ /// The vector of `Expr` is the arguments.
+ /// `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
+ /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d])`.
/// This `Span` is the span of the function, without the dot and receiver
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
- MethodCall(PathSegment, Vec<P<Expr>>, Span),
+ MethodCall(PathSegment, P<Expr>, Vec<P<Expr>>, Span),
/// A tuple (e.g., `(a, b, c, d)`).
Tup(Vec<P<Expr>>),
/// A binary operation (e.g., `a + b`, `a * b`).
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum VisibilityKind {
Public,
- Restricted { path: P<Path>, id: NodeId },
+ Restricted { path: P<Path>, id: NodeId, shorthand: bool },
Inherited,
}
MacroDef(MacroDef),
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ItemKind, 112);
-
impl ItemKind {
pub fn article(&self) -> &str {
use ItemKind::*;
MacCall(MacCall),
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(AssocItemKind, 72);
-
impl AssocItemKind {
pub fn defaultness(&self) -> Defaultness {
match *self {
MacCall(MacCall),
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ForeignItemKind, 72);
-
impl From<ForeignItemKind> for ItemKind {
fn from(foreign_item_kind: ForeignItemKind) -> ItemKind {
match foreign_item_kind {
}
pub type ForeignItem = Item<ForeignItemKind>;
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // These are in alphabetical order, which is easy to maintain.
+ static_assert_size!(AssocItem, 160);
+ static_assert_size!(AssocItemKind, 72);
+ static_assert_size!(Attribute, 152);
+ static_assert_size!(Block, 48);
+ static_assert_size!(Expr, 104);
+ static_assert_size!(Fn, 192);
+ static_assert_size!(ForeignItem, 160);
+ static_assert_size!(ForeignItemKind, 72);
+ static_assert_size!(GenericBound, 88);
+ static_assert_size!(Generics, 72);
+ static_assert_size!(Impl, 200);
+ static_assert_size!(Item, 200);
+ static_assert_size!(ItemKind, 112);
+ static_assert_size!(Lit, 48);
+ static_assert_size!(Pat, 120);
+ static_assert_size!(Path, 40);
+ static_assert_size!(PathSegment, 24);
+ static_assert_size!(Stmt, 32);
+ static_assert_size!(Ty, 96);
+}
vis.visit_expr(f);
visit_exprs(args, vis);
}
- ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => {
+ ExprKind::MethodCall(PathSegment { ident, id, args }, receiver, exprs, span) => {
vis.visit_ident(ident);
vis.visit_id(id);
visit_opt(args, |args| vis.visit_generic_args(args));
+ vis.visit_expr(receiver);
visit_exprs(exprs, vis);
vis.visit_span(span);
}
pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
match &mut visibility.kind {
VisibilityKind::Public | VisibilityKind::Inherited => {}
- VisibilityKind::Restricted { path, id } => {
+ VisibilityKind::Restricted { path, id, shorthand: _ } => {
vis.visit_path(path);
vis.visit_id(id);
}
}
for token in rustc_lexer::tokenize(&text[pos..]) {
- let token_text = &text[pos..pos + token.len];
+ let token_text = &text[pos..pos + token.len as usize];
match token.kind {
rustc_lexer::TokenKind::Whitespace => {
if let Some(mut idx) = token_text.find('\n') {
}
rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
if doc_style.is_none() {
- let code_to_the_right =
- !matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n'));
+ let code_to_the_right = !matches!(
+ text[pos + token.len as usize..].chars().next(),
+ Some('\r' | '\n')
+ );
let style = match (code_to_the_left, code_to_the_right) {
(_, true) => CommentStyle::Mixed,
(false, false) => CommentStyle::Isolated,
code_to_the_left = true;
}
}
- pos += token.len;
+ pos += token.len as usize;
}
comments
contains_exterior_struct_lit(&x)
}
- ast::ExprKind::MethodCall(.., ref exprs, _) => {
+ ast::ExprKind::MethodCall(_, ref receiver, _, _) => {
// X { y: 1 }.bar(...)
- contains_exterior_struct_lit(&exprs[0])
+ contains_exterior_struct_lit(&receiver)
}
_ => false,
fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) {
walk_param_bound(self, bounds)
}
- fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
- walk_poly_trait_ref(self, t, m)
+ fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
+ walk_poly_trait_ref(self, t)
}
fn visit_variant_data(&mut self, s: &'ast VariantData) {
walk_struct_def(self, s)
fn visit_field_def(&mut self, s: &'ast FieldDef) {
walk_field_def(self, s)
}
- fn visit_enum_def(
- &mut self,
- enum_definition: &'ast EnumDef,
- generics: &'ast Generics,
- item_id: NodeId,
- _: Span,
- ) {
- walk_enum_def(self, enum_definition, generics, item_id)
+ fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) {
+ walk_enum_def(self, enum_definition)
}
fn visit_variant(&mut self, v: &'ast Variant) {
walk_variant(self, v)
visitor.visit_ident(lifetime.ident);
}
-pub fn walk_poly_trait_ref<'a, V>(
- visitor: &mut V,
- trait_ref: &'a PolyTraitRef,
- _: &TraitBoundModifier,
-) where
+pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef)
+where
V: Visitor<'a>,
{
walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params);
}
ItemKind::Enum(ref enum_definition, ref generics) => {
visitor.visit_generics(generics);
- visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
+ visitor.visit_enum_def(enum_definition)
}
ItemKind::Impl(box Impl {
defaultness: _,
walk_list!(visitor, visit_attribute, &item.attrs);
}
-pub fn walk_enum_def<'a, V: Visitor<'a>>(
- visitor: &mut V,
- enum_definition: &'a EnumDef,
- _: &'a Generics,
- _: NodeId,
-) {
+pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, enum_definition: &'a EnumDef) {
walk_list!(visitor, visit_variant, &enum_definition.variants);
}
pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) {
match *bound {
- GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier),
+ GenericBound::Trait(ref typ, ref _modifier) => visitor.visit_poly_trait_ref(typ),
GenericBound::Outlives(ref lifetime) => {
visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound)
}
visitor.visit_expr(callee_expression);
walk_list!(visitor, visit_expr, arguments);
}
- ExprKind::MethodCall(ref segment, ref arguments, _span) => {
+ ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _span) => {
visitor.visit_path_segment(expression.span, segment);
+ visitor.visit_expr(receiver);
walk_list!(visitor, visit_expr, arguments);
}
ExprKind::Binary(_, ref left_expression, ref right_expression) => {
}
pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) {
- if let VisibilityKind::Restricted { ref path, id } = vis.kind {
+ if let VisibilityKind::Restricted { ref path, id, shorthand: _ } = vis.kind {
visitor.visit_path(path, id);
}
}
hir::ExprKind::Call(f, self.lower_exprs(args))
}
}
- ExprKind::MethodCall(ref seg, ref args, span) => {
+ ExprKind::MethodCall(ref seg, ref receiver, ref args, span) => {
let hir_seg = self.arena.alloc(self.lower_path_segment(
e.span,
seg,
ParenthesizedGenericArgs::Err,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
));
- let args = self.lower_exprs(args);
+ let args = self.arena.alloc_from_iter(
+ [&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)),
+ );
hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
(body_id, generator_option)
});
- self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
- // Lower outside new scope to preserve `is_in_loop_condition`.
- let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
-
- let c = self.arena.alloc(hir::Closure {
- binder: binder_clause,
- capture_clause,
- bound_generic_params,
- fn_decl,
- body: body_id,
- fn_decl_span: this.lower_span(fn_decl_span),
- movability: generator_option,
- });
+ let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
+ // Lower outside new scope to preserve `is_in_loop_condition`.
+ let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
+
+ let c = self.arena.alloc(hir::Closure {
+ binder: binder_clause,
+ capture_clause,
+ bound_generic_params,
+ fn_decl,
+ body: body_id,
+ fn_decl_span: self.lower_span(fn_decl_span),
+ movability: generator_option,
+ });
- hir::ExprKind::Closure(c)
- })
+ hir::ExprKind::Closure(c)
}
fn generator_movability_for_fn(
body_id
});
- self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
- // We need to lower the declaration outside the new scope, because we
- // have to conserve the state of being inside a loop condition for the
- // closure argument types.
- let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
-
- let c = self.arena.alloc(hir::Closure {
- binder: binder_clause,
- capture_clause,
- bound_generic_params,
- fn_decl,
- body,
- fn_decl_span: this.lower_span(fn_decl_span),
- movability: None,
- });
- hir::ExprKind::Closure(c)
- })
+ let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
+
+ // We need to lower the declaration outside the new scope, because we
+ // have to conserve the state of being inside a loop condition for the
+ // closure argument types.
+ let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
+
+ let c = self.arena.alloc(hir::Closure {
+ binder: binder_clause,
+ capture_clause,
+ bound_generic_params,
+ fn_decl,
+ body,
+ fn_decl_span: self.lower_span(fn_decl_span),
+ movability: None,
+ });
+ hir::ExprKind::Closure(c)
}
/// Destructure the LHS of complex assignments.
hir::MatchSource::ForLoopDesugar,
));
- let attrs: Vec<_> = e.attrs.iter().map(|a| self.lower_attr(a)).collect();
-
// This is effectively `{ let _result = ...; _result }`.
// The construct was introduced in #21984 and is necessary to make sure that
// temporaries in the `head` expression are dropped and do not leak to the
// surrounding scope of the `match` since the `match` is not a terminating scope.
//
// Also, add the attributes to the outer returned expr node.
- self.expr_drop_temps_mut(for_span, match_expr, attrs.into())
+ self.expr_drop_temps_mut(for_span, match_expr, e.attrs.clone())
}
/// Desugar `ExprKind::Try` from: `<expr>?` into:
self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
}
- fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
+ fn visit_variant(&mut self, v: &'hir Variant<'hir>) {
self.insert(v.span, v.id, Node::Variant(v));
self.with_parent(v.id, |this| {
// Register the constructor of this variant.
if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
}
- intravisit::walk_variant(this, v, g, item_id);
+ intravisit::walk_variant(this, v);
});
}
fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
// Do not visit the duplicate information in TraitItemRef. We want to
// map the actual nodes, not the duplicate ones in the *Ref.
- let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
+ let TraitItemRef { id, ident: _, kind: _, span: _ } = *ii;
self.visit_nested_trait_item(id);
}
fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
// Do not visit the duplicate information in ImplItemRef. We want to
// map the actual nodes, not the duplicate ones in the *Ref.
- let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _, trait_item_def_id: _ } =
- *ii;
+ let ImplItemRef { id, ident: _, kind: _, span: _, trait_item_def_id: _ } = *ii;
self.visit_nested_impl_item(id);
}
generator_kind: None,
task_context: None,
current_item: None,
- captured_lifetimes: None,
impl_trait_defs: Vec::new(),
impl_trait_bounds: Vec::new(),
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
let hir_id = self.lower_node_id(i.id);
let trait_item_def_id = hir_id.expect_owner();
- let (generics, kind) = match i.kind {
+ let (generics, kind, has_default) = match i.kind {
AssocItemKind::Const(_, ref ty, ref default) => {
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
- (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
+ (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
}
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
let names = self.lower_fn_params_to_names(&sig.decl);
let (generics, sig) =
self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None);
- (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
+ (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
}
AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
let asyncness = sig.header.asyncness;
FnDeclKind::Trait,
asyncness.opt_return_id(),
);
- (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
+ (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
}
AssocItemKind::TyAlias(box TyAlias {
ref generics,
}) => {
let mut generics = generics.clone();
add_ty_alias_where_clause(&mut generics, where_clauses, false);
- self.lower_generics(
+ let (generics, kind) = self.lower_generics(
&generics,
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
ty,
)
},
- )
+ );
+ (generics, kind, ty.is_some())
}
AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
};
generics,
kind,
span: self.lower_span(i.span),
+ defaultness: hir::Defaultness::Default { has_value: has_default },
};
self.arena.alloc(item)
}
fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
- let (kind, has_default) = match &i.kind {
- AssocItemKind::Const(_, _, default) => (hir::AssocItemKind::Const, default.is_some()),
- AssocItemKind::TyAlias(box TyAlias { ty, .. }) => {
- (hir::AssocItemKind::Type, ty.is_some())
- }
- AssocItemKind::Fn(box Fn { sig, body, .. }) => {
- (hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, body.is_some())
+ let kind = match &i.kind {
+ AssocItemKind::Const(..) => hir::AssocItemKind::Const,
+ AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
+ AssocItemKind::Fn(box Fn { sig, .. }) => {
+ hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
AssocItemKind::MacCall(..) => unimplemented!(),
};
let id = hir::TraitItemId { def_id: self.local_def_id(i.id) };
- let defaultness = hir::Defaultness::Default { has_value: has_default };
hir::TraitItemRef {
id,
ident: self.lower_ident(i.ident),
span: self.lower_span(i.span),
- defaultness,
kind,
}
}
}
fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
+ // Since `default impl` is not yet implemented, this is always true in impls.
+ let has_value = true;
+ let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
+
let (generics, kind) = match &i.kind {
AssocItemKind::Const(_, ty, expr) => {
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
kind,
vis_span: self.lower_span(i.vis.span),
span: self.lower_span(i.span),
+ defaultness,
};
self.arena.alloc(item)
}
fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
- // Since `default impl` is not yet implemented, this is always true in impls.
- let has_value = true;
- let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
hir::ImplItemRef {
id: hir::ImplItemId { def_id: self.local_def_id(i.id) },
ident: self.lower_ident(i.ident),
span: self.lower_span(i.span),
- defaultness,
kind: match &i.kind {
AssocItemKind::Const(..) => hir::AssocItemKind::Const,
AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
predicates.extend(generics.params.iter().filter_map(|param| {
- let bounds = self.lower_param_bounds(¶m.bounds, itctx);
self.lower_generic_bound_predicate(
param.ident,
param.id,
¶m.kind,
- bounds,
+ ¶m.bounds,
+ itctx,
PredicateOrigin::GenericParam,
)
}));
ident: Ident,
id: NodeId,
kind: &GenericParamKind,
- bounds: &'hir [hir::GenericBound<'hir>],
+ bounds: &[GenericBound],
+ itctx: ImplTraitContext,
origin: PredicateOrigin,
) -> Option<hir::WherePredicate<'hir>> {
// Do not create a clause if we do not have anything inside it.
if bounds.is_empty() {
return None;
}
+
+ let bounds = self.lower_param_bounds(bounds, itctx);
+
let ident = self.lower_ident(ident);
let param_span = ident.span;
let span = bounds
GenericParamKind::Lifetime => {
let ident_span = self.lower_span(ident.span);
let ident = self.lower_ident(ident);
- let res = self.resolver.get_lifetime_res(id).unwrap_or_else(|| {
- panic!("Missing resolution for lifetime {:?} at {:?}", id, ident.span)
- });
let lt_id = self.next_node_id();
- let lifetime = self.new_named_lifetime_with_res(lt_id, ident_span, ident, res);
+ let lifetime = self.new_named_lifetime(id, lt_id, ident_span, ident);
Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
lifetime,
span,
use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_hir::definitions::DefPathData;
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::span_bug;
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
use rustc_session::parse::feature_err;
use rustc_span::hygiene::MacroKind;
mod expr;
mod index;
mod item;
+mod lifetime_collector;
mod pat;
mod path;
is_in_trait_impl: bool,
is_in_dyn_type: bool,
- /// Used to handle lifetimes appearing in impl-traits.
- captured_lifetimes: Option<LifetimeCaptureContext>,
-
current_hir_id_owner: LocalDefId,
item_local_id_counter: hir::ItemLocalId,
local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
allow_into_future: Option<Lrc<[Symbol]>>,
}
-/// When we lower a lifetime, it is inserted in `captures`, and the resolution is modified so
-/// to point to the lifetime parameter impl-trait will generate.
-/// When traversing `for<...>` binders, they are inserted in `binders_to_ignore` so we know *not*
-/// to rebind the introduced lifetimes.
-#[derive(Debug)]
-struct LifetimeCaptureContext {
- /// parent def_id for new definitions
- parent_def_id: LocalDefId,
- /// Set of lifetimes to rebind.
- captures: FxHashMap<
- LocalDefId, // original parameter id
- (
- Span, // Span
- NodeId, // synthetized parameter id
- ParamName, // parameter name
- LifetimeRes, // original resolution
- ),
- >,
- /// Traversed binders. The ids in this set should *not* be rebound.
- binders_to_ignore: FxHashSet<NodeId>,
-}
-
trait ResolverAstLoweringExt {
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind;
+ /// Record the map from `from` local def id to `to` local def id, on `generics_def_id_map`
+ /// field.
+ fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId);
+ /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
+ /// `generics_def_id_map` field.
+ fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId;
}
impl ResolverAstLoweringExt for ResolverAstLowering {
fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind {
self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang)
}
+
+ /// Push a remapping into the top-most map.
+ /// Panics if no map has been pushed.
+ /// Remapping is used when creating lowering `-> impl Trait` return
+ /// types to create the resulting opaque type.
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) {
+ self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to);
+ }
+
+ fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
+ // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
+ // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
+ //
+ // Consider:
+ //
+ // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}`
+ //
+ // We would end with a generics_def_id_map like:
+ //
+ // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
+ //
+ // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
+ // impl_sized#'b, so iterating forward is the wrong thing to do.
+ for map in self.generics_def_id_map.iter().rev() {
+ if let Some(r) = map.get(&local_def_id) {
+ debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
+ local_def_id = *r;
+ } else {
+ debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
+ }
+ }
+
+ local_def_id
+ }
}
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
start
}
+ /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
+ /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
+ ///
+ /// For example, in a function like `fn foo<'a>(x: &'a u32)`,
+ /// invoking with the id from the `ast::Lifetime` node found inside
+ /// the `&'a u32` type would return the `LocalDefId` of the
+ /// `'a` parameter declared on `foo`.
+ ///
+ /// This function also applies remapping from `get_remapped_def_id`.
+ /// These are used when synthesizing opaque types from `-> impl Trait` return types and so forth.
+ /// For example, in a function like `fn foo<'a>() -> impl Debug + 'a`,
+ /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`.
+ /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`.
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
- self.resolver.node_id_to_def_id.get(&node).copied()
+ self.resolver
+ .node_id_to_def_id
+ .get(&node)
+ .map(|local_def_id| self.resolver.get_remapped_def_id(*local_def_id))
}
fn local_def_id(&self, node: NodeId) -> LocalDefId {
debug_assert!(_old.is_none())
}
+ /// Installs the remapping `remap` in scope while `f` is being executed.
+ /// This causes references to the `LocalDefId` keys to be changed to
+ /// refer to the values instead.
+ ///
+ /// The remapping is used when one piece of AST expands to multiple
+ /// pieces of HIR. For example, the function `fn foo<'a>(...) -> impl Debug + 'a`,
+ /// expands to both a function definition (`foo`) and a TAIT for the return value,
+ /// both of which have a lifetime parameter `'a`. The remapping allows us to
+ /// rewrite the `'a` in the return value to refer to the
+ /// `'a` declared on the TAIT, instead of the function.
+ fn with_remapping<R>(
+ &mut self,
+ remap: FxHashMap<LocalDefId, LocalDefId>,
+ f: impl FnOnce(&mut Self) -> R,
+ ) -> R {
+ self.resolver.generics_def_id_map.push(remap);
+ let res = f(self);
+ self.resolver.generics_def_id_map.pop();
+ res
+ }
+
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
let attrs = std::mem::take(&mut self.attrs);
let mut bodies = std::mem::take(&mut self.bodies);
})
}
- /// Setup lifetime capture for and impl-trait.
- /// The captures will be added to `captures`.
- fn while_capturing_lifetimes<T>(
- &mut self,
- parent_def_id: LocalDefId,
- captures: &mut FxHashMap<LocalDefId, (Span, NodeId, ParamName, LifetimeRes)>,
- f: impl FnOnce(&mut Self) -> T,
- ) -> T {
- let lifetime_stash = std::mem::replace(
- &mut self.captured_lifetimes,
- Some(LifetimeCaptureContext {
- parent_def_id,
- captures: std::mem::take(captures),
- binders_to_ignore: Default::default(),
- }),
- );
-
- let ret = f(self);
-
- let ctxt = std::mem::replace(&mut self.captured_lifetimes, lifetime_stash).unwrap();
- *captures = ctxt.captures;
-
- ret
- }
-
- /// Register a binder to be ignored for lifetime capture.
- #[tracing::instrument(level = "debug", skip(self, f))]
+ /// Lowers a lifetime binder that defines `generic_params`, returning the corresponding HIR
+ /// nodes. The returned list includes any "extra" lifetime parameters that were added by the
+ /// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id
+ /// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime
+ /// parameters will be successful.
+ #[tracing::instrument(level = "debug", skip(self))]
#[inline]
- fn with_lifetime_binder<T>(
+ fn lower_lifetime_binder(
&mut self,
binder: NodeId,
generic_params: &[GenericParam],
- f: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> T,
- ) -> T {
+ ) -> &'hir [hir::GenericParam<'hir>] {
let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
debug!(?extra_lifetimes);
let generic_params = self.arena.alloc_from_iter(generic_params);
debug!(?generic_params);
- if let Some(ctxt) = &mut self.captured_lifetimes {
- ctxt.binders_to_ignore.insert(binder);
- }
- let ret = f(self, generic_params);
- if let Some(ctxt) = &mut self.captured_lifetimes {
- ctxt.binders_to_ignore.remove(&binder);
- }
- ret
+ generic_params
}
fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
} else {
self.next_node_id()
};
- let span = self.tcx.sess.source_map().next_point(t.span.shrink_to_lo());
+ let span = self.tcx.sess.source_map().start_point(t.span);
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
});
let lifetime = self.lower_lifetime(®ion);
hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
}
TyKind::BareFn(ref f) => {
- self.with_lifetime_binder(t.id, &f.generic_params, |this, generic_params| {
- hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
- generic_params,
- unsafety: this.lower_unsafety(f.unsafety),
- abi: this.lower_extern(f.ext),
- decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
- param_names: this.lower_fn_params_to_names(&f.decl),
- }))
- })
+ let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
+ hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
+ generic_params,
+ unsafety: self.lower_unsafety(f.unsafety),
+ abi: self.lower_extern(f.ext),
+ decl: self.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+ param_names: self.lower_fn_params_to_names(&f.decl),
+ }))
}
TyKind::Never => hir::TyKind::Never,
TyKind::Tup(ref tys) => hir::TyKind::Tup(
TyKind::ImplTrait(def_node_id, ref bounds) => {
let span = t.span;
match itctx {
- ImplTraitContext::ReturnPositionOpaqueTy { origin } => self
- .lower_opaque_impl_trait(span, origin, def_node_id, |this| {
- this.lower_param_bounds(bounds, itctx)
- }),
+ ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
+ self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx)
+ }
ImplTraitContext::TypeAliasesOpaqueTy => {
let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
self.lower_opaque_impl_trait(
span,
hir::OpaqueTyOrigin::TyAlias,
def_node_id,
- |this| this.lower_param_bounds(bounds, nested_itctx),
+ bounds,
+ nested_itctx,
)
}
ImplTraitContext::Universal => {
hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
}
- #[tracing::instrument(level = "debug", skip(self, lower_bounds))]
+ /// Lowers a `ReturnPositionOpaqueTy` (`-> impl Trait`) or a `TypeAliasesOpaqueTy` (`type F =
+ /// impl Trait`): this creates the associated Opaque Type (TAIT) definition and then returns a
+ /// HIR type that references the TAIT.
+ ///
+ /// Given a function definition like:
+ ///
+ /// ```rust
+ /// fn test<'a, T: Debug>(x: &'a T) -> impl Debug + 'a {
+ /// x
+ /// }
+ /// ```
+ ///
+ /// we will create a TAIT definition in the HIR like
+ ///
+ /// ```
+ /// type TestReturn<'a, T, 'x> = impl Debug + 'x
+ /// ```
+ ///
+ /// and return a type like `TestReturn<'static, T, 'a>`, so that the function looks like:
+ ///
+ /// ```rust
+ /// fn test<'a, T: Debug>(x: &'a T) -> TestReturn<'static, T, 'a>
+ /// ```
+ ///
+ /// Note the subtlety around type parameters! The new TAIT, `TestReturn`, inherits all the
+ /// type parameters from the function `test` (this is implemented in the query layer, they aren't
+ /// added explicitly in the HIR). But this includes all the lifetimes, and we only want to
+ /// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters
+ /// for the lifetimes that get captured (`'x`, in our example above) and reference those.
+ #[tracing::instrument(level = "debug", skip(self))]
fn lower_opaque_impl_trait(
&mut self,
span: Span,
origin: hir::OpaqueTyOrigin,
opaque_ty_node_id: NodeId,
- lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>,
+ bounds: &GenericBounds,
+ itctx: ImplTraitContext,
) -> hir::TyKind<'hir> {
// Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
+ debug!(?opaque_ty_def_id);
- let mut collected_lifetimes = FxHashMap::default();
- self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
- let hir_bounds = if origin == hir::OpaqueTyOrigin::TyAlias {
- lower_bounds(lctx)
- } else {
- lctx.while_capturing_lifetimes(
- opaque_ty_def_id,
- &mut collected_lifetimes,
- lower_bounds,
- )
- };
- debug!(?collected_lifetimes);
+ // Contains the new lifetime definitions created for the TAIT (if any).
+ let mut collected_lifetimes = Vec::new();
- let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
- |(_, &(span, p_id, p_name, _))| {
- let hir_id = lctx.lower_node_id(p_id);
- debug_assert_ne!(lctx.opt_local_def_id(p_id), None);
+ // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
+ // to capture the lifetimes that appear in the bounds. So visit the bounds to find out
+ // exactly which ones those are.
+ let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias {
+ // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
+ Vec::new()
+ } else {
+ // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+ // we only keep the lifetimes that appear in the `impl Debug` itself:
+ lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+ };
+ debug!(?lifetimes_to_remap);
- let kind = if p_name.ident().name == kw::UnderscoreLifetime {
- hir::LifetimeParamKind::Elided
- } else {
- hir::LifetimeParamKind::Explicit
- };
+ self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
+ let mut new_remapping = FxHashMap::default();
+
+ // If this opaque type is only capturing a subset of the lifetimes (those that appear
+ // in bounds), then create the new lifetime parameters required and create a mapping
+ // from the old `'a` (on the function) to the new `'a` (on the opaque type).
+ collected_lifetimes = lctx.create_lifetime_defs(
+ opaque_ty_def_id,
+ &lifetimes_to_remap,
+ &mut new_remapping,
+ );
+ debug!(?collected_lifetimes);
+ debug!(?new_remapping);
+
+ // Install the remapping from old to new (if any):
+ lctx.with_remapping(new_remapping, |lctx| {
+ // This creates HIR lifetime definitions as `hir::GenericParam`, in the given
+ // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection
+ // containing `&['x]`.
+ let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
+ |&(new_node_id, lifetime)| {
+ let hir_id = lctx.lower_node_id(new_node_id);
+ debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None);
+
+ let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
+ (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+ } else {
+ (
+ hir::ParamName::Plain(lifetime.ident),
+ hir::LifetimeParamKind::Explicit,
+ )
+ };
- hir::GenericParam {
- hir_id,
- name: p_name,
- span,
- pure_wrt_drop: false,
- kind: hir::GenericParamKind::Lifetime { kind },
- colon_span: None,
- }
- },
- ));
-
- debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs);
-
- let opaque_ty_item = hir::OpaqueTy {
- generics: self.arena.alloc(hir::Generics {
- params: lifetime_defs,
- predicates: &[],
- has_where_clause_predicates: false,
- where_clause_span: lctx.lower_span(span),
- span: lctx.lower_span(span),
- }),
- bounds: hir_bounds,
- origin,
- };
+ hir::GenericParam {
+ hir_id,
+ name,
+ span: lifetime.ident.span,
+ pure_wrt_drop: false,
+ kind: hir::GenericParamKind::Lifetime { kind },
+ colon_span: None,
+ }
+ },
+ ));
+ debug!(?lifetime_defs);
+
+ // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we
+ // get back Debug + 'a1, which is suitable for use on the TAIT.
+ let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
+ debug!(?hir_bounds);
+
+ let opaque_ty_item = hir::OpaqueTy {
+ generics: self.arena.alloc(hir::Generics {
+ params: lifetime_defs,
+ predicates: &[],
+ has_where_clause_predicates: false,
+ where_clause_span: lctx.lower_span(span),
+ span: lctx.lower_span(span),
+ }),
+ bounds: hir_bounds,
+ origin,
+ };
+ debug!(?opaque_ty_item);
- trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_id);
- lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+ lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+ })
});
- let lifetimes = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
- |(_, (span, _, p_name, res))| {
+ // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
+ // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
+ let lifetimes =
+ self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| {
let id = self.next_node_id();
- let ident = Ident::new(p_name.ident().name, span);
- let l = self.new_named_lifetime_with_res(id, span, ident, res);
- hir::GenericArg::Lifetime(l)
- },
- ));
+ let span = lifetime.ident.span;
- debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes);
+ let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
+ Ident::with_dummy_span(kw::UnderscoreLifetime)
+ } else {
+ lifetime.ident
+ };
+
+ let l = self.new_named_lifetime(lifetime.id, id, span, ident);
+ hir::GenericArg::Lifetime(l)
+ }));
+ debug!(?lifetimes);
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
}
+ /// Given a `parent_def_id`, a list of `lifetimes_in_bounds and a `remapping` hash to be
+ /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
+ /// new definition, adds it to the remapping with the definition of the given lifetime and
+ /// returns a list of lifetimes to be lowered afterwards.
+ fn create_lifetime_defs(
+ &mut self,
+ parent_def_id: LocalDefId,
+ lifetimes_in_bounds: &[Lifetime],
+ remapping: &mut FxHashMap<LocalDefId, LocalDefId>,
+ ) -> Vec<(NodeId, Lifetime)> {
+ let mut result = Vec::new();
+
+ for lifetime in lifetimes_in_bounds {
+ let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
+ debug!(?res);
+
+ match res {
+ LifetimeRes::Param { param: old_def_id, binder: _ } => {
+ if remapping.get(&old_def_id).is_none() {
+ let node_id = self.next_node_id();
+
+ let new_def_id = self.create_def(
+ parent_def_id,
+ node_id,
+ DefPathData::LifetimeNs(lifetime.ident.name),
+ );
+ remapping.insert(old_def_id, new_def_id);
+
+ result.push((node_id, *lifetime));
+ }
+ }
+
+ LifetimeRes::Fresh { param, binder: _ } => {
+ debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
+ let old_def_id = self.local_def_id(param);
+ if remapping.get(&old_def_id).is_none() {
+ let node_id = self.next_node_id();
+
+ let new_def_id = self.create_def(
+ parent_def_id,
+ node_id,
+ DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+ );
+ remapping.insert(old_def_id, new_def_id);
+
+ result.push((node_id, *lifetime));
+ }
+ }
+
+ LifetimeRes::Static | LifetimeRes::Error => {}
+
+ res => {
+ let bug_msg = format!(
+ "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+ res, lifetime.ident, lifetime.ident.span
+ );
+ span_bug!(lifetime.ident.span, "{}", bug_msg);
+ }
+ }
+ }
+
+ result
+ }
+
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
// Skip the `...` (`CVarArgs`) trailing arguments from the AST,
// as they are not explicit in HIR/Ty function signatures.
//
// type OpaqueTy<generics_from_parent_fn> = impl Future<Output = T>;
//
- // `inputs`: lowered types of parameters to the function (used to collect lifetimes)
// `output`: unlowered output type (`T` in `-> T`)
// `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
// `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
- // `elided_lt_replacement`: replacement for elided lifetimes in the return type
#[tracing::instrument(level = "debug", skip(self))]
fn lower_async_fn_ret_ty(
&mut self,
// by the opaque type. This should include all in-scope
// lifetime parameters, including those defined in-band.
- let mut captures = FxHashMap::default();
+ // Contains the new lifetime definitions created for the TAIT (if any) generated for the
+ // return type.
+ let mut collected_lifetimes = Vec::new();
+ let mut new_remapping = FxHashMap::default();
let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
debug!(?extra_lifetime_params);
for (ident, outer_node_id, outer_res) in extra_lifetime_params {
- let Ident { name, span } = ident;
let outer_def_id = self.local_def_id(outer_node_id);
let inner_node_id = self.next_node_id();
// Add a definition for the in scope lifetime def.
- self.create_def(opaque_ty_def_id, inner_node_id, DefPathData::LifetimeNs(name));
+ let inner_def_id = self.create_def(
+ opaque_ty_def_id,
+ inner_node_id,
+ DefPathData::LifetimeNs(ident.name),
+ );
+ new_remapping.insert(outer_def_id, inner_def_id);
- let (p_name, inner_res) = match outer_res {
+ let inner_res = match outer_res {
// Input lifetime like `'a`:
LifetimeRes::Param { param, .. } => {
- (hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id })
+ LifetimeRes::Param { param, binder: fn_node_id }
}
// Input lifetime like `'1`:
LifetimeRes::Fresh { param, .. } => {
- (hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id })
+ LifetimeRes::Fresh { param, binder: fn_node_id }
}
LifetimeRes::Static | LifetimeRes::Error => continue,
res => {
- panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
+ panic!(
+ "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+ res, ident, ident.span
+ )
}
};
- captures.insert(outer_def_id, (span, inner_node_id, p_name, inner_res));
+ let lifetime = Lifetime { id: outer_node_id, ident };
+ collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
}
- debug!(?captures);
-
- self.with_hir_id_owner(opaque_ty_node_id, |this| {
- let future_bound =
- this.while_capturing_lifetimes(opaque_ty_def_id, &mut captures, |this| {
- // We have to be careful to get elision right here. The
- // idea is that we create a lifetime parameter for each
- // lifetime in the return type. So, given a return type
- // like `async fn foo(..) -> &[&u32]`, we lower to `impl
- // Future<Output = &'1 [ &'2 u32 ]>`.
- //
- // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
- // hence the elision takes place at the fn site.
- this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
- });
- debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
- debug!("lower_async_fn_ret_ty: captures={:#?}", captures);
+ debug!(?collected_lifetimes);
- let generic_params =
- this.arena.alloc_from_iter(captures.iter().map(|(_, &(span, p_id, p_name, _))| {
- let hir_id = this.lower_node_id(p_id);
- debug_assert_ne!(this.opt_local_def_id(p_id), None);
+ // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
+ // find out exactly which ones those are.
+ // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+ // we only keep the lifetimes that appear in the `impl Debug` itself:
+ let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
+ debug!(?lifetimes_to_remap);
- let kind = if p_name.ident().name == kw::UnderscoreLifetime {
- hir::LifetimeParamKind::Elided
- } else {
- hir::LifetimeParamKind::Explicit
- };
+ self.with_hir_id_owner(opaque_ty_node_id, |this| {
+ // If this opaque type is only capturing a subset of the lifetimes (those that appear
+ // in bounds), then create the new lifetime parameters required and create a mapping
+ // from the old `'a` (on the function) to the new `'a` (on the opaque type).
+ collected_lifetimes.extend(
+ this.create_lifetime_defs(
+ opaque_ty_def_id,
+ &lifetimes_to_remap,
+ &mut new_remapping,
+ )
+ .into_iter()
+ .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
+ );
+ debug!(?collected_lifetimes);
+ debug!(?new_remapping);
+
+ // Install the remapping from old to new (if any):
+ this.with_remapping(new_remapping, |this| {
+ // We have to be careful to get elision right here. The
+ // idea is that we create a lifetime parameter for each
+ // lifetime in the return type. So, given a return type
+ // like `async fn foo(..) -> &[&u32]`, we lower to `impl
+ // Future<Output = &'1 [ &'2 u32 ]>`.
+ //
+ // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
+ // hence the elision takes place at the fn site.
+ let future_bound =
+ this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span);
+
+ let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
+ |&(new_node_id, lifetime, _)| {
+ let hir_id = this.lower_node_id(new_node_id);
+ debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
+
+ let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
+ (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+ } else {
+ (
+ hir::ParamName::Plain(lifetime.ident),
+ hir::LifetimeParamKind::Explicit,
+ )
+ };
- hir::GenericParam {
- hir_id,
- name: p_name,
- span,
- pure_wrt_drop: false,
- kind: hir::GenericParamKind::Lifetime { kind },
- colon_span: None,
- }
- }));
- debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
-
- let opaque_ty_item = hir::OpaqueTy {
- generics: this.arena.alloc(hir::Generics {
- params: generic_params,
- predicates: &[],
- has_where_clause_predicates: false,
- where_clause_span: this.lower_span(span),
- span: this.lower_span(span),
- }),
- bounds: arena_vec![this; future_bound],
- origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
- };
+ hir::GenericParam {
+ hir_id,
+ name,
+ span: lifetime.ident.span,
+ pure_wrt_drop: false,
+ kind: hir::GenericParamKind::Lifetime { kind },
+ colon_span: None,
+ }
+ },
+ ));
+ debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
+
+ let opaque_ty_item = hir::OpaqueTy {
+ generics: this.arena.alloc(hir::Generics {
+ params: generic_params,
+ predicates: &[],
+ has_where_clause_predicates: false,
+ where_clause_span: this.lower_span(span),
+ span: this.lower_span(span),
+ }),
+ bounds: arena_vec![this; future_bound],
+ origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+ };
- trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
- this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+ trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
+ this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+ })
});
// As documented above, we need to create the lifetime
//
// For the "output" lifetime parameters, we just want to
// generate `'_`.
- let generic_args =
- self.arena.alloc_from_iter(captures.into_iter().map(|(_, (span, _, p_name, res))| {
+ let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
+ |(_, lifetime, res)| {
let id = self.next_node_id();
- let ident = Ident::new(p_name.ident().name, span);
+ let span = lifetime.ident.span;
+
+ let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
+ Ident::with_dummy_span(kw::UnderscoreLifetime)
+ } else {
+ lifetime.ident
+ };
+
+ let res = res.unwrap_or(
+ self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
+ );
let l = self.new_named_lifetime_with_res(id, span, ident, res);
hir::GenericArg::Lifetime(l)
- }));
+ },
+ ));
// Create the `Foo<...>` reference itself. Note that the `type
// Foo = impl Trait` is, internally, created as a child of the
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
let span = self.lower_span(l.ident.span);
let ident = self.lower_ident(l.ident);
- let res = self.resolver.get_lifetime_res(l.id).unwrap_or(LifetimeRes::Error);
- self.new_named_lifetime_with_res(l.id, span, ident, res)
+ self.new_named_lifetime(l.id, l.id, span, ident)
}
#[tracing::instrument(level = "debug", skip(self))]
ident: Ident,
res: LifetimeRes,
) -> hir::Lifetime {
- debug!(?self.captured_lifetimes);
let name = match res {
- LifetimeRes::Param { mut param, binder } => {
+ LifetimeRes::Param { param, .. } => {
let p_name = ParamName::Plain(ident);
- if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
- if !captured_lifetimes.binders_to_ignore.contains(&binder) {
- match captured_lifetimes.captures.entry(param) {
- Entry::Occupied(o) => param = self.local_def_id(o.get().1),
- Entry::Vacant(v) => {
- let p_id = self.next_node_id();
- let p_def_id = self.create_def(
- captured_lifetimes.parent_def_id,
- p_id,
- DefPathData::LifetimeNs(p_name.ident().name),
- );
-
- v.insert((span, p_id, p_name, res));
- param = p_def_id;
- }
- }
- }
+ let param = self.resolver.get_remapped_def_id(param);
- self.captured_lifetimes = Some(captured_lifetimes);
- }
hir::LifetimeName::Param(param, p_name)
}
- LifetimeRes::Fresh { param, binder } => {
+ LifetimeRes::Fresh { param, .. } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
- let mut param = self.local_def_id(param);
- if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
- if !captured_lifetimes.binders_to_ignore.contains(&binder) {
- match captured_lifetimes.captures.entry(param) {
- Entry::Occupied(o) => param = self.local_def_id(o.get().1),
- Entry::Vacant(v) => {
- let p_id = self.next_node_id();
- let p_def_id = self.create_def(
- captured_lifetimes.parent_def_id,
- p_id,
- DefPathData::LifetimeNs(kw::UnderscoreLifetime),
- );
-
- v.insert((span, p_id, ParamName::Fresh, res));
- param = p_def_id;
- }
- }
- }
+ let param = self.local_def_id(param);
- self.captured_lifetimes = Some(captured_lifetimes);
- }
hir::LifetimeName::Param(param, ParamName::Fresh)
}
LifetimeRes::Infer => hir::LifetimeName::Infer,
LifetimeRes::Error => hir::LifetimeName::Error,
res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
};
- debug!(?self.captured_lifetimes);
+
debug!(?name);
hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
}
+ #[tracing::instrument(level = "debug", skip(self))]
+ fn new_named_lifetime(
+ &mut self,
+ id: NodeId,
+ new_id: NodeId,
+ span: Span,
+ ident: Ident,
+ ) -> hir::Lifetime {
+ let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
+ self.new_named_lifetime_with_res(new_id, span, ident, res)
+ }
+
fn lower_generic_params_mut<'s>(
&'s mut self,
params: &'s [GenericParam],
p: &PolyTraitRef,
itctx: ImplTraitContext,
) -> hir::PolyTraitRef<'hir> {
- self.with_lifetime_binder(
- p.trait_ref.ref_id,
- &p.bound_generic_params,
- |this, bound_generic_params| {
- let trait_ref = this.lower_trait_ref(&p.trait_ref, itctx);
- hir::PolyTraitRef { bound_generic_params, trait_ref, span: this.lower_span(p.span) }
- },
- )
+ let bound_generic_params =
+ self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
+ let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
+ hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
}
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
// Add a definition for the in-band `Param`.
let def_id = self.local_def_id(node_id);
- let hir_bounds = self.lower_param_bounds(bounds, ImplTraitContext::Universal);
// Set the name to `impl Bound1 + Bound2`.
let param = hir::GenericParam {
hir_id: self.lower_node_id(node_id),
ident,
node_id,
&GenericParamKind::Type { default: None },
- hir_bounds,
+ bounds,
+ ImplTraitContext::Universal,
hir::PredicateOrigin::ImplTrait,
);
--- /dev/null
+use super::ResolverAstLoweringExt;
+use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
+use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
+use rustc_hir::def::LifetimeRes;
+use rustc_middle::span_bug;
+use rustc_middle::ty::ResolverAstLowering;
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::Span;
+
+struct LifetimeCollectVisitor<'ast> {
+ resolver: &'ast ResolverAstLowering,
+ current_binders: Vec<NodeId>,
+ collected_lifetimes: Vec<Lifetime>,
+}
+
+impl<'ast> LifetimeCollectVisitor<'ast> {
+ fn new(resolver: &'ast ResolverAstLowering) -> Self {
+ Self { resolver, current_binders: Vec::new(), collected_lifetimes: Vec::new() }
+ }
+
+ fn record_lifetime_use(&mut self, lifetime: Lifetime) {
+ match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
+ LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
+ if !self.current_binders.contains(&binder) {
+ if !self.collected_lifetimes.contains(&lifetime) {
+ self.collected_lifetimes.push(lifetime);
+ }
+ }
+ }
+ LifetimeRes::Static | LifetimeRes::Error => {
+ if !self.collected_lifetimes.contains(&lifetime) {
+ self.collected_lifetimes.push(lifetime);
+ }
+ }
+ LifetimeRes::Infer => {}
+ res => {
+ let bug_msg = format!(
+ "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+ res, lifetime.ident, lifetime.ident.span
+ );
+ span_bug!(lifetime.ident.span, "{}", bug_msg);
+ }
+ }
+ }
+
+ /// This collect lifetimes that are elided, for nodes like `Foo<T>` where there are no explicit
+ /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids
+ /// in the list start..end.
+ fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) {
+ if let Some(LifetimeRes::ElidedAnchor { start, end }) =
+ self.resolver.get_lifetime_res(node_id)
+ {
+ for i in start..end {
+ let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) };
+ self.record_lifetime_use(lifetime);
+ }
+ }
+ }
+}
+
+impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
+ fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) {
+ self.record_lifetime_use(*lifetime);
+ }
+
+ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
+ self.record_elided_anchor(path_segment.id, path_span);
+ visit::walk_path_segment(self, path_span, path_segment);
+ }
+
+ fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
+ self.current_binders.push(t.trait_ref.ref_id);
+
+ visit::walk_poly_trait_ref(self, t);
+
+ self.current_binders.pop();
+ }
+
+ fn visit_ty(&mut self, t: &'ast Ty) {
+ match t.kind {
+ TyKind::BareFn(_) => {
+ self.current_binders.push(t.id);
+ visit::walk_ty(self, t);
+ self.current_binders.pop();
+ }
+ TyKind::Rptr(None, _) => {
+ self.record_elided_anchor(t.id, t.span);
+ visit::walk_ty(self, t);
+ }
+ _ => {
+ visit::walk_ty(self, t);
+ }
+ }
+ }
+}
+
+pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
+ let mut visitor = LifetimeCollectVisitor::new(resolver);
+ visitor.visit_fn_ret_ty(ret_ty);
+ visitor.collected_lifetimes
+}
+
+pub fn lifetimes_in_bounds(
+ resolver: &ResolverAstLowering,
+ bounds: &GenericBounds,
+) -> Vec<Lifetime> {
+ let mut visitor = LifetimeCollectVisitor::new(resolver);
+ for bound in bounds {
+ visitor.visit_param_bound(bound, BoundKind::Bound);
+ }
+ visitor.collected_lifetimes
+}
use rustc_ast::*;
use rustc_ast_pretty::pprust::{self, State};
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{
- error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
-};
+use rustc_errors::{error_code, pluralize, struct_span_err, Applicability, Diagnostic};
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::{
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
ctx: &str,
msg: &str,
sugg: &str,
- help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>),
+ help: impl FnOnce(&mut Diagnostic),
) {
let source_map = self.session.source_map();
let end = source_map.end_point(sp);
let msg = "free function without a body";
let ext = sig.header.ext;
- let f = |e: &mut DiagnosticBuilder<'_, _>| {
+ let f = |e: &mut Diagnostic| {
if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
{
let start_suggestion = if let Extern::Explicit(abi, _) = ext {
visit::walk_param_bound(self, bound)
}
- fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
+ fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
self.check_late_bound_lifetime_defs(&t.bound_generic_params);
- visit::walk_poly_trait_ref(self, t, m);
+ visit::walk_poly_trait_ref(self, t);
}
fn visit_variant_data(&mut self, s: &'a VariantData) {
self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
}
- fn visit_enum_def(
- &mut self,
- enum_definition: &'a EnumDef,
- generics: &'a Generics,
- item_id: NodeId,
- _: Span,
- ) {
- self.with_banned_assoc_ty_bound(|this| {
- visit::walk_enum_def(this, enum_definition, generics, item_id)
- })
+ fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
+ self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
}
fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd, VariantData};
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{Features, GateIssue};
use rustc_session::parse::{feature_err, feature_err_issue};
|| attr.has_name(sym::stable)
|| attr.has_name(sym::rustc_const_unstable)
|| attr.has_name(sym::rustc_const_stable)
+ || attr.has_name(sym::rustc_default_body_unstable)
{
struct_span_err!(
self.sess,
}
}
+ fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
+ if let ast::StmtKind::Semi(expr) = &stmt.kind
+ && let ast::ExprKind::Assign(lhs, _, _) = &expr.kind
+ && let ast::ExprKind::Type(..) = lhs.kind
+ && self.sess.parse_sess.span_diagnostic.err_count() == 0
+ && !self.features.type_ascription
+ && !lhs.span.allows_unstable(sym::type_ascription)
+ {
+ // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
+ // ascription error, but the likely intention was to write a `let` statement. (#78907).
+ feature_err_issue(
+ &self.sess.parse_sess,
+ sym::type_ascription,
+ lhs.span,
+ GateIssue::Language,
+ "type ascription is experimental",
+ ).span_suggestion_verbose(
+ lhs.span.shrink_to_lo(),
+ "you might have meant to introduce a new binding",
+ "let ".to_string(),
+ Applicability::MachineApplicable,
+ ).emit();
+ }
+ visit::walk_stmt(self, stmt);
+ }
+
fn visit_expr(&mut self, e: &'a ast::Expr) {
match e.kind {
ast::ExprKind::Box(_) => {
// checks if `#![feature]` has been used to enable any lang feature
// does not check the same for lib features unless there's at least one
// declared lang feature
- use rustc_errors::Applicability;
-
if !sess.opts.unstable_features.is_nightly_build() {
let lang_features = &sess.features_untracked().declared_lang_features;
if lang_features.len() == 0 {
self.count += 1;
walk_param_bound(self, bounds)
}
- fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) {
+ fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) {
self.count += 1;
- walk_poly_trait_ref(self, t, m)
+ walk_poly_trait_ref(self, t)
}
fn visit_variant_data(&mut self, s: &VariantData) {
self.count += 1;
self.count += 1;
walk_field_def(self, s)
}
- fn visit_enum_def(
- &mut self,
- enum_definition: &EnumDef,
- generics: &Generics,
- item_id: NodeId,
- _: Span,
- ) {
+ fn visit_enum_def(&mut self, enum_definition: &EnumDef) {
self.count += 1;
- walk_enum_def(self, enum_definition, generics, item_id)
+ walk_enum_def(self, enum_definition)
}
fn visit_variant(&mut self, v: &Variant) {
self.count += 1;
fn print_string(&mut self, st: &str, style: ast::StrStyle) {
let st = match style {
- ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
+ ast::StrStyle::Cooked => format!("\"{}\"", st.escape_debug()),
ast::StrStyle::Raw(n) => {
format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
}
self.print_call_post(args)
}
- fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
- let base_args = &args[1..];
- self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+ fn print_expr_method_call(
+ &mut self,
+ segment: &ast::PathSegment,
+ receiver: &ast::Expr,
+ base_args: &[P<ast::Expr>],
+ ) {
+ self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX);
self.word(".");
self.print_ident(segment.ident);
if let Some(ref args) = segment.args {
ast::ExprKind::Call(ref func, ref args) => {
self.print_expr_call(func, &args);
}
- ast::ExprKind::MethodCall(ref segment, ref args, _) => {
- self.print_expr_method_call(segment, &args);
+ ast::ExprKind::MethodCall(ref segment, ref receiver, ref args, _) => {
+ self.print_expr_method_call(segment, &receiver, &args);
}
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
self.print_expr_binary(op, lhs, rhs);
pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) {
match vis.kind {
ast::VisibilityKind::Public => self.word_nbsp("pub"),
- ast::VisibilityKind::Restricted { ref path, .. } => {
+ ast::VisibilityKind::Restricted { ref path, id: _, shorthand } => {
let path = Self::to_string(|s| s.print_path(path, false, 0));
- if path == "crate" || path == "self" || path == "super" {
+ if shorthand && (path == "crate" || path == "self" || path == "super") {
self.word_nbsp(format!("pub({})", path))
} else {
self.word_nbsp(format!("pub(in {})", path))
}
}
+/// Represents the `#[rustc_default_body_unstable]` attribute.
+#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(HashStable_Generic)]
+pub struct DefaultBodyStability {
+ pub level: StabilityLevel,
+ pub feature: Symbol,
+}
+
/// The available stability levels.
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
#[derive(HashStable_Generic)]
sess: &Session,
attrs: &[Attribute],
item_sp: Span,
-) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) {
+) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
+{
find_stability_generic(sess, attrs.iter(), item_sp)
}
sess: &Session,
attrs_iter: I,
item_sp: Span,
-) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>)
+) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
where
I: Iterator<Item = &'a Attribute>,
{
let mut stab: Option<(Stability, Span)> = None;
let mut const_stab: Option<(ConstStability, Span)> = None;
+ let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
let mut promotable = false;
let mut allowed_through_unstable_modules = false;
sym::stable,
sym::rustc_promotable,
sym::rustc_allowed_through_unstable_modules,
+ sym::rustc_default_body_unstable,
]
.iter()
.any(|&s| attr.has_name(s))
let meta_name = meta.name_or_empty();
match meta_name {
- sym::rustc_const_unstable | sym::unstable => {
+ sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
if meta_name == sym::unstable && stab.is_some() {
handle_errors(
&sess.parse_sess,
AttrError::MultipleStabilityLevels,
);
break;
+ } else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
+ handle_errors(
+ &sess.parse_sess,
+ attr.span,
+ AttrError::MultipleStabilityLevels,
+ );
+ break;
}
let mut feature = None;
};
if sym::unstable == meta_name {
stab = Some((Stability { level, feature }, attr.span));
- } else {
+ } else if sym::rustc_const_unstable == meta_name {
const_stab = Some((
ConstStability { level, feature, promotable: false },
attr.span,
));
+ } else if sym::rustc_default_body_unstable == meta_name {
+ body_stab =
+ Some((DefaultBodyStability { level, feature }, attr.span));
+ } else {
+ unreachable!("Unknown stability attribute {meta_name}");
}
}
(None, _, _) => {
}
}
- (stab, const_stab)
+ (stab, const_stab, body_stab)
}
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
};
-use rustc_middle::ty::{
- self, subst::Subst, suggest_constraining_type_params, EarlyBinder, PredicateKind, Ty,
-};
+use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use super::{
explain_borrow::{BorrowExplanation, LaterUseKind},
- IncludingDowncast, RegionName, RegionNameSource, UseSpans,
+ DescribePlaceOpt, RegionName, RegionNameSource, UseSpans,
};
#[derive(Debug)]
span,
desired_action.as_noun(),
partially_str,
- self.describe_place_with_options(moved_place, IncludingDowncast(true)),
+ self.describe_place_with_options(
+ moved_place,
+ DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+ ),
);
let reinit_spans = maybe_reinitialized_locations
}
}
- let opt_name =
- self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
+ let opt_name = self.describe_place_with_options(
+ place.as_ref(),
+ DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+ );
let note_msg = match opt_name {
Some(ref name) => format!("`{}`", name),
None => "value".to_owned(),
}
}
- let (name, desc) =
- match self.describe_place_with_options(moved_place, IncludingDowncast(true)) {
- Some(name) => (format!("`{name}`"), format!("`{name}` ")),
- None => ("the variable".to_string(), String::new()),
- };
- let path = match self.describe_place_with_options(used_place, IncludingDowncast(true)) {
+ let (name, desc) = match self.describe_place_with_options(
+ moved_place,
+ DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+ ) {
+ Some(name) => (format!("`{name}`"), format!("`{name}` ")),
+ None => ("the variable".to_string(), String::new()),
+ };
+ let path = match self.describe_place_with_options(
+ used_place,
+ DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+ ) {
Some(name) => format!("`{name}`"),
None => "value".to_string(),
};
fn suggest_borrow_fn_like(
&self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ err: &mut Diagnostic,
ty: Ty<'tcx>,
move_sites: &[MoveSite],
value_name: &str,
let tcx = self.infcx.tcx;
// Find out if the predicates show that the type is a Fn or FnMut
- let find_fn_kind_from_did = |predicates: &[(ty::Predicate<'tcx>, Span)], substs| {
- predicates.iter().find_map(|(pred, _)| {
- let pred = if let Some(substs) = substs {
- EarlyBinder(*pred).subst(tcx, substs).kind().skip_binder()
- } else {
- pred.kind().skip_binder()
- };
- if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty {
+ let find_fn_kind_from_did =
+ |predicates: ty::EarlyBinder<&[(ty::Predicate<'tcx>, Span)]>, substs| {
+ predicates.0.iter().find_map(|(pred, _)| {
+ let pred = if let Some(substs) = substs {
+ predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder()
+ } else {
+ pred.kind().skip_binder()
+ };
+ if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty {
if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
return Some(hir::Mutability::Not);
} else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
return Some(hir::Mutability::Mut);
}
}
- None
- })
- };
+ None
+ })
+ };
// If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
// borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
// borrowed variants in a function body when we see a move error.
let borrow_level = match ty.kind() {
ty::Param(_) => find_fn_kind_from_did(
- tcx.explicit_predicates_of(self.mir_def_id().to_def_id()).predicates,
+ tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id())
+ .map_bound(|p| p.predicates),
None,
),
ty::Opaque(did, substs) => {
- find_fn_kind_from_did(tcx.explicit_item_bounds(*did), Some(*substs))
+ find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*did), Some(*substs))
}
ty::Closure(_, substs) => match substs.as_closure().kind() {
ty::ClosureKind::Fn => Some(hir::Mutability::Not),
true
}
- fn suggest_adding_copy_bounds(
- &self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
- ty: Ty<'tcx>,
- span: Span,
- ) {
+ fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
let tcx = self.infcx.tcx;
let generics = tcx.generics_of(self.mir_def_id());
self.errors.push((
e.span,
format!(
- "if the `for` loop runs 0 times, {} is not initialized ",
+ "if the `for` loop runs 0 times, {} is not initialized",
self.name
),
));
use rustc_const_eval::util::{call_kind, CallDesugaringKind};
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
-use rustc_hir::def::Namespace;
+use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::GeneratorKind;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
use rustc_span::def_id::LocalDefId;
-use rustc_span::{symbol::sym, Span, DUMMY_SP};
+use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
pub(crate) use region_name::{RegionName, RegionNameSource};
pub(crate) use rustc_const_eval::util::CallKind;
-pub(super) struct IncludingDowncast(pub(super) bool);
+pub(super) struct DescribePlaceOpt {
+ pub including_downcast: bool,
+
+ /// Enable/Disable tuple fields.
+ /// For example `x` tuple. if it's `true` `x.0`. Otherwise `x`
+ pub including_tuple_field: bool,
+}
+
+pub(super) struct IncludingTupleField(pub(super) bool);
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
/// End-user visible description of `place` if one can be found.
/// If the place is a temporary for instance, `None` will be returned.
pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
- self.describe_place_with_options(place_ref, IncludingDowncast(false))
+ self.describe_place_with_options(
+ place_ref,
+ DescribePlaceOpt { including_downcast: false, including_tuple_field: true },
+ )
}
/// End-user visible description of `place` if one can be found. If the place is a temporary
pub(super) fn describe_place_with_options(
&self,
place: PlaceRef<'tcx>,
- including_downcast: IncludingDowncast,
+ opt: DescribePlaceOpt,
) -> Option<String> {
let local = place.local;
let mut autoderef_index = None;
}
}
}
- ProjectionElem::Downcast(..) if including_downcast.0 => return None,
+ ProjectionElem::Downcast(..) if opt.including_downcast => return None,
ProjectionElem::Downcast(..) => (),
ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here.
let field_name = self.describe_field(
PlaceRef { local, projection: place.projection.split_at(index).0 },
*field,
+ IncludingTupleField(opt.including_tuple_field),
);
- buf.push('.');
- buf.push_str(&field_name);
+ if let Some(field_name_str) = field_name {
+ buf.push('.');
+ buf.push_str(&field_name_str);
+ }
}
}
ProjectionElem::Index(index) => {
ok.ok().map(|_| buf)
}
+ fn describe_name(&self, place: PlaceRef<'tcx>) -> Option<Symbol> {
+ for elem in place.projection.into_iter() {
+ match elem {
+ ProjectionElem::Downcast(Some(name), _) => {
+ return Some(*name);
+ }
+ _ => {}
+ }
+ }
+ None
+ }
+
/// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
/// a name, or its name was generated by the compiler, then `Err` is returned
fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
}
/// End-user visible description of the `field`nth field of `base`
- fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
+ fn describe_field(
+ &self,
+ place: PlaceRef<'tcx>,
+ field: Field,
+ including_tuple_field: IncludingTupleField,
+ ) -> Option<String> {
let place_ty = match place {
PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
},
};
- self.describe_field_from_ty(place_ty.ty, field, place_ty.variant_index)
+ self.describe_field_from_ty(
+ place_ty.ty,
+ field,
+ place_ty.variant_index,
+ including_tuple_field,
+ )
}
/// End-user visible description of the `field_index`nth field of `ty`
ty: Ty<'_>,
field: Field,
variant_index: Option<VariantIdx>,
- ) -> String {
+ including_tuple_field: IncludingTupleField,
+ ) -> Option<String> {
if ty.is_box() {
// If the type is a box, the field is described from the boxed type
- self.describe_field_from_ty(ty.boxed_ty(), field, variant_index)
+ self.describe_field_from_ty(ty.boxed_ty(), field, variant_index, including_tuple_field)
} else {
match *ty.kind() {
ty::Adt(def, _) => {
} else {
def.non_enum_variant()
};
- variant.fields[field.index()].name.to_string()
+ if !including_tuple_field.0 && variant.ctor_kind == CtorKind::Fn {
+ return None;
+ }
+ Some(variant.fields[field.index()].name.to_string())
}
- ty::Tuple(_) => field.index().to_string(),
+ ty::Tuple(_) => Some(field.index().to_string()),
ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
- self.describe_field_from_ty(ty, field, variant_index)
+ self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
}
ty::Array(ty, _) | ty::Slice(ty) => {
- self.describe_field_from_ty(ty, field, variant_index)
+ self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
}
ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
// We won't be borrowck'ing here if the closure came from another crate,
.unwrap()
.get_root_variable();
- self.infcx.tcx.hir().name(var_id).to_string()
+ Some(self.infcx.tcx.hir().name(var_id).to_string())
}
_ => {
// Might need a revision when the fields in trait RFC is implemented
};
use rustc_span::Span;
-use crate::diagnostics::UseSpans;
+use crate::diagnostics::{DescribePlaceOpt, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
}
_ => {
let source = self.borrowed_content_source(deref_base);
- match (self.describe_place(move_place.as_ref()), source.describe_for_named_place())
- {
- (Some(place_desc), Some(source_desc)) => self.cannot_move_out_of(
+ let move_place_ref = move_place.as_ref();
+ match (
+ self.describe_place_with_options(
+ move_place_ref,
+ DescribePlaceOpt {
+ including_downcast: false,
+ including_tuple_field: false,
+ },
+ ),
+ self.describe_name(move_place_ref),
+ source.describe_for_named_place(),
+ ) {
+ (Some(place_desc), Some(name), Some(source_desc)) => self.cannot_move_out_of(
+ span,
+ &format!("`{place_desc}` as enum variant `{name}` which is behind a {source_desc}"),
+ ),
+ (Some(place_desc), Some(name), None) => self.cannot_move_out_of(
+ span,
+ &format!("`{place_desc}` as enum variant `{name}`"),
+ ),
+ (Some(place_desc), _, Some(source_desc)) => self.cannot_move_out_of(
span,
&format!("`{place_desc}` which is behind a {source_desc}"),
),
- (_, _) => self.cannot_move_out_of(
+ (_, _, _) => self.cannot_move_out_of(
span,
&source.describe_for_unnamed_place(self.infcx.tcx),
),
fn maybe_suggest_constrain_dyn_trait_impl(
&self,
- diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ diag: &mut Diagnostic,
f: Region<'tcx>,
o: Region<'tcx>,
category: &ConstraintCategory<'tcx>,
hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
..
- }) => (tcx.sess.source_map().end_point(fn_decl_span)),
+ }) => tcx.sess.source_map().end_point(fn_decl_span),
_ => self.body.span,
};
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{Span, DUMMY_SP};
self.add_outlives(r1_vid, r2_vid);
}
- GenericArgKind::Type(mut t1) => {
+ GenericArgKind::Type(t1) => {
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
- // Placeholder regions need to be converted now because it may
- // create new region variables, which can't be done later when
- // verifying these bounds.
- if t1.has_placeholders() {
- t1 = tcx.fold_regions(t1, |r, _| match *r {
- ty::RePlaceholder(placeholder) => {
- self.constraints.placeholder_region(self.infcx, placeholder)
- }
- _ => r,
- });
- }
-
TypeOutlives::new(
&mut *self,
tcx,
}
}
+ /// Placeholder regions need to be converted eagerly because it may
+ /// create new region variables, which we must not do when verifying
+ /// our region bounds.
+ ///
+ /// FIXME: This should get removed once higher ranked region obligations
+ /// are dealt with during trait solving.
+ fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+ if value.has_placeholders() {
+ self.tcx.fold_regions(value, |r, _| match *r {
+ ty::RePlaceholder(placeholder) => {
+ self.constraints.placeholder_region(self.infcx, placeholder)
+ }
+ _ => r,
+ })
+ } else {
+ value
+ }
+ }
+
fn verify_to_type_test(
&mut self,
generic_kind: GenericKind<'tcx>,
verify_bound: VerifyBound<'tcx>,
) -> TypeTest<'tcx> {
let lower_bound = self.to_region_vid(region);
-
TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
}
a: ty::Region<'tcx>,
bound: VerifyBound<'tcx>,
) {
+ let kind = self.replace_placeholders_with_nll(kind);
+ let bound = self.replace_placeholders_with_nll(bound);
let type_test = self.verify_to_type_test(kind, a, bound);
self.add_type_test(type_test);
}
let constraint_sets: Vec<_> = unnormalized_input_output_tys
.flat_map(|ty| {
debug!("build: input_or_output={:?}", ty);
- // We only add implied bounds for the normalized type as the unnormalized
- // type may not actually get checked by the caller.
- //
- // Can otherwise be unsound, see #91068.
+ // We add implied bounds from both the unnormalized and normalized ty.
+ // See issue #87748
+ let constraints_implied1 = self.add_implied_bounds(ty);
let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
// }
// ```
// Both &Self::Bar and &() are WF
- let constraints_implied = self.add_implied_bounds(norm_ty);
+ let constraints_implied2 =
+ if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
normalized_inputs_and_output.push(norm_ty);
- constraints1.into_iter().chain(constraints_implied)
+ constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
})
.collect();
))
});
debug!(?sig);
- let sig = self.normalize(sig, term_location);
- self.check_call_dest(body, term, &sig, *destination, target, term_location);
-
+ // IMPORTANT: We have to prove well formed for the function signature before
+ // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
+ // get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
+ //
+ // Normalization results in a well formed type if the input is well formed, so we
+ // don't have to check it twice.
+ //
+ // See #91068 for an example.
self.prove_predicates(
sig.inputs_and_output
.iter()
term_location.to_locations(),
ConstraintCategory::Boring,
);
+ let sig = self.normalize(sig, term_location);
+ self.check_call_dest(body, term, &sig, *destination, target, term_location);
// The ordinary liveness rules will ensure that all
// regions in the type of the callee are live here. We
);
}
+ // Now equate closure substs to regions inherited from `typeck_root_def_id`. Fixes #98589.
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.body.source.def_id());
+ let typeck_root_substs = ty::InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+
+ let parent_substs = match tcx.def_kind(def_id) {
+ DefKind::Closure => substs.as_closure().parent_substs(),
+ DefKind::Generator => substs.as_generator().parent_substs(),
+ DefKind::InlineConst => substs.as_inline_const().parent_substs(),
+ other => bug!("unexpected item {:?}", other),
+ };
+ let parent_substs = tcx.mk_substs(parent_substs.iter());
+
+ assert_eq!(typeck_root_substs.len(), parent_substs.len());
+ if let Err(_) = self.eq_substs(
+ typeck_root_substs,
+ parent_substs,
+ location.to_locations(),
+ ConstraintCategory::BoringNoLocation,
+ ) {
+ span_mirbug!(
+ self,
+ def_id,
+ "could not relate closure to parent {:?} != {:?}",
+ typeck_root_substs,
+ parent_substs
+ );
+ }
+
tcx.predicates_of(def_id).instantiate(tcx, substs)
}
.relate(a, b)?;
Ok(())
}
+
+ /// Add sufficient constraints to ensure `a == b`. See also [Self::relate_types].
+ pub(super) fn eq_substs(
+ &mut self,
+ a: ty::SubstsRef<'tcx>,
+ b: ty::SubstsRef<'tcx>,
+ locations: Locations,
+ category: ConstraintCategory<'tcx>,
+ ) -> Fallible<()> {
+ TypeRelating::new(
+ self.infcx,
+ NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()),
+ ty::Variance::Invariant,
+ )
+ .relate(a, b)?;
+ Ok(())
+ }
}
struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
} else if !is_global_asm && p.eat_keyword(sym::nostack) {
try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
+ } else if !is_global_asm && p.eat_keyword(sym::may_unwind) {
+ try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
} else if p.eat_keyword(sym::att_syntax) {
try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
} else if p.eat_keyword(kw::Raw) {
try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
- } else if p.eat_keyword(sym::may_unwind) {
- try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
} else {
return p.unexpected();
}
let span = arg_spans.next().unwrap_or(template_sp);
let operand_idx = match arg.position {
- parse::ArgumentIs(idx, _) | parse::ArgumentImplicitlyIs(idx) => {
+ parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
if idx >= args.operands.len()
|| named_pos.contains_key(&idx)
|| args.reg_args.contains(&idx)
Some(idx)
}
}
- parse::ArgumentNamed(name, span) => {
+ parse::ArgumentNamed(name) => {
match args.named_args.get(&Symbol::intern(name)) {
Some(&idx) => Some(idx),
None => {
let msg = format!("there is no argument named `{}`", name);
+ let span = arg.position_span;
ecx.struct_span_err(
template_span
.from_inner(InnerSpan::new(span.start, span.end)),
self.manage_cond_expr(prefix);
self.manage_cond_expr(suffix);
}
- ExprKind::MethodCall(_, ref mut local_exprs, _) => {
- for local_expr in local_exprs.iter_mut().skip(1) {
+ ExprKind::MethodCall(_, _,ref mut local_exprs, _) => {
+ for local_expr in local_exprs.iter_mut() {
self.manage_cond_expr(local_expr);
}
}
id: DUMMY_NODE_ID,
ident: Ident::new(sym::try_capture, self.span),
},
- vec![
- expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
- expr_addr_of_mut(
- self.cx,
- self.span,
- self.cx.expr_path(Path::from_ident(capture)),
- ),
- ],
+ expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
+ vec![expr_addr_of_mut(
+ self.cx,
+ self.span,
+ self.cx.expr_path(Path::from_ident(capture)),
+ )],
self.span,
))
.add_trailing_semicolon();
fn expr_method_call(
cx: &ExtCtxt<'_>,
path: PathSegment,
+ receiver: P<Expr>,
args: Vec<P<Expr>>,
span: Span,
) -> P<Expr> {
- cx.expr(span, ExprKind::MethodCall(path, args, span))
+ cx.expr(span, ExprKind::MethodCall(path, receiver, args, span))
}
fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
}
// 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,
- ) {
+ fn visit_poly_trait_ref(&mut self, trait_ref: &'a ast::PolyTraitRef) {
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);
+ visit::walk_poly_trait_ref(self, trait_ref);
self.bound_generic_params_stack.truncate(stack_len);
}
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
+use rustc_parse_format::Count;
use std::borrow::Cow;
use std::collections::hash_map::Entry;
replacement: Symbol,
/// The span for the positional named argument (so the lint can point a message to it)
positional_named_arg_span: Span,
+ has_formatting: bool,
}
impl PositionalNamedArg {
- /// Determines what span to replace with the name of the named argument
- fn get_span_to_replace(&self, cx: &Context<'_, '_>) -> Option<Span> {
+ /// Determines:
+ /// 1) span to be replaced with the name of the named argument and
+ /// 2) span to be underlined for error messages
+ fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option<Span>, Option<Span>) {
if let Some(inner_span) = &self.inner_span_to_replace {
- return Some(
- cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }),
- );
+ let span =
+ cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end });
+ (Some(span), Some(span))
} else if self.ty == PositionalNamedArgType::Arg {
- // In the case of a named argument whose position is implicit, there will not be a span
- // to replace. Instead, we insert the name after the `{`, which is the first character
- // of arg_span.
- return cx
- .arg_spans
- .get(self.cur_piece)
- .map(|arg_span| arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo());
+ // In the case of a named argument whose position is implicit, if the argument *has*
+ // formatting, there will not be a span to replace. Instead, we insert the name after
+ // the `{`, which will be the first character of arg_span. If the argument does *not*
+ // have formatting, there may or may not be a span to replace. This is because
+ // whitespace is allowed in arguments without formatting (such as `format!("{ }", 1);`)
+ // but is not allowed in arguments with formatting (an error will be generated in cases
+ // like `format!("{ :1.1}", 1.0f32);`.
+ // For the message span, if there is formatting, we want to use the opening `{` and the
+ // next character, which will the `:` indicating the start of formatting. If there is
+ // not any formatting, we want to underline the entire span.
+ cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+ if self.has_formatting {
+ (
+ Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
+ Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
+ )
+ } else {
+ let replace_start = arg_span.lo() + BytePos(1);
+ let replace_end = arg_span.hi() - BytePos(1);
+ let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
+ (Some(to_replace), Some(*arg_span))
+ }
+ })
+ } else {
+ (None, None)
}
-
- None
}
}
cur_piece: usize,
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
names: &FxHashMap<Symbol, (usize, Span)>,
+ has_formatting: bool,
) {
let start_of_named_args = total_args_length - names.len();
if current_positional_arg >= start_of_named_args {
- self.maybe_push(format_argument_index, ty, cur_piece, inner_span_to_replace, names)
+ self.maybe_push(
+ format_argument_index,
+ ty,
+ cur_piece,
+ inner_span_to_replace,
+ names,
+ has_formatting,
+ )
}
}
cur_piece: usize,
inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
names: &FxHashMap<Symbol, (usize, Span)>,
+ has_formatting: bool,
) {
let named_arg = names
.iter()
inner_span_to_replace,
replacement,
positional_named_arg_span,
+ has_formatting,
});
}
}
unused_names_lint: PositionalNamedArgsLint,
}
+pub struct FormatArg {
+ expr: P<ast::Expr>,
+ named: bool,
+}
+
/// Parses the arguments from the given list of tokens, returning the diagnostic
/// if there's a parse error so we can continue parsing other format!
/// expressions.
ecx: &mut ExtCtxt<'a>,
sp: Span,
tts: TokenStream,
-) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, (usize, Span)>)> {
- let mut args = Vec::<P<ast::Expr>>::new();
+) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, (usize, Span)>)> {
+ let mut args = Vec::<FormatArg>::new();
let mut names = FxHashMap::<Symbol, (usize, Span)>::default();
let mut p = ecx.new_parser_from_tts(tts);
let e = p.parse_expr()?;
if let Some((prev, _)) = names.get(&ident.name) {
ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
- .span_label(args[*prev].span, "previously here")
+ .span_label(args[*prev].expr.span, "previously here")
.span_label(e.span, "duplicate argument")
.emit();
continue;
// args. And remember the names.
let slot = args.len();
names.insert(ident.name, (slot, ident.span));
- args.push(e);
+ args.push(FormatArg { expr: e, named: true });
}
_ => {
let e = p.parse_expr()?;
);
err.span_label(e.span, "positional arguments must be before named arguments");
for pos in names.values() {
- err.span_label(args[pos.0].span, "named argument");
+ err.span_label(args[pos.0].expr.span, "named argument");
}
err.emit();
}
- args.push(e);
+ args.push(FormatArg { expr: e, named: false });
}
}
}
match *p {
parse::String(_) => {}
parse::NextArgument(ref mut arg) => {
- if let parse::ArgumentNamed(s, _) = arg.position {
- arg.position = parse::ArgumentIs(lookup(s), None);
+ if let parse::ArgumentNamed(s) = arg.position {
+ arg.position = parse::ArgumentIs(lookup(s));
}
if let parse::CountIsName(s, _) = arg.format.width {
arg.format.width = parse::CountIsParam(lookup(s));
PositionalNamedArgType::Precision,
);
+ let has_precision = arg.format.precision != Count::CountImplied;
+ let has_width = arg.format.width != Count::CountImplied;
+
// argument second, if it's an implicit positional parameter
// it's written second, so it should come after width/precision.
let pos = match arg.position {
- parse::ArgumentIs(i, arg_end) => {
+ parse::ArgumentIs(i) => {
self.unused_names_lint.maybe_add_positional_named_arg(
i,
self.args.len(),
i,
PositionalNamedArgType::Arg,
self.curpiece,
- arg_end,
+ Some(arg.position_span),
&self.names,
+ has_precision || has_width,
);
Exact(i)
self.curpiece,
None,
&self.names,
+ has_precision || has_width,
);
Exact(i)
}
- parse::ArgumentNamed(s, span) => {
+ parse::ArgumentNamed(s) => {
let symbol = Symbol::intern(s);
+ let span = arg.position_span;
Named(symbol, InnerSpan::new(span.start, span.end))
}
};
self.curpiece,
*inner_span,
&self.names,
+ true,
);
self.verify_arg_type(Exact(i), Count);
}
// track the current argument ourselves.
let i = self.curarg;
self.curarg += 1;
- parse::ArgumentIs(i, None)
+ parse::ArgumentIs(i)
},
+ position_span: arg.position_span,
format: parse::FormatSpec {
fill: arg.format.fill,
align: parse::AlignUnknown,
fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) {
for named_arg in &cx.unused_names_lint.positional_named_args {
- let arg_span = named_arg.get_span_to_replace(cx);
+ let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx);
let msg = format!("named argument `{}` is not used by name", named_arg.replacement);
- let replacement = match named_arg.ty {
- PositionalNamedArgType::Arg => named_arg.replacement.to_string(),
- _ => named_arg.replacement.to_string() + "$",
- };
cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
span: MultiSpan::from_span(named_arg.positional_named_arg_span),
msg: msg.clone(),
node_id: ast::CRATE_NODE_ID,
lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
- diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally(
- arg_span,
- named_arg.positional_named_arg_span,
- replacement,
- ),
+ diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
+ position_sp_to_replace,
+ position_sp_for_msg,
+ named_arg_sp: named_arg.positional_named_arg_span,
+ named_arg_name: named_arg.replacement.to_string(),
+ is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg,
+ },
});
}
}
ecx: &mut ExtCtxt<'_>,
sp: Span,
efmt: P<ast::Expr>,
- args: Vec<P<ast::Expr>>,
+ args: Vec<FormatArg>,
names: FxHashMap<Symbol, (usize, Span)>,
append_newline: bool,
) -> P<ast::Expr> {
e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
}
}
+ if err.should_be_replaced_with_positional_argument {
+ let captured_arg_span =
+ fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
+ let positional_args = args.iter().filter(|arg| !arg.named).collect::<Vec<_>>();
+ if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
+ let span = match positional_args.last() {
+ Some(arg) => arg.expr.span,
+ None => fmt_sp,
+ };
+ e.multipart_suggestion_verbose(
+ "consider using a positional formatting argument instead",
+ vec![
+ (captured_arg_span, positional_args.len().to_string()),
+ (span.shrink_to_hi(), format!(", {}", arg)),
+ ],
+ Applicability::MachineApplicable,
+ );
+ }
+ }
e.emit();
return DummyResult::raw_expr(sp, true);
}
let mut cx = Context {
ecx,
- args,
+ args: args.into_iter().map(|arg| arg.expr).collect(),
num_captured_args: 0,
arg_types,
arg_unique_types,
[[package]]
name = "anyhow"
-version = "1.0.56"
+version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
+checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
[[package]]
name = "ar"
.features
.split(',')
.filter(|v| !v.is_empty() && backend_feature_name(v).is_some())
+ // Drop +atomics-32 feature introduced in LLVM 15.
+ .filter(|v| *v != "+atomics-32" || get_version() >= (15, 0, 0))
.map(String::from),
);
fn add_pre_link_objects(
cmd: &mut dyn Linker,
sess: &Session,
+ flavor: LinkerFlavor,
link_output_kind: LinkOutputKind,
self_contained: bool,
) {
+ // FIXME: we are currently missing some infra here (per-linker-flavor CRT objects),
+ // so Fuchsia has to be special-cased.
let opts = &sess.target;
- let objects =
- if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
+ let empty = Default::default();
+ let objects = if self_contained {
+ &opts.pre_link_objects_fallback
+ } else if !(sess.target.os == "fuchsia" && flavor == LinkerFlavor::Gcc) {
+ &opts.pre_link_objects
+ } else {
+ &empty
+ };
for obj in objects.get(&link_output_kind).iter().copied().flatten() {
cmd.add_object(&get_object_file_path(sess, obj, self_contained));
}
// ------------ Object code and libraries, order-dependent ------------
// Pre-link CRT objects.
- add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+ add_pre_link_objects(cmd, sess, flavor, link_output_kind, crt_objects_fallback);
add_linked_symbol_object(
cmd,
add_link_script(cmd, sess, tmpdir, crate_type);
- if sess.target.os == "fuchsia" && crate_type == CrateType::Executable {
+ if sess.target.os == "fuchsia"
+ && crate_type == CrateType::Executable
+ && flavor != LinkerFlavor::Gcc
+ {
let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
"asan/"
} else {
// be added explicitly if necessary, see the error in `fn link_rlib`) compiled
// as an executable due to `--test`. Use whole-archive implicitly, like before
// the introduction of native lib modifiers.
- || (bundle != Some(false) && sess.opts.test)
+ || (whole_archive == None && bundle != Some(false) && sess.opts.test)
{
cmd.link_whole_staticlib(
name,
let os = &sess.target.os;
let llvm_target = &sess.target.llvm_target;
if sess.target.vendor != "apple"
- || !matches!(os.as_ref(), "ios" | "tvos" | "watchos")
- || flavor != LinkerFlavor::Gcc
+ || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos")
+ || (flavor != LinkerFlavor::Gcc && flavor != LinkerFlavor::Lld(LldFlavor::Ld64))
{
return;
}
+
+ if os == "macos" && flavor != LinkerFlavor::Lld(LldFlavor::Ld64) {
+ return;
+ }
+
let sdk_name = match (arch.as_ref(), os.as_ref()) {
("aarch64", "tvos") => "appletvos",
("x86_64", "tvos") => "appletvsimulator",
("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator",
("aarch64", "watchos") => "watchos",
("arm", "watchos") => "watchos",
+ (_, "macos") => "macosx",
_ => {
sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os));
return;
return;
}
};
- if llvm_target.contains("macabi") {
- cmd.args(&["-target", llvm_target])
- } else {
- let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
- cmd.args(&["-arch", arch_name])
+
+ match flavor {
+ LinkerFlavor::Gcc => {
+ cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
+ }
+ LinkerFlavor::Lld(LldFlavor::Ld64) => {
+ cmd.args(&["-syslibroot", &sdk_root]);
+ }
+ _ => unreachable!(),
}
- cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
}
fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
{
MergeFunctions::Disabled => false,
MergeFunctions::Trampolines | MergeFunctions::Aliases => {
- sess.opts.optimize == config::OptLevel::Default
- || sess.opts.optimize == config::OptLevel::Aggressive
+ use config::OptLevel::*;
+ match sess.opts.optimize {
+ Aggressive | Default | SizeMin | Size => true,
+ Less | No => false,
+ }
}
},
use rustc_middle::traits::Reveal;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, subst::Subst, EarlyBinder, TyCtxt};
+use rustc_middle::ty::{self, subst::Subst, TyCtxt};
use rustc_span::source_map::Span;
use rustc_target::abi::{self, Abi};
use std::borrow::Cow;
"Unexpected DefKind: {:?}",
ecx.tcx.def_kind(cid.instance.def_id())
);
- let layout = ecx.layout_of(EarlyBinder(body.return_ty()).subst(tcx, cid.instance.substs))?;
+ let layout = ecx.layout_of(body.bound_return_ty().subst(tcx, cid.instance.substs))?;
assert!(!layout.is_unsized());
let ret = ecx.allocate(layout, MemoryKind::Stack)?;
/// Gives raw access to the `Allocation`, without bounds or alignment checks.
/// The caller is responsible for calling the access hooks!
+ ///
+ /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead.
fn get_alloc_raw(
&self,
id: AllocId,
Ok(&self.get_alloc_raw(id)?.extra)
}
+ /// Return the `mutability` field of the given allocation.
+ pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> {
+ Ok(self.get_alloc_raw(id)?.mutability)
+ }
+
/// Gives raw mutable access to the `Allocation`, without bounds or alignment checks.
/// The caller is responsible for calling the access hooks!
///
Uninit,
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Immediate, 56);
-
impl<Prov: Provenance> From<ScalarMaybeUninit<Prov>> for Immediate<Prov> {
#[inline(always)]
fn from(val: ScalarMaybeUninit<Prov>) -> Self {
pub layout: TyAndLayout<'tcx>,
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
-
impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
/// Helper function for printing a scalar to a FmtPrinter
Indirect(MemPlace<Prov>),
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Operand, 64);
-
#[derive(Clone, Debug)]
pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
op: Operand<Prov>, // Keep this private; it helps enforce invariants.
pub align: Option<Align>,
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(OpTy<'_>, 88);
-
impl<'tcx, Prov: Provenance> std::ops::Deref for OpTy<'tcx, Prov> {
type Target = Operand<Prov>;
#[inline(always)]
})
}
}
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // These are in alphabetical order, which is easy to maintain.
+ static_assert_size!(Immediate, 56);
+ static_assert_size!(ImmTy<'_>, 72);
+ static_assert_size!(Operand, 64);
+ static_assert_size!(OpTy<'_>, 88);
+}
None,
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MemPlaceMeta, 24);
-
impl<Prov: Provenance> MemPlaceMeta<Prov> {
pub fn unwrap_meta(self) -> Scalar<Prov> {
match self {
pub meta: MemPlaceMeta<Prov>,
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MemPlace, 40);
-
/// A MemPlace with its layout. Constructing it is only possible in this module.
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
pub align: Align,
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64);
-
#[derive(Copy, Clone, Debug)]
pub enum Place<Prov: Provenance = AllocId> {
/// A place referring to a value allocated in the `Memory` system.
Local { frame: usize, local: mir::Local },
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Place, 48);
-
#[derive(Clone, Debug)]
pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
place: Place<Prov>, // Keep this private; it helps enforce invariants.
pub align: Align,
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72);
-
impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> {
type Target = Place<Prov>;
#[inline(always)]
Ok(mplace)
}
}
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // These are in alphabetical order, which is easy to maintain.
+ static_assert_size!(MemPlaceMeta, 24);
+ static_assert_size!(MemPlace, 40);
+ static_assert_size!(MPlaceTy<'_>, 64);
+ static_assert_size!(Place, 48);
+ static_assert_size!(PlaceTy<'_>, 72);
+}
let mut nonconst_call_permission = false;
if let Some(callee_trait) = tcx.trait_of_item(callee)
&& tcx.has_attr(callee_trait, sym::const_trait)
- && Some(callee_trait) == tcx.trait_of_item(caller)
+ && Some(callee_trait) == tcx.trait_of_item(caller.to_def_id())
// Can only call methods when it's `<Self as TheTrait>::f`.
&& tcx.types.self_param == substs.type_at(0)
{
use rustc_errors::ErrorGuaranteed;
use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngine;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::{
- self, FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext,
+ self, ImplSource, Obligation, ObligationCause, SelectionContext,
};
use super::ConstCx;
return false;
}
- // If we successfully found one, then select all of the predicates
- // implied by our const drop impl.
- let mut fcx = FulfillmentContext::new();
- for nested in impl_src.nested_obligations() {
- fcx.register_predicate_obligation(&infcx, nested);
- }
-
// If we had any errors, then it's bad
- !fcx.select_all_or_error(&infcx).is_empty()
+ !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
})
}
where
L: HasLocalDecls<'tcx>,
{
- for (place_base, elem) in place.iter_projections().rev() {
- match elem {
- // encountered a Deref, which is ABI-aligned
- ProjectionElem::Deref => break,
- ProjectionElem::Field(..) => {
- let ty = place_base.ty(local_decls, tcx).ty;
- match ty.kind() {
- ty::Adt(def, _) => return def.repr().pack,
- _ => {}
- }
- }
- _ => {}
- }
- }
-
- None
+ place
+ .iter_projections()
+ .rev()
+ // Stop at `Deref`; standard ABI alignment applies there.
+ .take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref))
+ // Consider the packed alignments at play here...
+ .filter_map(|(base, _elem)| {
+ base.ty(local_decls, tcx).ty.ty_adt_def().and_then(|adt| adt.repr().pack)
+ })
+ // ... and compute their minimum.
+ // The overall smallest alignment is what matters.
+ .min()
}
from_hir_call: bool,
self_arg: Option<Ident>,
) -> CallKind<'tcx> {
- let parent = tcx.opt_associated_item(method_did).and_then(|assoc| match assoc.container {
- AssocItemContainer::ImplContainer(impl_did) => tcx.trait_id_of_impl(impl_did),
- AssocItemContainer::TraitContainer(trait_did) => Some(trait_did),
+ let parent = tcx.opt_associated_item(method_did).and_then(|assoc| {
+ let container_id = assoc.container_id(tcx);
+ match assoc.container {
+ AssocItemContainer::ImplContainer => tcx.trait_id_of_impl(container_id),
+ AssocItemContainer::TraitContainer => Some(container_id),
+ }
});
let fn_call = parent
LazyLock::new(|| {
let hook = panic::take_hook();
panic::set_hook(Box::new(|info| {
+ // If the error was caused by a broken pipe then this is not a bug.
+ // Write the error and return immediately. See #98700.
+ #[cfg(windows)]
+ if let Some(msg) = info.payload().downcast_ref::<String>() {
+ if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
+ {
+ early_error_no_abort(ErrorOutputType::default(), &msg);
+ return;
+ }
+ };
+
// Invoke the default handler, which prints the actual panic message and optionally a backtrace
(*DEFAULT_HOOK)(info);
passes-rustc-lint-opt-deny-field-access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field
.label = not a field
+
+passes-link-ordinal = attribute should be applied to a foreign function or static
+ .label = not a foreign function or static
\ No newline at end of file
unicode-width = "0.1.4"
atty = "0.2"
termcolor = "1.0"
-annotate-snippets = "0.8.0"
+annotate-snippets = "0.9"
termize = "0.1.1"
serde = { version = "1.0.125", features = ["derive"] }
serde_json = "1.0.59"
annotation_type: annotation_type_for_level(*level),
}),
footer: vec![],
- opt: FormatOptions { color: true, anonymized_line_numbers: self.ui_testing },
+ opt: FormatOptions {
+ color: true,
+ anonymized_line_numbers: self.ui_testing,
+ margin: None,
+ },
slices: annotated_files
.iter()
.map(|(source, line_index, annotations)| {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
}
+pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display);
+
+impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ self.0.to_string().into_diagnostic_arg()
+ }
+}
+
+impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> {
+ fn from(t: &'a dyn fmt::Display) -> Self {
+ DiagnosticArgFromDisplay(t)
+ }
+}
+
+impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> {
+ fn from(t: &'a T) -> Self {
+ DiagnosticArgFromDisplay(t)
+ }
+}
+
macro_rules! into_diagnostic_arg_using_display {
($( $ty:ty ),+ $(,)?) => {
$(
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(drain_filter)]
-#![feature(backtrace)]
#![feature(if_let_guard)]
#![cfg_attr(bootstrap, feature(let_chains))]
#![feature(let_else)]
impl error::Error for ExplicitBug {}
pub use diagnostic::{
- AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
- DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
+ AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
+ DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
};
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder};
use std::backtrace::Backtrace;
)
})
.unwrap_or_else(|| (None, helper_attrs));
- let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
+ let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
if let Some((_, sp)) = const_stability {
sess.parse_sess
.span_diagnostic
)
.emit();
}
+ if let Some((_, sp)) = body_stability {
+ sess.parse_sess
+ .span_diagnostic
+ .struct_span_err(sp, "macros cannot have body stability attributes")
+ .span_label(sp, "invalid body stability attribute")
+ .span_label(
+ sess.source_map().guess_head_span(span),
+ "body stability attribute affects this macro",
+ )
+ .emit();
+ }
SyntaxExtension {
kind,
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, TransparencyError};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
use rustc_feature::Features;
use rustc_lint_defs::builtin::{
RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
},
}
-fn annotate_doc_comment(
- err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
- sm: &SourceMap,
- span: Span,
-) {
+fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) {
if let Ok(src) = sm.span_to_snippet(span) {
if src.starts_with("///") || src.starts_with("/**") {
err.subdiagnostic(ExplainDocComment::Outer { span });
),
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
+ ungated!(
+ rustc_default_body_unstable, Normal,
+ template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
+ ),
gated!(
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
"allow_internal_unstable side-steps feature gating and stability checks",
/// Adds a definition with a parent definition.
pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId {
- debug!("create_def(parent={:?}, data={:?})", parent, data);
+ // We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a
+ // reference to `Definitions` and we're already holding a mutable reference.
+ debug!(
+ "create_def(parent={}, data={data:?})",
+ self.def_path(parent).to_string_no_crate_verbose(),
+ );
// The root node must be created with `create_root_def()`.
assert!(data != DefPathData::CrateRoot);
pub generics: &'hir Generics<'hir>,
pub kind: TraitItemKind<'hir>,
pub span: Span,
+ pub defaultness: Defaultness,
}
impl TraitItem<'_> {
pub def_id: LocalDefId,
pub generics: &'hir Generics<'hir>,
pub kind: ImplItemKind<'hir>,
+ pub defaultness: Defaultness,
pub span: Span,
pub vis_span: Span,
}
pub ident: Ident,
pub kind: AssocItemKind,
pub span: Span,
- pub defaultness: Defaultness,
}
/// A reference from an impl to one of its associated items. This
pub ident: Ident,
pub kind: AssocItemKind,
pub span: Span,
- pub defaultness: Defaultness,
/// When we are in a trait impl, link to the trait-item's id.
pub trait_item_def_id: Option<DefId>,
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts {
- rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
- rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
- rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
- rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
- rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
- rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48);
- rustc_data_structures::static_assert_size!(super::Generics<'static>, 56);
- rustc_data_structures::static_assert_size!(super::Impl<'static>, 80);
-
- rustc_data_structures::static_assert_size!(super::Item<'static>, 80);
- rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 88);
- rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 80);
- rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 72);
+ use super::*;
+ // These are in alphabetical order, which is easy to maintain.
+ static_assert_size!(Block<'static>, 48);
+ static_assert_size!(Expr<'static>, 56);
+ static_assert_size!(ForeignItem<'static>, 72);
+ static_assert_size!(GenericBound<'_>, 48);
+ static_assert_size!(Generics<'static>, 56);
+ static_assert_size!(ImplItem<'static>, 88);
+ static_assert_size!(Impl<'static>, 80);
+ static_assert_size!(Item<'static>, 80);
+ static_assert_size!(Pat<'static>, 88);
+ static_assert_size!(QPath<'static>, 24);
+ static_assert_size!(TraitItem<'static>, 96);
+ static_assert_size!(Ty<'static>, 72);
}
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>, m: TraitBoundModifier) {
walk_poly_trait_ref(self, t, m)
}
- fn visit_variant_data(
- &mut self,
- s: &'v VariantData<'v>,
- _: Symbol,
- _: &'v Generics<'v>,
- _parent_id: HirId,
- _: Span,
- ) {
+ fn visit_variant_data(&mut self, s: &'v VariantData<'v>) {
walk_struct_def(self, s)
}
fn visit_field_def(&mut self, s: &'v FieldDef<'v>) {
walk_field_def(self, s)
}
- fn visit_enum_def(
- &mut self,
- enum_definition: &'v EnumDef<'v>,
- generics: &'v Generics<'v>,
- item_id: HirId,
- _: Span,
- ) {
- walk_enum_def(self, enum_definition, generics, item_id)
+ fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) {
+ walk_enum_def(self, enum_definition, item_id)
}
- fn visit_variant(&mut self, v: &'v Variant<'v>, g: &'v Generics<'v>, item_id: HirId) {
- walk_variant(self, v, g, item_id)
+ fn visit_variant(&mut self, v: &'v Variant<'v>) {
+ walk_variant(self, v)
}
fn visit_label(&mut self, label: &'v Label) {
walk_label(self, label)
ItemKind::Enum(ref enum_definition, ref generics) => {
visitor.visit_generics(generics);
// `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
- visitor.visit_enum_def(enum_definition, generics, item.hir_id(), item.span)
+ visitor.visit_enum_def(enum_definition, item.hir_id())
}
ItemKind::Impl(Impl {
unsafety: _,
| ItemKind::Union(ref struct_definition, ref generics) => {
visitor.visit_generics(generics);
visitor.visit_id(item.hir_id());
- visitor.visit_variant_data(
- struct_definition,
- item.ident.name,
- generics,
- item.hir_id(),
- item.span,
- );
+ visitor.visit_variant_data(struct_definition);
}
ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
visitor.visit_id(item.hir_id());
pub fn walk_enum_def<'v, V: Visitor<'v>>(
visitor: &mut V,
enum_definition: &'v EnumDef<'v>,
- generics: &'v Generics<'v>,
item_id: HirId,
) {
visitor.visit_id(item_id);
- walk_list!(visitor, visit_variant, enum_definition.variants, generics, item_id);
+ walk_list!(visitor, visit_variant, enum_definition.variants);
}
-pub fn walk_variant<'v, V: Visitor<'v>>(
- visitor: &mut V,
- variant: &'v Variant<'v>,
- generics: &'v Generics<'v>,
- parent_item_id: HirId,
-) {
+pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) {
visitor.visit_ident(variant.ident);
visitor.visit_id(variant.id);
- visitor.visit_variant_data(
- &variant.data,
- variant.ident.name,
- generics,
- parent_item_id,
- variant.span,
- );
+ visitor.visit_variant_data(&variant.data);
walk_list!(visitor, visit_anon_const, &variant.disr_expr);
}
}
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
- visitor.visit_ident(trait_item.ident);
- visitor.visit_generics(&trait_item.generics);
- match trait_item.kind {
+ // N.B., deliberately force a compilation error if/when new fields are added.
+ let TraitItem { ident, generics, ref defaultness, ref kind, span, def_id: _ } = *trait_item;
+ let hir_id = trait_item.hir_id();
+ visitor.visit_ident(ident);
+ visitor.visit_generics(&generics);
+ visitor.visit_defaultness(&defaultness);
+ match *kind {
TraitItemKind::Const(ref ty, default) => {
- visitor.visit_id(trait_item.hir_id());
+ visitor.visit_id(hir_id);
visitor.visit_ty(ty);
walk_list!(visitor, visit_nested_body, default);
}
TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
- visitor.visit_id(trait_item.hir_id());
+ visitor.visit_id(hir_id);
visitor.visit_fn_decl(&sig.decl);
for ¶m_name in param_names {
visitor.visit_ident(param_name);
}
}
TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
- visitor.visit_fn(
- FnKind::Method(trait_item.ident, sig),
- &sig.decl,
- body_id,
- trait_item.span,
- trait_item.hir_id(),
- );
+ visitor.visit_fn(FnKind::Method(ident, sig), &sig.decl, body_id, span, hir_id);
}
TraitItemKind::Type(bounds, ref default) => {
- visitor.visit_id(trait_item.hir_id());
+ visitor.visit_id(hir_id);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, default);
}
pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) {
// N.B., deliberately force a compilation error if/when new fields are added.
- let TraitItemRef { id, ident, ref kind, span: _, ref defaultness } = *trait_item_ref;
+ let TraitItemRef { id, ident, ref kind, span: _ } = *trait_item_ref;
visitor.visit_nested_trait_item(id);
visitor.visit_ident(ident);
visitor.visit_associated_item_kind(kind);
- visitor.visit_defaultness(defaultness);
}
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
- let ImplItem { def_id: _, ident, ref generics, ref kind, span: _, vis_span: _ } = *impl_item;
+ let ImplItem {
+ def_id: _,
+ ident,
+ ref generics,
+ ref kind,
+ ref defaultness,
+ span: _,
+ vis_span: _,
+ } = *impl_item;
visitor.visit_ident(ident);
visitor.visit_generics(generics);
+ visitor.visit_defaultness(defaultness);
match *kind {
ImplItemKind::Const(ref ty, body) => {
visitor.visit_id(impl_item.hir_id());
pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) {
// N.B., deliberately force a compilation error if/when new fields are added.
- let ImplItemRef { id, ident, ref kind, span: _, ref defaultness, trait_item_def_id: _ } =
- *impl_item_ref;
+ let ImplItemRef { id, ident, ref kind, span: _, trait_item_def_id: _ } = *impl_item_ref;
visitor.visit_nested_impl_item(id);
visitor.visit_ident(ident);
visitor.visit_associated_item_kind(kind);
- visitor.visit_defaultness(defaultness);
}
pub fn walk_struct_def<'v, V: Visitor<'v>>(
CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1);
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
+ // language items relating to transmutability
+ TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(6);
+
Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1);
Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1);
Mul(Op), sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1);
impl Display for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(
- f,
- "{}",
- match *self {
- Target::ExternCrate => "extern crate",
- Target::Use => "use",
- Target::Static => "static item",
- Target::Const => "constant item",
- Target::Fn => "function",
- Target::Closure => "closure",
- Target::Mod => "module",
- Target::ForeignMod => "foreign module",
- Target::GlobalAsm => "global asm",
- Target::TyAlias => "type alias",
- Target::OpaqueTy => "opaque type",
- Target::Enum => "enum",
- Target::Variant => "enum variant",
- Target::Struct => "struct",
- Target::Field => "struct field",
- Target::Union => "union",
- Target::Trait => "trait",
- Target::TraitAlias => "trait alias",
- Target::Impl => "item",
- Target::Expression => "expression",
- Target::Statement => "statement",
- Target::Arm => "match arm",
- Target::AssocConst => "associated const",
- Target::Method(kind) => match kind {
- MethodKind::Inherent => "inherent method",
- MethodKind::Trait { body: false } => "required trait method",
- MethodKind::Trait { body: true } => "provided trait method",
- },
- Target::AssocTy => "associated type",
- Target::ForeignFn => "foreign function",
- Target::ForeignStatic => "foreign static item",
- Target::ForeignTy => "foreign type",
- Target::GenericParam(kind) => match kind {
- GenericParamKind::Type => "type parameter",
- GenericParamKind::Lifetime => "lifetime parameter",
- GenericParamKind::Const => "const parameter",
- },
- Target::MacroDef => "macro def",
- Target::Param => "function param",
- }
- )
+ write!(f, "{}", Self::name(*self))
}
}
hir::GenericParamKind::Const { .. } => Target::GenericParam(GenericParamKind::Const),
}
}
+
+ pub fn name(self) -> &'static str {
+ match self {
+ Target::ExternCrate => "extern crate",
+ Target::Use => "use",
+ Target::Static => "static item",
+ Target::Const => "constant item",
+ Target::Fn => "function",
+ Target::Closure => "closure",
+ Target::Mod => "module",
+ Target::ForeignMod => "foreign module",
+ Target::GlobalAsm => "global asm",
+ Target::TyAlias => "type alias",
+ Target::OpaqueTy => "opaque type",
+ Target::Enum => "enum",
+ Target::Variant => "enum variant",
+ Target::Struct => "struct",
+ Target::Field => "struct field",
+ Target::Union => "union",
+ Target::Trait => "trait",
+ Target::TraitAlias => "trait alias",
+ Target::Impl => "implementation block",
+ Target::Expression => "expression",
+ Target::Statement => "statement",
+ Target::Arm => "match arm",
+ Target::AssocConst => "associated const",
+ Target::Method(kind) => match kind {
+ MethodKind::Inherent => "inherent method",
+ MethodKind::Trait { body: false } => "required trait method",
+ MethodKind::Trait { body: true } => "provided trait method",
+ },
+ Target::AssocTy => "associated type",
+ Target::ForeignFn => "foreign function",
+ Target::ForeignStatic => "foreign static item",
+ Target::ForeignTy => "foreign type",
+ Target::GenericParam(kind) => match kind {
+ GenericParamKind::Type => "type parameter",
+ GenericParamKind::Lifetime => "lifetime parameter",
+ GenericParamKind::Const => "const parameter",
+ },
+ Target::MacroDef => "macro def",
+ Target::Param => "function param",
+ }
+ }
}
/// Extra `DepNode`s for functions and methods.
const EXTRA_ASSOCIATED: &[&str] = &[label_strs::associated_item];
-const EXTRA_TRAIT: &[&str] = &[label_strs::trait_of_item];
+const EXTRA_TRAIT: &[&str] = &[];
// Fully Built Labels
}
ty::ConstKind::Placeholder(placeholder) => {
return self.canonicalize_const_var(
- CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
+ CanonicalVarInfo {
+ kind: CanonicalVarKind::PlaceholderConst(placeholder, ct.ty()),
+ },
ct,
);
}
..placeholder
})
}
- CanonicalVarKind::PlaceholderConst(placeholder) => {
- CanonicalVarKind::PlaceholderConst(ty::Placeholder {
- universe: reverse_universe_map[&placeholder.universe],
- ..placeholder
- })
+ CanonicalVarKind::PlaceholderConst(placeholder, t) => {
+ CanonicalVarKind::PlaceholderConst(
+ ty::Placeholder {
+ universe: reverse_universe_map[&placeholder.universe],
+ ..placeholder
+ },
+ t,
+ )
}
},
})
)
.into(),
- CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }) => {
+ CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }, ty) => {
let universe_mapped = universe_map(universe);
let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name };
self.tcx
.mk_const(ty::ConstS {
kind: ty::ConstKind::Placeholder(placeholder_mapped),
- ty: name.ty,
+ ty,
})
.into()
}
"...is used and required to live as long as `'static` here \
because of an implicit lifetime bound on the {}",
match ctxt.assoc_item.container {
- AssocItemContainer::TraitContainer(id) =>
- format!("`impl` of `{}`", tcx.def_path_str(id)),
- AssocItemContainer::ImplContainer(_) =>
- "inherent `impl`".to_string(),
+ AssocItemContainer::TraitContainer => {
+ let id = ctxt.assoc_item.container_id(tcx);
+ format!("`impl` of `{}`", tcx.def_path_str(id))
+ }
+ AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
},
),
);
///
/// This is implemented by first entering a new universe.
/// We then replace all bound variables in `sup` with placeholders,
- /// and all bound variables in `sup` with inference vars.
+ /// and all bound variables in `sub` with inference vars.
/// We can then just relate the two resulting types as normal.
///
/// Note: this is a subtle algorithm. For a full explanation, please see
self.tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
universe: next_universe,
- name: ty::BoundConst { var: bound_var, ty },
+ name: bound_var,
}),
ty,
})
use self::opaque_types::OpaqueTypeStorage;
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
-use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
+use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine, TraitEngineExt};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
fulfill_cx: &mut dyn TraitEngine<'tcx>,
) -> T {
let InferOk { value, obligations } = self;
- for obligation in obligations {
- fulfill_cx.register_predicate_obligation(infcx, obligation);
- }
+ fulfill_cx.register_predicate_obligations(infcx, obligations);
value
}
}
self.inner.borrow_mut().commit(undo_snapshot);
}
- /// Executes `f` and commit the bindings.
- #[instrument(skip(self, f), level = "debug")]
- pub fn commit_unconditionally<R, F>(&self, f: F) -> R
- where
- F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
- {
- let snapshot = self.start_snapshot();
- let r = f(&snapshot);
- self.commit_from(snapshot);
- r
- }
-
/// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
#[instrument(skip(self, f), level = "debug")]
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
ty,
kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
universe: ty::UniverseIndex::ROOT,
- name: ty::BoundConst { ty, var: ty::BoundVar::from_usize(idx) },
+ name: ty::BoundVar::from_usize(idx),
}),
})
.into()
/// }
/// ```
/// This is described with an `AnyRegion('a, 'b)` node.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
pub enum VerifyBound<'tcx> {
/// See [`VerifyIfEq`] docs
IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
}
/// Returns amount of already consumed symbols.
- pub(crate) fn len_consumed(&self) -> usize {
- self.initial_len - self.chars.as_str().len()
+ pub(crate) fn len_consumed(&self) -> u32 {
+ (self.initial_len - self.chars.as_str().len()) as u32
}
/// Resets the number of bytes consumed to 0.
#[derive(Debug)]
pub struct Token {
pub kind: TokenKind,
- pub len: usize,
+ pub len: u32,
}
impl Token {
- fn new(kind: TokenKind, len: usize) -> Token {
+ fn new(kind: TokenKind, len: u32) -> Token {
Token { kind, len }
}
}
/// Enum representing common lexeme types.
-// perf note: Changing all `usize` to `u32` doesn't change performance. See #77629
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TokenKind {
// Multi-char tokens:
/// "// comment"
/// tokens.
UnknownPrefix,
/// "12_u8", "1.0e-40", "b"123"". See `LiteralKind` for more details.
- Literal { kind: LiteralKind, suffix_start: usize },
+ Literal { kind: LiteralKind, suffix_start: u32 },
/// "'a"
Lifetime { starts_with_number: bool },
Str { terminated: bool },
/// "b"abc"", "b"abc"
ByteStr { terminated: bool },
- /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a"
- RawStr { n_hashes: u8, err: Option<RawStrError> },
- /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a"
- RawByteStr { n_hashes: u8, err: Option<RawStrError> },
+ /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates
+ /// an invalid literal.
+ RawStr { n_hashes: Option<u8> },
+ /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a". `None`
+ /// indicates an invalid literal.
+ RawByteStr { n_hashes: Option<u8> },
}
-/// Error produced validating a raw string. Represents cases like:
-/// - `r##~"abcde"##`: `InvalidStarter`
-/// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)`
-/// - Too many `#`s (>255): `TooManyDelimiters`
-// perf note: It doesn't matter that this makes `Token` 36 bytes bigger. See #77629
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum RawStrError {
- /// Non `#` characters exist between `r` and `"` eg. `r#~"..`
+ /// Non `#` characters exist between `r` and `"`, e.g. `r##~"abcde"##`
InvalidStarter { bad_char: char },
- /// The string was never terminated. `possible_terminator_offset` is the number of characters after `r` or `br` where they
- /// may have intended to terminate it.
- NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option<usize> },
+ /// The string was not terminated, e.g. `r###"abcde"##`.
+ /// `possible_terminator_offset` is the number of characters after `r` or
+ /// `br` where they may have intended to terminate it.
+ NoTerminator { expected: u32, found: u32, possible_terminator_offset: Option<u32> },
/// More than 255 `#`s exist.
- TooManyDelimiters { found: usize },
+ TooManyDelimiters { found: u32 },
}
/// Base of numeric literal encoding according to its prefix.
}
/// Parses the first token from the provided input string.
+#[inline]
pub fn first_token(input: &str) -> Token {
debug_assert!(!input.is_empty());
Cursor::new(input).advance_token()
}
+/// Validates a raw string literal. Used for getting more information about a
+/// problem with a `RawStr`/`RawByteStr` with a `None` field.
+#[inline]
+pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> {
+ debug_assert!(!input.is_empty());
+ let mut cursor = Cursor::new(input);
+ // Move past the leading `r` or `br`.
+ for _ in 0..prefix_len {
+ cursor.bump().unwrap();
+ }
+ cursor.raw_double_quoted_string(prefix_len).map(|_| ())
+}
+
/// Creates an iterator that produces tokens from the input string.
pub fn tokenize(input: &str) -> impl Iterator<Item = Token> + '_ {
let mut cursor = Cursor::new(input);
'r' => match (self.first(), self.second()) {
('#', c1) if is_id_start(c1) => self.raw_ident(),
('#', _) | ('"', _) => {
- let (n_hashes, err) = self.raw_double_quoted_string(1);
+ let res = self.raw_double_quoted_string(1);
let suffix_start = self.len_consumed();
- if err.is_none() {
+ if res.is_ok() {
self.eat_literal_suffix();
}
- let kind = RawStr { n_hashes, err };
+ let kind = RawStr { n_hashes: res.ok() };
Literal { kind, suffix_start }
}
_ => self.ident_or_unknown_prefix(),
}
('r', '"') | ('r', '#') => {
self.bump();
- let (n_hashes, err) = self.raw_double_quoted_string(2);
+ let res = self.raw_double_quoted_string(2);
let suffix_start = self.len_consumed();
- if err.is_none() {
+ if res.is_ok() {
self.eat_literal_suffix();
}
- let kind = RawByteStr { n_hashes, err };
+ let kind = RawByteStr { n_hashes: res.ok() };
Literal { kind, suffix_start }
}
_ => self.ident_or_unknown_prefix(),
}
/// Eats the double-quoted string and returns `n_hashes` and an error if encountered.
- fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u8, Option<RawStrError>) {
+ fn raw_double_quoted_string(&mut self, prefix_len: u32) -> Result<u8, RawStrError> {
// Wrap the actual function to handle the error with too many hashes.
// This way, it eats the whole raw string.
- let (n_hashes, err) = self.raw_string_unvalidated(prefix_len);
+ let n_hashes = self.raw_string_unvalidated(prefix_len)?;
// Only up to 255 `#`s are allowed in raw strings
match u8::try_from(n_hashes) {
- Ok(num) => (num, err),
- // We lie about the number of hashes here :P
- Err(_) => (0, Some(RawStrError::TooManyDelimiters { found: n_hashes })),
+ Ok(num) => Ok(num),
+ Err(_) => Err(RawStrError::TooManyDelimiters { found: n_hashes }),
}
}
- fn raw_string_unvalidated(&mut self, prefix_len: usize) -> (usize, Option<RawStrError>) {
+ fn raw_string_unvalidated(&mut self, prefix_len: u32) -> Result<u32, RawStrError> {
debug_assert!(self.prev() == 'r');
let start_pos = self.len_consumed();
let mut possible_terminator_offset = None;
Some('"') => (),
c => {
let c = c.unwrap_or(EOF_CHAR);
- return (n_start_hashes, Some(RawStrError::InvalidStarter { bad_char: c }));
+ return Err(RawStrError::InvalidStarter { bad_char: c });
}
}
self.eat_while(|c| c != '"');
if self.is_eof() {
- return (
- n_start_hashes,
- Some(RawStrError::NoTerminator {
- expected: n_start_hashes,
- found: max_hashes,
- possible_terminator_offset,
- }),
- );
+ return Err(RawStrError::NoTerminator {
+ expected: n_start_hashes,
+ found: max_hashes,
+ possible_terminator_offset,
+ });
}
// Eat closing double quote.
}
if n_end_hashes == n_start_hashes {
- return (n_start_hashes, None);
+ return Ok(n_start_hashes);
} else if n_end_hashes > max_hashes {
// Keep track of possible terminators to give a hint about
// where there might be a missing terminator
use expect_test::{expect, Expect};
-fn check_raw_str(s: &str, expected_hashes: u8, expected_err: Option<RawStrError>) {
+fn check_raw_str(s: &str, expected: Result<u8, RawStrError>) {
let s = &format!("r{}", s);
let mut cursor = Cursor::new(s);
cursor.bump();
- let (n_hashes, err) = cursor.raw_double_quoted_string(0);
- assert_eq!(n_hashes, expected_hashes);
- assert_eq!(err, expected_err);
+ let res = cursor.raw_double_quoted_string(0);
+ assert_eq!(res, expected);
}
#[test]
fn test_naked_raw_str() {
- check_raw_str(r#""abc""#, 0, None);
+ check_raw_str(r#""abc""#, Ok(0));
}
#[test]
fn test_raw_no_start() {
- check_raw_str(r##""abc"#"##, 0, None);
+ check_raw_str(r##""abc"#"##, Ok(0));
}
#[test]
fn test_too_many_terminators() {
// this error is handled in the parser later
- check_raw_str(r###"#"abc"##"###, 1, None);
+ check_raw_str(r###"#"abc"##"###, Ok(1));
}
#[test]
fn test_unterminated() {
check_raw_str(
r#"#"abc"#,
- 1,
- Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }),
+ Err(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }),
);
check_raw_str(
r###"##"abc"#"###,
- 2,
- Some(RawStrError::NoTerminator {
+ Err(RawStrError::NoTerminator {
expected: 2,
found: 1,
possible_terminator_offset: Some(7),
// We're looking for "# not just any #
check_raw_str(
r###"##"abc#"###,
- 2,
- Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }),
+ Err(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }),
)
}
#[test]
fn test_invalid_start() {
- check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' }));
+ check_raw_str(r##"#~"abc"#"##, Err(RawStrError::InvalidStarter { bad_char: '~' }));
}
#[test]
// https://github.com/rust-lang/rust/issues/70677
check_raw_str(
r#"""#,
- 0,
- Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }),
+ Err(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }),
);
}
#[test]
fn test_too_many_hashes() {
let max_count = u8::MAX;
- let mut hashes: String = "#".repeat(max_count.into());
+ let hashes1 = "#".repeat(max_count as usize);
+ let hashes2 = "#".repeat(max_count as usize + 1);
+ let middle = "\"abc\"";
+ let s1 = [&hashes1, middle, &hashes1].join("");
+ let s2 = [&hashes2, middle, &hashes2].join("");
- // Valid number of hashes (255 = 2^8 - 1 = u8::MAX), but invalid string.
- check_raw_str(&hashes, max_count, Some(RawStrError::InvalidStarter { bad_char: '\u{0}' }));
+ // Valid number of hashes (255 = 2^8 - 1 = u8::MAX).
+ check_raw_str(&s1, Ok(255));
// One more hash sign (256 = 2^8) becomes too many.
- hashes.push('#');
- check_raw_str(
- &hashes,
- 0,
- Some(RawStrError::TooManyDelimiters { found: usize::from(max_count) + 1 }),
- );
+ check_raw_str(&s2, Err(RawStrError::TooManyDelimiters { found: u32::from(max_count) + 1 }));
}
#[test]
check_lexing(
"r###\"\"#a\\b\x00c\"\"###",
expect![[r#"
- Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 17 }, len: 17 }
+ Token { kind: Literal { kind: RawStr { n_hashes: Some(3) }, suffix_start: 17 }, len: 17 }
"#]],
)
}
Token { kind: Whitespace, len: 1 }
Token { kind: Literal { kind: Int { base: Decimal, empty_int: false }, suffix_start: 1 }, len: 3 }
Token { kind: Whitespace, len: 1 }
- Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 12 }, len: 18 }
+ Token { kind: Literal { kind: RawStr { n_hashes: Some(3) }, suffix_start: 12 }, len: 18 }
Token { kind: Whitespace, len: 1 }
- Token { kind: Literal { kind: RawByteStr { n_hashes: 3, err: None }, suffix_start: 13 }, len: 19 }
+ Token { kind: Literal { kind: RawByteStr { n_hashes: Some(3) }, suffix_start: 13 }, len: 19 }
Token { kind: Whitespace, len: 1 }
"#]],
)
cx: &LateContext<'_>,
what: &str,
def_id: LocalDefId,
- span: Span,
vis_span: Span,
exportable: bool,
) {
if vis_span.from_expansion() {
applicability = Applicability::MaybeIncorrect;
}
- let def_span = cx.tcx.sess.source_map().guess_head_span(span);
+ let def_span = cx.tcx.def_span(def_id);
cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
err.set_arg("what", what);
if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
return;
}
- self.perform_lint(cx, "item", item.def_id, item.span, item.vis_span, true);
+ self.perform_lint(cx, "item", item.def_id, item.vis_span, true);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
- self.perform_lint(
- cx,
- "item",
- foreign_item.def_id,
- foreign_item.span,
- foreign_item.vis_span,
- true,
- );
+ self.perform_lint(cx, "item", foreign_item.def_id, foreign_item.vis_span, true);
}
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
let def_id = cx.tcx.hir().local_def_id(field.hir_id);
- self.perform_lint(cx, "field", def_id, field.span, field.vis_span, false);
+ self.perform_lint(cx, "field", def_id, field.vis_span, false);
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
// Only lint inherent impl items.
if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
- self.perform_lint(
- cx,
- "item",
- impl_item.def_id,
- impl_item.span,
- impl_item.vis_span,
- false,
- );
+ self.perform_lint(cx, "item", impl_item.def_id, impl_item.vis_span, false);
}
}
}
Applicability::MachineApplicable,
);
},
- BuiltinLintDiagnostics::NamedArgumentUsedPositionally(positional_arg, named_arg, name) => {
- db.span_label(named_arg, "this named argument is only referred to by position in formatting string");
- if let Some(positional_arg) = positional_arg {
- let msg = format!("this formatting argument uses named argument `{}` by position", name);
- db.span_label(positional_arg, msg);
+ BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => {
+ db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string");
+ if let Some(positional_arg_for_msg) = position_sp_for_msg {
+ let msg = format!("this formatting argument uses named argument `{}` by position", named_arg_name);
+ db.span_label(positional_arg_for_msg, msg);
+ }
+
+ if let Some(positional_arg_to_replace) = position_sp_to_replace {
+ let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
+
db.span_suggestion_verbose(
- positional_arg,
+ positional_arg_to_replace,
"use the named argument by name to avoid ambiguity",
name,
Applicability::MaybeIncorrect,
ast_visit::walk_where_predicate(self, p);
}
- fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) {
- run_early_pass!(self, check_poly_trait_ref, t, m);
- ast_visit::walk_poly_trait_ref(self, t, m);
+ fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
+ run_early_pass!(self, check_poly_trait_ref, t);
+ ast_visit::walk_poly_trait_ref(self, t);
}
fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::LintPass;
-use rustc_span::symbol::Symbol;
use rustc_span::Span;
use std::any::Any;
self.context.cached_typeck_results.set(old_cached_typeck_results);
}
- fn visit_variant_data(
- &mut self,
- s: &'tcx hir::VariantData<'tcx>,
- _: Symbol,
- _: &'tcx hir::Generics<'tcx>,
- _: hir::HirId,
- _: Span,
- ) {
+ fn visit_variant_data(&mut self, s: &'tcx hir::VariantData<'tcx>) {
lint_callback!(self, check_struct_def, s);
hir_visit::walk_struct_def(self, s);
}
})
}
- fn visit_variant(
- &mut self,
- v: &'tcx hir::Variant<'tcx>,
- g: &'tcx hir::Generics<'tcx>,
- item_id: hir::HirId,
- ) {
+ fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
self.with_lint_attrs(v.id, |cx| {
lint_callback!(cx, check_variant, v);
- hir_visit::walk_variant(cx, v, g, item_id);
+ hir_visit::walk_variant(cx, v);
})
}
})
}
- fn visit_variant(
- &mut self,
- v: &'tcx hir::Variant<'tcx>,
- g: &'tcx hir::Generics<'tcx>,
- item_id: hir::HirId,
- ) {
+ fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
self.with_lint_attrs(v.id, |builder| {
- intravisit::walk_variant(builder, v, g, item_id);
+ intravisit::walk_variant(builder, v);
})
}
let def_id = cx.tcx.hir().local_def_id(id);
let item = cx.tcx.associated_item(def_id);
match item.container {
- ty::TraitContainer(..) => MethodLateContext::TraitAutoImpl,
- ty::ImplContainer(cid) => match cx.tcx.impl_trait_ref(cid) {
+ ty::TraitContainer => MethodLateContext::TraitAutoImpl,
+ ty::ImplContainer => match cx.tcx.impl_trait_ref(item.container_id(cx.tcx)) {
Some(_) => MethodLateContext::TraitImpl,
None => MethodLateContext::PlainImpl,
},
fn check_generic_arg(a: &ast::GenericArg);
fn check_generic_param(a: &ast::GenericParam);
fn check_generics(a: &ast::Generics);
- fn check_poly_trait_ref(a: &ast::PolyTraitRef,
- b: &ast::TraitBoundModifier);
+ fn check_poly_trait_ref(a: &ast::PolyTraitRef);
fn check_fn(a: rustc_ast::visit::FnKind<'_>, c: Span, d_: ast::NodeId);
fn check_trait_item(a: &ast::AssocItem);
fn check_impl_item(a: &ast::AssocItem);
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{kw, sym};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, Span};
declare_lint! {
/// The `unused_must_use` lint detects unused result of a type flagged as
LetScrutineeExpr,
ArrayLenExpr,
AnonConst,
+ MatchArmExpr,
}
impl From<UnusedDelimsCtx> for &'static str {
UnusedDelimsCtx::BlockRetValue => "block return value",
UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
+ UnusedDelimsCtx::MatchArmExpr => "match arm expression",
}
}
}
ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => {
let start = block.stmts[0].span;
let end = block.stmts[block.stmts.len() - 1].span;
- if value.span.from_expansion() || start.from_expansion() || end.from_expansion() {
- (
- value.span.with_hi(value.span.lo() + BytePos(1)),
- value.span.with_lo(value.span.hi() - BytePos(1)),
- )
+ if let Some(start) = start.find_ancestor_inside(value.span)
+ && let Some(end) = end.find_ancestor_inside(value.span)
+ {
+ Some((
+ value.span.with_hi(start.lo()),
+ value.span.with_lo(end.hi()),
+ ))
} else {
- (value.span.with_hi(start.lo()), value.span.with_lo(end.hi()))
+ None
}
}
ast::ExprKind::Paren(ref expr) => {
- if value.span.from_expansion() || expr.span.from_expansion() {
- (
- value.span.with_hi(value.span.lo() + BytePos(1)),
- value.span.with_lo(value.span.hi() - BytePos(1)),
- )
+ let expr_span = expr.span.find_ancestor_inside(value.span);
+ if let Some(expr_span) = expr_span {
+ Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())))
} else {
- (value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi()))
+ None
}
}
_ => return,
left_pos.map_or(false, |s| s >= value.span.lo()),
right_pos.map_or(false, |s| s <= value.span.hi()),
);
- self.emit_unused_delims(cx, spans, ctx.into(), keep_space);
+ self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
}
fn emit_unused_delims(
&self,
cx: &EarlyContext<'_>,
- spans: (Span, Span),
+ value_span: Span,
+ spans: Option<(Span, Span)>,
msg: &str,
keep_space: (bool, bool),
) {
- // FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc
- // properly.
- if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP {
- return;
- }
-
- cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
- let replacement = vec![
- (spans.0, if keep_space.0 { " ".into() } else { "".into() }),
- (spans.1, if keep_space.1 { " ".into() } else { "".into() }),
- ];
- lint.build(fluent::lint::unused_delim)
- .set_arg("delim", Self::DELIM_STR)
- .set_arg("item", msg)
- .multipart_suggestion(
+ let primary_span = if let Some((lo, hi)) = spans {
+ MultiSpan::from(vec![lo, hi])
+ } else {
+ MultiSpan::from(value_span)
+ };
+ cx.struct_span_lint(self.lint(), primary_span, |lint| {
+ let mut db = lint.build(fluent::lint::unused_delim);
+ db.set_arg("delim", Self::DELIM_STR);
+ db.set_arg("item", msg);
+ if let Some((lo, hi)) = spans {
+ let replacement = vec![
+ (lo, if keep_space.0 { " ".into() } else { "".into() }),
+ (hi, if keep_space.1 { " ".into() } else { "".into() }),
+ ];
+ db.multipart_suggestion(
fluent::lint::suggestion,
replacement,
Applicability::MachineApplicable,
- )
- .emit();
+ );
+ }
+ db.emit();
});
}
ref call_or_other => {
let (args_to_check, ctx) = match *call_or_other {
Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
- // first "argument" is self (which sometimes needs delims)
- MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg),
+ MethodCall(_, _, ref args, _) => (&args[..], UnusedDelimsCtx::MethodArg),
// actual catch-all arm
_ => {
return;
// Otherwise proceed with linting.
_ => {}
}
- let spans = if value.span.from_expansion() || inner.span.from_expansion() {
- (
- value.span.with_hi(value.span.lo() + BytePos(1)),
- value.span.with_lo(value.span.hi() - BytePos(1)),
- )
+ let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) {
+ Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
} else {
- (value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi()))
+ None
};
- self.emit_unused_delims(cx, spans, "pattern", (false, false));
+ self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
}
}
}
}
return;
}
+ ExprKind::Match(ref _expr, ref arm) => {
+ for a in arm {
+ self.check_unused_delims_expr(
+ cx,
+ &a.body,
+ UnusedDelimsCtx::MatchArmExpr,
+ false,
+ None,
+ None,
+ );
+ }
+ }
_ => {}
}
);
}
_ => {
- let spans = if ty.span.from_expansion() || r.span.from_expansion() {
- (
- ty.span.with_hi(ty.span.lo() + BytePos(1)),
- ty.span.with_lo(ty.span.hi() - BytePos(1)),
- )
+ let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
+ Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
} else {
- (ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi()))
+ None
};
- self.emit_unused_delims(cx, spans, "type", (false, false));
+ self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
}
}
}
"detects attributes that were not used by the compiler"
}
+declare_lint! {
+ /// The `unused_tuple_struct_fields` lint detects fields of tuple structs
+ /// that are never read.
+ ///
+ /// ### Example
+ ///
+ /// ```
+ /// #[warn(unused_tuple_struct_fields)]
+ /// struct S(i32, i32, i32);
+ /// let s = S(1, 2, 3);
+ /// let _ = (s.0, s.2);
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Tuple struct fields that are never read anywhere may indicate a
+ /// mistake or unfinished code. To silence this warning, consider
+ /// removing the unused field(s) or, to preserve the numbering of the
+ /// remaining fields, change the unused field(s) to have unit type.
+ pub UNUSED_TUPLE_STRUCT_FIELDS,
+ Allow,
+ "detects tuple struct fields that are never read"
+}
+
declare_lint! {
/// The `unreachable_code` lint detects unreachable code paths.
///
UNSUPPORTED_CALLING_CONVENTIONS,
BREAK_WITH_LABEL_AND_LOOP,
UNUSED_ATTRIBUTES,
+ UNUSED_TUPLE_STRUCT_FIELDS,
NON_EXHAUSTIVE_OMITTED_PATTERNS,
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
DEREF_INTO_DYN_SUPERTRAIT,
/// If true, the lifetime will be fully elided.
use_span: Option<(Span, bool)>,
},
- NamedArgumentUsedPositionally(Option<Span>, Span, String),
+ NamedArgumentUsedPositionally {
+ /// Span where the named argument is used by position and will be replaced with the named
+ /// argument name
+ position_sp_to_replace: Option<Span>,
+ /// Span where the named argument is used by position and is used for lint messages
+ position_sp_for_msg: Option<Span>,
+ /// Span where the named argument's name is (so we know where to put the warning message)
+ named_arg_sp: Span,
+ /// String containing the named arguments name
+ named_arg_name: String,
+ /// Indicates if the named argument is used as a width/precision for formatting
+ is_formatting_arg: bool,
+ },
}
/// Lints that are buffered up early on in the `Session` before the
println!("cargo:rustc-link-lib=uuid");
} else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") {
println!("cargo:rustc-link-lib=z");
+ } else if target.starts_with("arm")
+ || target.starts_with("mips-")
+ || target.starts_with("mipsel-")
+ || target.starts_with("powerpc-")
+ {
+ // 32-bit targets need to link libatomic.
+ println!("cargo:rustc-link-lib=atomic");
}
cmd.args(&components);
return LLVMBFloatTypeKind;
case Type::X86_AMXTyID:
return LLVMX86_AMXTypeKind;
-#if LLVM_VERSION_GE(15, 0)
+#if LLVM_VERSION_GE(15, 0) && LLVM_VERSION_LT(16, 0)
case Type::DXILPointerTyID:
report_fatal_error("Rust does not support DirectX typed pointers.");
break;
+#endif
+#if LLVM_VERSION_GE(16, 0)
+ case Type::TypedPointerTyID:
+ report_fatal_error("Rust does not support typed pointers.");
+ break;
#endif
}
report_fatal_error("Unhandled TypeID.");
proc-macro = true
[dependencies]
-annotate-snippets = "0.8.0"
+annotate-snippets = "0.9"
fluent-bundle = "0.15.2"
fluent-syntax = "0.11"
synstructure = "0.12.1"
.map(|child_item| self.build_dll_import(abi, child_item))
.collect()
}
- _ => Vec::new(),
+ _ => {
+ for child_item in foreign_mod_items {
+ if self.tcx.def_kind(child_item.id.def_id).has_codegen_attrs()
+ && self
+ .tcx
+ .codegen_fn_attrs(child_item.id.def_id)
+ .link_ordinal
+ .is_some()
+ {
+ let link_ordinal_attr = self
+ .tcx
+ .hir()
+ .attrs(self.tcx.hir().local_def_id_to_hir_id(child_item.id.def_id))
+ .iter()
+ .find(|a| a.has_name(sym::link_ordinal))
+ .unwrap();
+ sess.span_err(
+ link_ordinal_attr.span,
+ "`#[link_ordinal]` is only supported if link kind is `raw-dylib`",
+ );
+ }
+ }
+
+ Vec::new()
+ }
};
self.libs.push(NativeLib {
name: name.map(|(name, _)| name),
Abi::Fastcall { .. } => {
DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
}
- // Vectorcall is intentionally not supported at this time.
+ Abi::Vectorcall { .. } => {
+ DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
+ }
_ => {
self.tcx.sess.span_fatal(
item.span,
fn get_fn_has_self_parameter(self, id: DefIndex) -> bool {
match self.kind(id) {
- EntryKind::AssocFn(data) => data.decode(self).has_self,
+ EntryKind::AssocFn { has_self, .. } => has_self,
_ => false,
}
}
}
fn get_associated_item(self, id: DefIndex) -> ty::AssocItem {
- let def_key = self.def_key(id);
- let parent = self.local_def_id(def_key.parent.unwrap());
let name = self.item_name(id);
let (kind, container, has_self) = match self.kind(id) {
EntryKind::AssocConst(container) => (ty::AssocKind::Const, container, false),
- EntryKind::AssocFn(data) => {
- let data = data.decode(self);
- (ty::AssocKind::Fn, data.container, data.has_self)
- }
+ EntryKind::AssocFn { container, has_self } => (ty::AssocKind::Fn, container, has_self),
EntryKind::AssocType(container) => (ty::AssocKind::Type, container, false),
- _ => bug!("cannot get associated-item of `{:?}`", def_key),
+ _ => bug!("cannot get associated-item of `{:?}`", id),
};
ty::AssocItem {
name,
kind,
- vis: self.get_visibility(id),
- defaultness: container.defaultness(),
def_id: self.local_def_id(id),
trait_item_def_id: self.get_trait_item_def_id(id),
- container: container.with_def_id(parent),
+ container,
fn_has_self_parameter: has_self,
}
}
}
}
- fn get_trait_of_item(self, id: DefIndex) -> Option<DefId> {
- let def_key = self.def_key(id);
- match def_key.disambiguated_data.data {
- DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (),
- // Not an associated item
- _ => return None,
- }
- def_key.parent.and_then(|parent_index| match self.kind(parent_index) {
- EntryKind::Trait | EntryKind::TraitAlias => Some(self.local_def_id(parent_index)),
- _ => None,
- })
- }
-
fn get_native_libraries(self, sess: &'a Session) -> impl Iterator<Item = NativeLib> + 'a {
self.root.native_libraries.decode((self, sess))
}
def_ident_span => { table }
lookup_stability => { table }
lookup_const_stability => { table }
+ lookup_default_body_stability => { table }
lookup_deprecation_entry => { table }
visibility => { table }
unused_generic_params => { table }
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
- trait_of_item => { cdata.get_trait_of_item(def_id.index) }
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
if should_encode_stability(def_kind) {
self.encode_stability(def_id);
self.encode_const_stability(def_id);
+ self.encode_default_body_stability(def_id);
self.encode_deprecation(def_id);
}
if should_encode_variances(def_kind) {
let tcx = self.tcx;
let ast_item = tcx.hir().expect_trait_item(def_id.expect_local());
+ self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
let trait_item = tcx.associated_item(def_id);
- let container = match trait_item.defaultness {
- hir::Defaultness::Default { has_value: true } => AssocContainer::TraitWithDefault,
- hir::Defaultness::Default { has_value: false } => AssocContainer::TraitRequired,
- hir::Defaultness::Final => span_bug!(ast_item.span, "traits cannot have final items"),
- };
-
match trait_item.kind {
ty::AssocKind::Const => {
let rendered = rustc_hir_pretty::to_string(
|s| s.print_trait_item(ast_item),
);
- record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container));
+ record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::TraitContainer));
record!(self.tables.mir_const_qualif[def_id] <- mir::ConstQualifs::default());
record!(self.tables.rendered_const[def_id] <- rendered);
}
};
self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
self.tables.constness.set(def_id.index, hir::Constness::NotConst);
- record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
- container,
+ record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
+ container: ty::AssocItemContainer::TraitContainer,
has_self: trait_item.fn_has_self_parameter,
- })));
+ });
}
ty::AssocKind::Type => {
self.encode_explicit_item_bounds(def_id);
- record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
+ record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::TraitContainer));
}
}
match trait_item.kind {
self.encode_item_type(def_id);
}
ty::AssocKind::Type => {
- if trait_item.defaultness.has_value() {
+ if ast_item.defaultness.has_value() {
self.encode_item_type(def_id);
}
}
let tcx = self.tcx;
let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
+ self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
let impl_item = self.tcx.associated_item(def_id);
- let container = match impl_item.defaultness {
- hir::Defaultness::Default { has_value: true } => AssocContainer::ImplDefault,
- hir::Defaultness::Final => AssocContainer::ImplFinal,
- hir::Defaultness::Default { has_value: false } => {
- span_bug!(ast_item.span, "impl items always have values (currently)")
- }
- };
-
match impl_item.kind {
ty::AssocKind::Const => {
if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id);
let const_data = self.encode_rendered_const_for_body(body_id);
- record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container));
+ record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::ImplContainer));
record!(self.tables.mir_const_qualif[def_id] <- qualifs);
record!(self.tables.rendered_const[def_id] <- const_data);
} else {
hir::Constness::NotConst
};
self.tables.constness.set(def_id.index, constness);
- record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
- container,
+ record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
+ container: ty::AssocItemContainer::ImplContainer,
has_self: impl_item.fn_has_self_parameter,
- })));
+ });
}
ty::AssocKind::Type => {
- record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
+ record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::ImplContainer));
}
}
self.encode_item_type(def_id);
}
}
+ fn encode_default_body_stability(&mut self, def_id: DefId) {
+ debug!("EncodeContext::encode_default_body_stability({:?})", def_id);
+
+ // The query lookup can take a measurable amount of time in crates with many items. Check if
+ // the stability attributes are even enabled before using their queries.
+ if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
+ if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) {
+ record!(self.tables.lookup_default_body_stability[def_id] <- stab)
+ }
+ }
+ }
+
fn encode_deprecation(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_deprecation({:?})", def_id);
if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
def_ident_span: Table<DefIndex, LazyValue<Span>>,
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
+ lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
// As an optimization, a missing entry indicates an empty `&[]`.
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
Generator,
Trait,
Impl,
- AssocFn(LazyValue<AssocFnData>),
- AssocType(AssocContainer),
- AssocConst(AssocContainer),
+ AssocFn { container: ty::AssocItemContainer, has_self: bool },
+ AssocType(ty::AssocItemContainer),
+ AssocConst(ty::AssocItemContainer),
TraitAlias,
}
is_non_exhaustive: bool,
}
-/// Describes whether the container of an associated item
-/// is a trait or an impl and whether, in a trait, it has
-/// a default, or an in impl, whether it's marked "default".
-#[derive(Copy, Clone, TyEncodable, TyDecodable)]
-enum AssocContainer {
- TraitRequired,
- TraitWithDefault,
- ImplDefault,
- ImplFinal,
-}
-
-impl AssocContainer {
- fn with_def_id(&self, def_id: DefId) -> ty::AssocItemContainer {
- match *self {
- AssocContainer::TraitRequired | AssocContainer::TraitWithDefault => {
- ty::TraitContainer(def_id)
- }
-
- AssocContainer::ImplDefault | AssocContainer::ImplFinal => ty::ImplContainer(def_id),
- }
- }
-
- fn defaultness(&self) -> hir::Defaultness {
- match *self {
- AssocContainer::TraitRequired => hir::Defaultness::Default { has_value: false },
-
- AssocContainer::TraitWithDefault | AssocContainer::ImplDefault => {
- hir::Defaultness::Default { has_value: true }
- }
-
- AssocContainer::ImplFinal => hir::Defaultness::Final,
- }
- }
-}
-
-#[derive(MetadataEncodable, MetadataDecodable)]
-struct AssocFnData {
- container: AssocContainer,
- has_self: bool,
-}
-
#[derive(TyEncodable, TyDecodable)]
struct GeneratorData<'tcx> {
layout: mir::GeneratorLayout<'tcx>,
trivially_parameterized_over_tcx! {
VariantData,
- AssocFnData,
EntryKind,
RawDefId,
TraitImpls,
CanonicalVarKind::Region(_) => true,
CanonicalVarKind::PlaceholderRegion(..) => false,
CanonicalVarKind::Const(..) => true,
- CanonicalVarKind::PlaceholderConst(_) => false,
+ CanonicalVarKind::PlaceholderConst(_, _) => false,
}
}
}
Const(ty::UniverseIndex, Ty<'tcx>),
/// A "placeholder" that represents "any const".
- PlaceholderConst(ty::PlaceholderConst<'tcx>),
+ PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
}
impl<'tcx> CanonicalVarKind<'tcx> {
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
CanonicalVarKind::Const(ui, _) => ui,
- CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
+ CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe,
}
}
}
#![feature(allocator_api)]
#![feature(array_windows)]
#![feature(assert_matches)]
-#![feature(backtrace)]
#![feature(box_patterns)]
#![feature(core_intrinsics)]
#![feature(discriminant_kind)]
use crate::ty::{self, DefIdTree, TyCtxt};
use rustc_ast::NodeId;
-use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
+use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diagnostic};
use rustc_feature::GateIssue;
/// are filled by the annotator.
pub stab_map: FxHashMap<LocalDefId, Stability>,
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
+ pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
/// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
/// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
self.const_stab_map.get(&def_id).copied()
}
+ pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option<DefaultBodyStability> {
+ self.default_body_stab_map.get(&def_id).copied()
+ }
+
pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
self.depr_map.get(&def_id).cloned()
}
return EvalResult::Allow;
}
+ // Only the cross-crate scenario matters when checking unstable APIs
+ let cross_crate = !def_id.is_local();
+ if !cross_crate {
+ return EvalResult::Allow;
+ }
+
let stability = self.lookup_stability(def_id);
debug!(
"stability: \
def_id, span, stability
);
- // Only the cross-crate scenario matters when checking unstable APIs
- let cross_crate = !def_id.is_local();
- if !cross_crate {
- return EvalResult::Allow;
- }
-
// Issue #38412: private items lack stability markers.
if skip_stability_check_due_to_privacy(self, def_id) {
return EvalResult::Allow;
}
}
+ /// Evaluates the default-impl stability of an item.
+ ///
+ /// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding
+ /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
+ /// unstable feature otherwise.
+ pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult {
+ let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
+ if !is_staged_api {
+ return EvalResult::Allow;
+ }
+
+ // Only the cross-crate scenario matters when checking unstable APIs
+ let cross_crate = !def_id.is_local();
+ if !cross_crate {
+ return EvalResult::Allow;
+ }
+
+ let stability = self.lookup_default_body_stability(def_id);
+ debug!(
+ "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}"
+ );
+
+ // Issue #38412: private items lack stability markers.
+ if skip_stability_check_due_to_privacy(self, def_id) {
+ return EvalResult::Allow;
+ }
+
+ match stability {
+ Some(DefaultBodyStability {
+ level: attr::Unstable { reason, issue, is_soft, .. },
+ feature,
+ }) => {
+ if span.allows_unstable(feature) {
+ debug!("body stability: skipping span={:?} since it is internal", span);
+ return EvalResult::Allow;
+ }
+ if self.features().active(feature) {
+ return EvalResult::Allow;
+ }
+
+ EvalResult::Deny {
+ feature,
+ reason: reason.to_opt_reason(),
+ issue,
+ suggestion: None,
+ is_soft,
+ }
+ }
+ Some(_) => {
+ // Stable APIs are always ok to call
+ EvalResult::Allow
+ }
+ None => EvalResult::Unmarked,
+ }
+ }
+
/// Checks if an item is stable or error out.
///
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
self.local_decls[RETURN_PLACE].ty
}
+ /// Returns the return type; it always return first element from `local_decls` array.
+ #[inline]
+ pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> {
+ ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty)
+ }
+
/// Gets the location of the terminator for the given block.
#[inline]
pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
new_blocks: Vec<BasicBlockData<'tcx>>,
new_statements: Vec<(Location, StatementKind<'tcx>)>,
new_locals: Vec<LocalDecl<'tcx>>,
- resume_block: BasicBlock,
+ resume_block: Option<BasicBlock>,
+ body_span: Span,
next_local: usize,
}
new_statements: vec![],
new_locals: vec![],
next_local: body.local_decls.len(),
- resume_block: START_BLOCK,
+ resume_block: None,
+ body_span: body.span,
};
- // make sure the MIR we create has a resume block. It is
- // completely legal to convert jumps to the resume block
- // to jumps to None, but we occasionally have to add
- // instructions just before that.
-
- let mut resume_block = None;
- let mut resume_stmt_block = None;
+ // Check if we already have a resume block
for (bb, block) in body.basic_blocks().iter_enumerated() {
- if let TerminatorKind::Resume = block.terminator().kind {
- if !block.statements.is_empty() {
- assert!(resume_stmt_block.is_none());
- resume_stmt_block = Some(bb);
- } else {
- resume_block = Some(bb);
- }
+ if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() {
+ result.resume_block = Some(bb);
break;
}
}
- let resume_block = resume_block.unwrap_or_else(|| {
- result.new_block(BasicBlockData {
- statements: vec![],
- terminator: Some(Terminator {
- source_info: SourceInfo::outermost(body.span),
- kind: TerminatorKind::Resume,
- }),
- is_cleanup: true,
- })
- });
- result.resume_block = resume_block;
- if let Some(resume_stmt_block) = resume_stmt_block {
- result
- .patch_terminator(resume_stmt_block, TerminatorKind::Goto { target: resume_block });
- }
+
result
}
- pub fn resume_block(&self) -> BasicBlock {
- self.resume_block
+ pub fn resume_block(&mut self) -> BasicBlock {
+ if let Some(bb) = self.resume_block {
+ return bb;
+ }
+
+ let bb = self.new_block(BasicBlockData {
+ statements: vec![],
+ terminator: Some(Terminator {
+ source_info: SourceInfo::outermost(self.body_span),
+ kind: TerminatorKind::Resume,
+ }),
+ is_cleanup: true,
+ });
+ self.resume_block = Some(bb);
+ bb
}
pub fn is_patched(&self, bb: BasicBlock) -> bool {
self.new_blocks.len(),
body.basic_blocks().len()
);
- body.basic_blocks_mut().extend(self.new_blocks);
+ let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() {
+ body.basic_blocks.as_mut_preserves_cfg()
+ } else {
+ body.basic_blocks.as_mut()
+ };
+ bbs.extend(self.new_blocks);
body.local_decls.extend(self.new_locals);
for (src, patch) in self.patch_map.into_iter_enumerated() {
if let Some(patch) = patch {
debug!("MirPatch: patching block {:?}", src);
- body[src].terminator_mut().kind = patch;
+ bbs[src].terminator_mut().kind = patch;
}
}
pub projection: &'tcx List<PlaceElem<'tcx>>,
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Place<'_>, 16);
-
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable)]
pub enum ProjectionElem<V, T> {
/// and the index is a local.
pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
-// This type is fairly frequently used, so we shouldn't unintentionally increase
-// its size.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PlaceElem<'_>, 24);
-
///////////////////////////////////////////////////////////////////////////
// Operands
Constant(Box<Constant<'tcx>>),
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Operand<'_>, 24);
-
///////////////////////////////////////////////////////////////////////////
// Rvalues
CopyForDeref(Place<'tcx>),
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Rvalue<'_>, 40);
-
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum CastKind {
/// An exposing pointer to address cast. A cast between a pointer and an integer type, or
Generator(LocalDefId, SubstsRef<'tcx>, hir::Movability),
}
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(AggregateKind<'_>, 48);
-
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum NullOp {
/// Returns the size of a value of that type
/// The `ptr.offset` operator
Offset,
}
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ // These are in alphabetical order, which is easy to maintain.
+ static_assert_size!(AggregateKind<'_>, 48);
+ static_assert_size!(Operand<'_>, 24);
+ static_assert_size!(Place<'_>, 16);
+ static_assert_size!(PlaceElem<'_>, 24);
+ static_assert_size!(Rvalue<'_>, 40);
+}
self.super_body(body);
}
+ extra_body_methods!($($mutability)?);
+
fn visit_basic_block_data(
&mut self,
block: BasicBlock,
&mut self,
body: &$($mutability)? Body<'tcx>,
) {
- let span = body.span;
- if let Some(gen) = &$($mutability)? body.generator {
- if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
- self.visit_ty(
- yield_ty,
- TyContext::YieldTy(SourceInfo::outermost(span))
- );
- }
- }
-
- // for best performance, we want to use an iterator rather
- // than a for-loop, to avoid calling `body::Body::invalidate` for
- // each basic block.
- #[allow(unused_macro_rules)]
- macro_rules! basic_blocks {
- (mut) => (body.basic_blocks_mut().iter_enumerated_mut());
- () => (body.basic_blocks().iter_enumerated());
- }
- for (bb, data) in basic_blocks!($($mutability)?) {
- self.visit_basic_block_data(bb, data);
- }
-
- for scope in &$($mutability)? body.source_scopes {
- self.visit_source_scope_data(scope);
- }
-
- self.visit_ty(
- $(& $mutability)? body.return_ty(),
- TyContext::ReturnTy(SourceInfo::outermost(body.span))
- );
-
- for local in body.local_decls.indices() {
- self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
- }
-
- #[allow(unused_macro_rules)]
- macro_rules! type_annotations {
- (mut) => (body.user_type_annotations.iter_enumerated_mut());
- () => (body.user_type_annotations.iter_enumerated());
- }
-
- for (index, annotation) in type_annotations!($($mutability)?) {
- self.visit_user_type_annotation(
- index, annotation
- );
- }
-
- for var_debug_info in &$($mutability)? body.var_debug_info {
- self.visit_var_debug_info(var_debug_info);
- }
-
- self.visit_span($(& $mutability)? body.span);
-
- for const_ in &$($mutability)? body.required_consts {
- let location = START_BLOCK.start_location();
- self.visit_constant(const_, location);
- }
+ super_body!(self, body, $($mutability, true)?);
}
fn super_basic_block_data(&mut self,
body: &$($mutability)? Body<'tcx>,
location: Location
) {
- #[allow(unused_macro_rules)]
- macro_rules! basic_blocks {
- (mut) => (body.basic_blocks_mut());
- () => (body.basic_blocks());
- }
- let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block];
+ let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
if basic_block.statements.len() == location.statement_index {
if let Some(ref $($mutability)? terminator) = basic_block.terminator {
self.visit_terminator(terminator, location)
}
}
+macro_rules! basic_blocks {
+ ($body:ident, mut, true) => {
+ $body.basic_blocks.as_mut()
+ };
+ ($body:ident, mut, false) => {
+ $body.basic_blocks.as_mut_preserves_cfg()
+ };
+ ($body:ident,) => {
+ $body.basic_blocks()
+ };
+}
+
+macro_rules! basic_blocks_iter {
+ ($body:ident, mut, $invalidate:tt) => {
+ basic_blocks!($body, mut, $invalidate).iter_enumerated_mut()
+ };
+ ($body:ident,) => {
+ basic_blocks!($body,).iter_enumerated()
+ };
+}
+
+macro_rules! extra_body_methods {
+ (mut) => {
+ fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
+ self.super_body_preserves_cfg(body);
+ }
+
+ fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
+ super_body!(self, body, mut, false);
+ }
+ };
+ () => {};
+}
+
+macro_rules! super_body {
+ ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
+ let span = $body.span;
+ if let Some(gen) = &$($mutability)? $body.generator {
+ if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
+ $self.visit_ty(
+ yield_ty,
+ TyContext::YieldTy(SourceInfo::outermost(span))
+ );
+ }
+ }
+
+ for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
+ $self.visit_basic_block_data(bb, data);
+ }
+
+ for scope in &$($mutability)? $body.source_scopes {
+ $self.visit_source_scope_data(scope);
+ }
+
+ $self.visit_ty(
+ $(& $mutability)? $body.return_ty(),
+ TyContext::ReturnTy(SourceInfo::outermost($body.span))
+ );
+
+ for local in $body.local_decls.indices() {
+ $self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]);
+ }
+
+ #[allow(unused_macro_rules)]
+ macro_rules! type_annotations {
+ (mut) => ($body.user_type_annotations.iter_enumerated_mut());
+ () => ($body.user_type_annotations.iter_enumerated());
+ }
+
+ for (index, annotation) in type_annotations!($($mutability)?) {
+ $self.visit_user_type_annotation(
+ index, annotation
+ );
+ }
+
+ for var_debug_info in &$($mutability)? $body.var_debug_info {
+ $self.visit_var_debug_info(var_debug_info);
+ }
+
+ $self.visit_span($(& $mutability)? $body.span);
+
+ for const_ in &$($mutability)? $body.required_consts {
+ let location = START_BLOCK.start_location();
+ $self.visit_constant(const_, location);
+ }
+ }
+}
+
macro_rules! visit_place_fns {
(mut) => {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
separate_provide_extern
}
+ query lookup_default_body_stability(def_id: DefId) -> Option<attr::DefaultBodyStability> {
+ desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
+ }
+
query should_inherit_track_caller(def_id: DefId) -> bool {
desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
}
separate_provide_extern
}
- /// Given an `associated_item`, find the trait it belongs to.
- /// Return `None` if the `DefId` is not an associated item.
- query trait_of_item(associated_item: DefId) -> Option<DefId> {
- desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
- cache_on_disk_if { associated_item.is_local() }
- separate_provide_extern
- }
-
query is_ctfe_mir_available(key: DefId) -> bool {
desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
}
}
+ query is_impossible_method(key: (DefId, DefId)) -> bool {
+ desc { |tcx|
+ "checking if {} is impossible to call within {}",
+ tcx.def_path_str(key.1),
+ tcx.def_path_str(key.0),
+ }
+ }
+
query method_autoderef_steps(
goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> {
},
}
-// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr<'_>, 104);
-
#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct LocalVarId(pub hir::HirId);
}
}
}
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ // These are in alphabetical order, which is easy to maintain.
+ static_assert_size!(Block, 56);
+ static_assert_size!(Expr<'_>, 104);
+ static_assert_size!(Pat<'_>, 24);
+ static_assert_size!(Stmt<'_>, 120);
+}
/// `false` if there are no *further* obligations.
has_nested: bool,
},
+
+ /// Implementation of transmutability trait.
+ TransmutabilityCandidate,
+
ParamCandidate(ty::PolyTraitPredicate<'tcx>),
ImplCandidate(DefId),
AutoImplCandidate(DefId),
self.find_map(|node| {
if let Some(item) = node.item(tcx, trait_item_def_id) {
if finalizing_node.is_none() {
- let is_specializable = item.defaultness.is_default()
+ let is_specializable = item.defaultness(tcx).is_default()
|| tcx.impl_defaultness(node.def_id()).is_default();
if !is_specializable {
///
/// Due to normalization being eager, this applies even if
/// the associated type is behind a pointer (e.g., issue #31299).
- pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] {
- tcx.adt_sized_constraint(self.did()).0
+ pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
+ ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
}
}
pub use self::AssocItemContainer::*;
-use crate::ty;
+use crate::ty::{self, DefIdTree};
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace};
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
pub enum AssocItemContainer {
- TraitContainer(DefId),
- ImplContainer(DefId),
-}
-
-impl AssocItemContainer {
- pub fn impl_def_id(&self) -> Option<DefId> {
- match *self {
- ImplContainer(id) => Some(id),
- _ => None,
- }
- }
-
- /// Asserts that this is the `DefId` of an associated item declared
- /// in a trait, and returns the trait `DefId`.
- pub fn assert_trait(&self) -> DefId {
- match *self {
- TraitContainer(id) => id,
- _ => bug!("associated item has wrong container type: {:?}", self),
- }
- }
-
- pub fn id(&self) -> DefId {
- match *self {
- TraitContainer(id) => id,
- ImplContainer(id) => id,
- }
- }
+ TraitContainer,
+ ImplContainer,
}
/// Information about an associated item
pub def_id: DefId,
pub name: Symbol,
pub kind: AssocKind,
- pub vis: Visibility,
- pub defaultness: hir::Defaultness,
pub container: AssocItemContainer,
/// If this is an item in an impl of a trait then this is the `DefId` of
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
}
+ pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
+ tcx.impl_defaultness(self.def_id)
+ }
+
+ #[inline]
+ pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility {
+ tcx.visibility(self.def_id)
+ }
+
+ #[inline]
+ pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
+ tcx.parent(self.def_id)
+ }
+
+ #[inline]
+ pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+ match self.container {
+ AssocItemContainer::ImplContainer => None,
+ AssocItemContainer::TraitContainer => Some(tcx.parent(self.def_id)),
+ }
+ }
+
+ #[inline]
+ pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+ match self.container {
+ AssocItemContainer::ImplContainer => Some(tcx.parent(self.def_id)),
+ AssocItemContainer::TraitContainer => None,
+ }
+ }
+
pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
match self.kind {
ty::AssocKind::Fn => {
};
format!(
- "{}[{}]{}",
+ "{}[{:04x}]{}",
crate_name,
// Don't print the whole stable crate id. That's just
// annoying in debug output.
- &(format!("{:08x}", stable_crate_id.to_u64()))[..4],
+ stable_crate_id.to_u64() >> 8 * 6,
self.def_path(def_id).to_string_no_crate_verbose()
)
}
// Checks if the bound region is in Impl Item.
pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool {
- let container_id =
- self.associated_item(suitable_region_binding_scope.to_def_id()).container.id();
+ let container_id = self.parent(suitable_region_binding_scope.to_def_id());
if self.impl_trait_ref(container_id).is_some() {
// For now, we do not try to target impls of traits. This is
// because this message is going to suggest that the user
// the associated type or calling a method that returns the associated type".
let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
diag,
- assoc.container.id(),
+ assoc.container_id(self),
current_method_ident,
proj_ty.item_def_id,
values.expected,
hir::AssocItemKind::Type => {
// FIXME: account for returning some type in a trait fn impl that has
// an assoc type as a return type (#72076).
- if let hir::Defaultness::Default { has_value: true } = item.defaultness
+ if let hir::Defaultness::Default { has_value: true } =
+ self.impl_defaultness(item.id.def_id)
{
if self.type_of(item.id.def_id) == found {
diag.span_label(
&& !matches!(
tcx.opt_associated_item(def.did),
Some(ty::AssocItem {
- container: ty::AssocItemContainer::TraitContainer(_),
+ container: ty::AssocItemContainer::TraitContainer,
..
})
)
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
use crate::ty::normalize_erasing_regions::NormalizationError;
use crate::ty::subst::Subst;
-use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable};
+use crate::ty::{
+ self, layout_sanity_check::sanity_check_layout, subst::SubstsRef, EarlyBinder, ReprOptions, Ty,
+ TyCtxt, TypeVisitable,
+};
use rustc_ast as ast;
use rustc_attr as attr;
use rustc_hir as hir;
}
}
-/// Enforce some basic invariants on layouts.
-fn sanity_check_layout<'tcx>(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- layout: &TyAndLayout<'tcx>,
-) {
- // Type-level uninhabitedness should always imply ABI uninhabitedness.
- if tcx.conservative_is_privately_uninhabited(param_env.and(layout.ty)) {
- assert!(layout.abi.is_uninhabited());
- }
-
- if layout.size.bytes() % layout.align.abi.bytes() != 0 {
- bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
- }
-
- if cfg!(debug_assertions) {
- fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) {
- match layout.abi() {
- Abi::Scalar(scalar) => {
- // No padding in scalars.
- assert_eq!(
- layout.align().abi,
- scalar.align(&tcx).abi,
- "alignment mismatch between ABI and layout in {layout:#?}"
- );
- assert_eq!(
- layout.size(),
- scalar.size(&tcx),
- "size mismatch between ABI and layout in {layout:#?}"
- );
- }
- Abi::Vector { count, element } => {
- // No padding in vectors. Alignment can be strengthened, though.
- assert!(
- layout.align().abi >= element.align(&tcx).abi,
- "alignment mismatch between ABI and layout in {layout:#?}"
- );
- let size = element.size(&tcx) * count;
- assert_eq!(
- layout.size(),
- size.align_to(tcx.data_layout().vector_align(size).abi),
- "size mismatch between ABI and layout in {layout:#?}"
- );
- }
- Abi::ScalarPair(scalar1, scalar2) => {
- // Sanity-check scalar pairs. These are a bit more flexible and support
- // padding, but we can at least ensure both fields actually fit into the layout
- // and the alignment requirement has not been weakened.
- let align1 = scalar1.align(&tcx).abi;
- let align2 = scalar2.align(&tcx).abi;
- assert!(
- layout.align().abi >= cmp::max(align1, align2),
- "alignment mismatch between ABI and layout in {layout:#?}",
- );
- let field2_offset = scalar1.size(&tcx).align_to(align2);
- assert!(
- layout.size() >= field2_offset + scalar2.size(&tcx),
- "size mismatch between ABI and layout in {layout:#?}"
- );
- }
- Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
- }
- }
-
- check_layout_abi(tcx, layout.layout);
-
- if let Variants::Multiple { variants, .. } = &layout.variants {
- for variant in variants {
- check_layout_abi(tcx, *variant);
- // No nested "multiple".
- assert!(matches!(variant.variants(), Variants::Single { .. }));
- // Skip empty variants.
- if variant.size() == Size::ZERO
- || variant.fields().count() == 0
- || variant.abi().is_uninhabited()
- {
- // These are never actually accessed anyway, so we can skip them. (Note that
- // sometimes, variants with fields have size 0, and sometimes, variants without
- // fields have non-0 size.)
- continue;
- }
- // Variants should have the same or a smaller size as the full thing.
- if variant.size() > layout.size {
- bug!(
- "Type with size {} bytes has variant with size {} bytes: {layout:#?}",
- layout.size.bytes(),
- variant.size().bytes(),
- )
- }
- // The top-level ABI and the ABI of the variants should be coherent.
- let abi_coherent = match (layout.abi, variant.abi()) {
- (Abi::Scalar(..), Abi::Scalar(..)) => true,
- (Abi::ScalarPair(..), Abi::ScalarPair(..)) => true,
- (Abi::Uninhabited, _) => true,
- (Abi::Aggregate { .. }, _) => true,
- _ => false,
- };
- if !abi_coherent {
- bug!(
- "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}",
- variant
- );
- }
- }
- }
- }
-}
-
#[instrument(skip(tcx, query), level = "debug")]
fn layout_of<'tcx>(
tcx: TyCtxt<'tcx>,
cx.record_layout_for_printing(layout);
- sanity_check_layout(tcx, param_env, &layout);
+ sanity_check_layout(&cx, &layout);
Ok(layout)
})
--- /dev/null
+use crate::ty::{
+ layout::{LayoutCx, TyAndLayout},
+ TyCtxt,
+};
+use rustc_target::abi::*;
+
+use std::cmp;
+
+/// Enforce some basic invariants on layouts.
+pub(super) fn sanity_check_layout<'tcx>(
+ cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+ layout: &TyAndLayout<'tcx>,
+) {
+ // Type-level uninhabitedness should always imply ABI uninhabitedness.
+ if cx.tcx.conservative_is_privately_uninhabited(cx.param_env.and(layout.ty)) {
+ assert!(layout.abi.is_uninhabited());
+ }
+
+ if layout.size.bytes() % layout.align.abi.bytes() != 0 {
+ bug!("size is not a multiple of align, in the following layout:\n{layout:#?}");
+ }
+
+ if cfg!(debug_assertions) {
+ /// Yields non-ZST fields of the type
+ fn non_zst_fields<'tcx, 'a>(
+ cx: &'a LayoutCx<'tcx, TyCtxt<'tcx>>,
+ layout: &'a TyAndLayout<'tcx>,
+ ) -> impl Iterator<Item = (Size, TyAndLayout<'tcx>)> + 'a {
+ (0..layout.layout.fields().count()).filter_map(|i| {
+ let field = layout.field(cx, i);
+ // Also checking `align == 1` here leads to test failures in
+ // `layout/zero-sized-array-union.rs`, where a type has a zero-size field with
+ // alignment 4 that still gets ignored during layout computation (which is okay
+ // since other fields already force alignment 4).
+ let zst = field.is_zst();
+ (!zst).then(|| (layout.fields.offset(i), field))
+ })
+ }
+
+ fn skip_newtypes<'tcx>(
+ cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+ layout: &TyAndLayout<'tcx>,
+ ) -> TyAndLayout<'tcx> {
+ if matches!(layout.layout.variants(), Variants::Multiple { .. }) {
+ // Definitely not a newtype of anything.
+ return *layout;
+ }
+ let mut fields = non_zst_fields(cx, layout);
+ let Some(first) = fields.next() else {
+ // No fields here, so this could be a primitive or enum -- either way it's not a newtype around a thing
+ return *layout
+ };
+ if fields.next().is_none() {
+ let (offset, first) = first;
+ if offset == Size::ZERO && first.layout.size() == layout.size {
+ // This is a newtype, so keep recursing.
+ // FIXME(RalfJung): I don't think it would be correct to do any checks for
+ // alignment here, so we don't. Is that correct?
+ return skip_newtypes(cx, &first);
+ }
+ }
+ // No more newtypes here.
+ *layout
+ }
+
+ fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) {
+ match layout.layout.abi() {
+ Abi::Scalar(scalar) => {
+ // No padding in scalars.
+ let size = scalar.size(cx);
+ let align = scalar.align(cx).abi;
+ assert_eq!(
+ layout.layout.size(),
+ size,
+ "size mismatch between ABI and layout in {layout:#?}"
+ );
+ assert_eq!(
+ layout.layout.align().abi,
+ align,
+ "alignment mismatch between ABI and layout in {layout:#?}"
+ );
+ // Check that this matches the underlying field.
+ let inner = skip_newtypes(cx, layout);
+ assert!(
+ matches!(inner.layout.abi(), Abi::Scalar(_)),
+ "`Scalar` type {} is newtype around non-`Scalar` type {}",
+ layout.ty,
+ inner.ty
+ );
+ match inner.layout.fields() {
+ FieldsShape::Primitive => {
+ // Fine.
+ }
+ FieldsShape::Union(..) => {
+ // FIXME: I guess we could also check something here? Like, look at all fields?
+ return;
+ }
+ FieldsShape::Arbitrary { .. } => {
+ // Should be an enum, the only field is the discriminant.
+ assert!(
+ inner.ty.is_enum(),
+ "`Scalar` layout for non-primitive non-enum type {}",
+ inner.ty
+ );
+ assert_eq!(
+ inner.layout.fields().count(),
+ 1,
+ "`Scalar` layout for multiple-field type in {inner:#?}",
+ );
+ let offset = inner.layout.fields().offset(0);
+ let field = inner.field(cx, 0);
+ // The field should be at the right offset, and match the `scalar` layout.
+ assert_eq!(
+ offset,
+ Size::ZERO,
+ "`Scalar` field at non-0 offset in {inner:#?}",
+ );
+ assert_eq!(
+ field.size, size,
+ "`Scalar` field with bad size in {inner:#?}",
+ );
+ assert_eq!(
+ field.align.abi, align,
+ "`Scalar` field with bad align in {inner:#?}",
+ );
+ assert!(
+ matches!(field.abi, Abi::Scalar(_)),
+ "`Scalar` field with bad ABI in {inner:#?}",
+ );
+ }
+ _ => {
+ panic!("`Scalar` layout for non-primitive non-enum type {}", inner.ty);
+ }
+ }
+ }
+ Abi::ScalarPair(scalar1, scalar2) => {
+ // Sanity-check scalar pairs. These are a bit more flexible and support
+ // padding, but we can at least ensure both fields actually fit into the layout
+ // and the alignment requirement has not been weakened.
+ let size1 = scalar1.size(cx);
+ let align1 = scalar1.align(cx).abi;
+ let size2 = scalar2.size(cx);
+ let align2 = scalar2.align(cx).abi;
+ assert!(
+ layout.layout.align().abi >= cmp::max(align1, align2),
+ "alignment mismatch between ABI and layout in {layout:#?}",
+ );
+ let field2_offset = size1.align_to(align2);
+ assert!(
+ layout.layout.size() >= field2_offset + size2,
+ "size mismatch between ABI and layout in {layout:#?}"
+ );
+ // Check that the underlying pair of fields matches.
+ let inner = skip_newtypes(cx, layout);
+ assert!(
+ matches!(inner.layout.abi(), Abi::ScalarPair(..)),
+ "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}",
+ layout.ty,
+ inner.ty
+ );
+ if matches!(inner.layout.variants(), Variants::Multiple { .. }) {
+ // FIXME: ScalarPair for enums is enormously complicated and it is very hard
+ // to check anything about them.
+ return;
+ }
+ match inner.layout.fields() {
+ FieldsShape::Arbitrary { .. } => {
+ // Checked below.
+ }
+ FieldsShape::Union(..) => {
+ // FIXME: I guess we could also check something here? Like, look at all fields?
+ return;
+ }
+ _ => {
+ panic!("`ScalarPair` layout with unexpected field shape in {inner:#?}");
+ }
+ }
+ let mut fields = non_zst_fields(cx, &inner);
+ let (offset1, field1) = fields.next().unwrap_or_else(|| {
+ panic!("`ScalarPair` layout for type with not even one non-ZST field: {inner:#?}")
+ });
+ let (offset2, field2) = fields.next().unwrap_or_else(|| {
+ panic!("`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}")
+ });
+ assert!(
+ fields.next().is_none(),
+ "`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}"
+ );
+ // The fields might be in opposite order.
+ let (offset1, field1, offset2, field2) = if offset1 <= offset2 {
+ (offset1, field1, offset2, field2)
+ } else {
+ (offset2, field2, offset1, field1)
+ };
+ // The fields should be at the right offset, and match the `scalar` layout.
+ assert_eq!(
+ offset1,
+ Size::ZERO,
+ "`ScalarPair` first field at non-0 offset in {inner:#?}",
+ );
+ assert_eq!(
+ field1.size, size1,
+ "`ScalarPair` first field with bad size in {inner:#?}",
+ );
+ assert_eq!(
+ field1.align.abi, align1,
+ "`ScalarPair` first field with bad align in {inner:#?}",
+ );
+ assert!(
+ matches!(field1.abi, Abi::Scalar(_)),
+ "`ScalarPair` first field with bad ABI in {inner:#?}",
+ );
+ assert_eq!(
+ offset2, field2_offset,
+ "`ScalarPair` second field at bad offset in {inner:#?}",
+ );
+ assert_eq!(
+ field2.size, size2,
+ "`ScalarPair` second field with bad size in {inner:#?}",
+ );
+ assert_eq!(
+ field2.align.abi, align2,
+ "`ScalarPair` second field with bad align in {inner:#?}",
+ );
+ assert!(
+ matches!(field2.abi, Abi::Scalar(_)),
+ "`ScalarPair` second field with bad ABI in {inner:#?}",
+ );
+ }
+ Abi::Vector { count, element } => {
+ // No padding in vectors. Alignment can be strengthened, though.
+ assert!(
+ layout.layout.align().abi >= element.align(cx).abi,
+ "alignment mismatch between ABI and layout in {layout:#?}"
+ );
+ let size = element.size(cx) * count;
+ assert_eq!(
+ layout.layout.size(),
+ size.align_to(cx.data_layout().vector_align(size).abi),
+ "size mismatch between ABI and layout in {layout:#?}"
+ );
+ }
+ Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
+ }
+ }
+
+ check_layout_abi(cx, layout);
+
+ if let Variants::Multiple { variants, .. } = &layout.variants {
+ for variant in variants.iter() {
+ // No nested "multiple".
+ assert!(matches!(variant.variants(), Variants::Single { .. }));
+ // Variants should have the same or a smaller size as the full thing,
+ // and same for alignment.
+ if variant.size() > layout.size {
+ bug!(
+ "Type with size {} bytes has variant with size {} bytes: {layout:#?}",
+ layout.size.bytes(),
+ variant.size().bytes(),
+ )
+ }
+ if variant.align().abi > layout.align.abi {
+ bug!(
+ "Type with alignment {} bytes has variant with alignment {} bytes: {layout:#?}",
+ layout.align.abi.bytes(),
+ variant.align().abi.bytes(),
+ )
+ }
+ // Skip empty variants.
+ if variant.size() == Size::ZERO
+ || variant.fields().count() == 0
+ || variant.abi().is_uninhabited()
+ {
+ // These are never actually accessed anyway, so we can skip the coherence check
+ // for them. They also fail that check, since they have
+ // `Aggregate`/`Uninhbaited` ABI even when the main type is
+ // `Scalar`/`ScalarPair`. (Note that sometimes, variants with fields have size
+ // 0, and sometimes, variants without fields have non-0 size.)
+ continue;
+ }
+ // The top-level ABI and the ABI of the variants should be coherent.
+ let scalar_coherent = |s1: Scalar, s2: Scalar| {
+ s1.size(cx) == s2.size(cx) && s1.align(cx) == s2.align(cx)
+ };
+ let abi_coherent = match (layout.abi, variant.abi()) {
+ (Abi::Scalar(s1), Abi::Scalar(s2)) => scalar_coherent(s1, s2),
+ (Abi::ScalarPair(a1, b1), Abi::ScalarPair(a2, b2)) => {
+ scalar_coherent(a1, a2) && scalar_coherent(b1, b2)
+ }
+ (Abi::Uninhabited, _) => true,
+ (Abi::Aggregate { .. }, _) => true,
+ _ => false,
+ };
+ if !abi_coherent {
+ bug!(
+ "Variant ABI is incompatible with top-level ABI:\nvariant={:#?}\nTop-level: {layout:#?}",
+ variant
+ );
+ }
+ }
+ }
+ }
+}
pub use vtable::*;
use std::fmt::Debug;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
use std::ops::ControlFlow;
use std::{fmt, str};
mod generics;
mod impls_ty;
mod instance;
+mod layout_sanity_check;
mod list;
mod parameterized;
mod rvalue_scopes;
pub label_res_map: NodeMap<ast::NodeId>,
/// Resolutions for lifetimes.
pub lifetimes_res_map: NodeMap<LifetimeRes>,
+ /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
+ /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
+ /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
+ /// field from the original parameter 'a to the new parameter 'a1.
+ pub generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
/// Lifetime parameters that lowering will have to introduce.
pub extra_lifetime_params_map: NodeMap<Vec<(Ident, ast::NodeId, LifetimeRes)>>,
}
self
}
+
+ /// Whether this projection can be soundly normalized.
+ ///
+ /// Wf predicates must not be normalized, as normalization
+ /// can remove required bounds which would cause us to
+ /// unsoundly accept some programs. See #91068.
+ #[inline]
+ pub fn allow_normalization(self) -> bool {
+ match self.kind().skip_binder() {
+ PredicateKind::WellFormed(_) => false,
+ PredicateKind::Trait(_)
+ | PredicateKind::RegionOutlives(_)
+ | PredicateKind::TypeOutlives(_)
+ | PredicateKind::Projection(_)
+ | PredicateKind::ObjectSafe(_)
+ | PredicateKind::ClosureKind(_, _, _)
+ | PredicateKind::Subtype(_)
+ | PredicateKind::Coerce(_)
+ | PredicateKind::ConstEvaluatable(_)
+ | PredicateKind::ConstEquate(_, _)
+ | PredicateKind::TypeWellFormedFromEnv(_) => true,
+ }
+ }
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
pub ty: Ty<'tcx>,
}
-pub type PlaceholderConst<'tcx> = Placeholder<BoundConst<'tcx>>;
+pub type PlaceholderConst<'tcx> = Placeholder<BoundVar>;
/// A `DefId` which, in case it is a const argument, is potentially bundled with
/// the `DefId` of the generic parameter it instantiates.
}
}
+impl PartialEq for VariantDef {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ // There should be only one `VariantDef` for each `def_id`, therefore
+ // it is fine to implement `PartialEq` only based on `def_id`.
+ //
+ // Below, we exhaustively destructure `self` and `other` so that if the
+ // definition of `VariantDef` changes, a compile-error will be produced,
+ // reminding us to revisit this assumption.
+
+ let Self {
+ def_id: lhs_def_id,
+ ctor_def_id: _,
+ name: _,
+ discr: _,
+ fields: _,
+ ctor_kind: _,
+ flags: _,
+ } = &self;
+
+ let Self {
+ def_id: rhs_def_id,
+ ctor_def_id: _,
+ name: _,
+ discr: _,
+ fields: _,
+ ctor_kind: _,
+ flags: _,
+ } = other;
+
+ lhs_def_id == rhs_def_id
+ }
+}
+
+impl Eq for VariantDef {}
+
+impl Hash for VariantDef {
+ #[inline]
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // There should be only one `VariantDef` for each `def_id`, therefore
+ // it is fine to implement `Hash` only based on `def_id`.
+ //
+ // Below, we exhaustively destructure `self` so that if the definition
+ // of `VariantDef` changes, a compile-error will be produced, reminding
+ // us to revisit this assumption.
+
+ let Self { def_id, ctor_def_id: _, name: _, discr: _, fields: _, ctor_kind: _, flags: _ } =
+ &self;
+
+ def_id.hash(s)
+ }
+}
+
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub enum VariantDiscr {
/// Explicit value for this variant, i.e., `X = 123`.
pub vis: Visibility,
}
+impl PartialEq for FieldDef {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ // There should be only one `FieldDef` for each `did`, therefore it is
+ // fine to implement `PartialEq` only based on `did`.
+ //
+ // Below, we exhaustively destructure `self` so that if the definition
+ // of `FieldDef` changes, a compile-error will be produced, reminding
+ // us to revisit this assumption.
+
+ let Self { did: lhs_did, name: _, vis: _ } = &self;
+
+ let Self { did: rhs_did, name: _, vis: _ } = other;
+
+ lhs_did == rhs_did
+ }
+}
+
+impl Eq for FieldDef {}
+
+impl Hash for FieldDef {
+ #[inline]
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ // There should be only one `FieldDef` for each `did`, therefore it is
+ // fine to implement `Hash` only based on `did`.
+ //
+ // Below, we exhaustively destructure `self` so that if the definition
+ // of `FieldDef` changes, a compile-error will be produced, reminding
+ // us to revisit this assumption.
+
+ let Self { did, name: _, vis: _ } = &self;
+
+ did.hash(s)
+ }
+}
+
bitflags! {
#[derive(TyEncodable, TyDecodable, Default, HashStable)]
pub struct ReprFlags: u8 {
pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
self.associated_items(id)
.in_definition_order()
- .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value())
+ .filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
}
/// Look up the name of a definition across crates. This does not look at HIR.
self.impl_trait_ref(def_id).map(|tr| tr.def_id)
}
+ /// If the given `DefId` describes an item belonging to a trait,
+ /// returns the `DefId` of the trait that the trait item belongs to;
+ /// otherwise, returns `None`.
+ pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
+ if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+ let parent = self.parent(def_id);
+ if let DefKind::Trait | DefKind::TraitAlias = self.def_kind(parent) {
+ return Some(parent);
+ }
+ }
+ None
+ }
+
/// If the given `DefId` describes a method belonging to an impl, returns the
/// `DefId` of the impl that the method belongs to; otherwise, returns `None`.
pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
- self.opt_associated_item(def_id).and_then(|trait_item| match trait_item.container {
- TraitContainer(_) => None,
- ImplContainer(def_id) => Some(def_id),
- })
+ if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+ let parent = self.parent(def_id);
+ if let DefKind::Impl = self.def_kind(parent) {
+ return Some(parent);
+ }
+ }
+ None
}
/// If the given `DefId` belongs to a trait that was automatically derived, returns `true`.
rustc_ast::Attribute,
rustc_ast::MacArgs,
rustc_attr::ConstStability,
+ rustc_attr::DefaultBodyStability,
rustc_attr::Deprecation,
rustc_attr::Stability,
rustc_hir::Constness,
}
return Ok(self);
}
+ (ty::ValTree::Leaf(leaf), ty::Ref(_, inner_ty, _)) => {
+ p!(write("&"));
+ return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty);
+ }
(ty::ValTree::Leaf(leaf), _) => {
return self.pretty_print_const_scalar_int(leaf, ty, print_ty);
}
/// The `DefId` of the `TraitItem` for the associated type `N`.
///
/// Note that this is not the `DefId` of the `TraitRef` containing this
- /// associated type, which is in `tcx.associated_item(item_def_id).container`.
+ /// associated type, which is in `tcx.associated_item(item_def_id).container`,
+ /// aka. `tcx.parent(item_def_id).unwrap()`.
pub item_def_id: DefId,
}
impl<'tcx> ProjectionTy<'tcx> {
pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
- tcx.associated_item(self.item_def_id).container.id()
+ tcx.parent(self.item_def_id)
}
/// Extracts the underlying trait reference and own substs from this projection.
&self,
tcx: TyCtxt<'tcx>,
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
- let def_id = tcx.associated_item(self.item_def_id).container.id();
+ let def_id = tcx.parent(self.item_def_id);
let trait_generics = tcx.generics_of(def_id);
(
ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
/// then this function would return an `exists T. T: Iterator` existential trait
/// reference.
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
- let def_id = tcx.associated_item(self.item_def_id).container.id();
+ let def_id = tcx.parent(self.item_def_id);
let subst_count = tcx.generics_of(def_id).count() - 1;
let substs = tcx.intern_substs(&self.substs[..subst_count]);
ty::ExistentialTraitRef { def_id, substs }
ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)),
- ty::Adt(def, _substs) => def.sized_constraint(tcx).is_empty(),
+ ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(),
ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false,
Some(dtor) => dtor.did,
};
- let impl_def_id = self.associated_item(dtor).container.id();
+ let impl_def_id = self.parent(dtor);
let impl_generics = self.generics_of(impl_def_id);
// We have a destructor - all the parameters that are not
pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
ty::EarlyBinder(self.const_param_default(def_id))
}
+
+ pub fn bound_predicates_of(
+ self,
+ def_id: DefId,
+ ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
+ ty::EarlyBinder(self.predicates_of(def_id))
+ }
+
+ pub fn bound_explicit_predicates_of(
+ self,
+ def_id: DefId,
+ ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
+ ty::EarlyBinder(self.explicit_predicates_of(def_id))
+ }
+
+ pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> {
+ ty::EarlyBinder(self.impl_subject(def_id))
+ }
}
struct OpaqueTypeExpander<'tcx> {
let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms);
- let match_has_guard = arms.iter().copied().any(|arm| self.thir[arm].guard.is_some());
+ let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard);
let mut candidates =
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
// This place is not really used because this destination place
// should never be used to take values at the end of the failure
// block.
- let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() };
+ let dummy_place = self.temp(self.tcx.types.never, else_block.span);
let failure_block;
unpack!(
failure_block = self.ast_block(
use rustc_data_structures::graph::iterate::{
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
};
-use rustc_hir::intravisit::FnKind;
+use rustc_hir::def::DefKind;
use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
-use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
+use rustc_middle::ty::{self, Instance, TyCtxt};
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
use rustc_span::Span;
use std::ops::ControlFlow;
pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let def_id = body.source.def_id().expect_local();
- if let Some(fn_kind) = tcx.hir().get_by_def_id(def_id).fn_kind() {
- if let FnKind::Closure = fn_kind {
- // closures can't recur, so they don't matter.
- return;
- }
-
+ if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) {
// If this is trait/impl method, extract the trait's substs.
- let trait_substs = match tcx.opt_associated_item(def_id.to_def_id()) {
- Some(AssocItem {
- container: AssocItemContainer::TraitContainer(trait_def_id), ..
- }) => {
- let trait_substs_count = tcx.generics_of(*trait_def_id).count();
+ let trait_substs = match tcx.trait_of_item(def_id.to_def_id()) {
+ Some(trait_def_id) => {
+ let trait_substs_count = tcx.generics_of(trait_def_id).count();
&InternalSubsts::identity_for_item(tcx, def_id.to_def_id())[..trait_substs_count]
}
_ => &[],
vis.reachable_recursive_calls.sort();
+ let sp = tcx.def_span(def_id);
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let sp = tcx.sess.source_map().guess_head_span(tcx.hir().span_with_body(hir_id));
tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
let mut db = lint.build("function cannot return without recursing");
db.span_label(sp, "cannot return without recursing");
));
}
[.., prev, last] if prev.span.eq_ctxt(last.span) => {
- if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) {
- let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
- && last.span.eq_ctxt(last.body.span)
- {
- ""
- } else {
- ","
- };
+ let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
+ && last.span.eq_ctxt(last.body.span)
+ {
+ ""
+ } else {
+ ","
+ };
+ let spacing = if sm.is_multiline(prev.span.between(last.span)) {
+ sm.indentation_before(last.span).map(|indent| format!("\n{indent}"))
+ } else {
+ Some(" ".to_string())
+ };
+ if let Some(spacing) = spacing {
suggestion = Some((
last.span.shrink_to_hi(),
- format!(
- "{}{}{} => todo!()",
- comma,
- snippet.strip_prefix(',').unwrap_or(&snippet),
- pattern
- ),
+ format!("{}{}{} => todo!()", comma, spacing, pattern),
));
}
}
// once indirect_structural_match is a full fledged error, this
// level of indirection can be eliminated
- let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap();
+ let inlined_const_as_pat =
+ self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| Pat {
+ span: self.span,
+ ty: cv.ty(),
+ kind: Box::new(PatKind::Constant { value: cv }),
+ });
if self.include_lint_checks && !self.saw_const_match_error.get() {
// If we were able to successfully convert the const to some pat,
/// Lint on likely incorrect range patterns (#63987)
pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>(
&self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
+ pcx: &PatCtxt<'_, 'p, 'tcx>,
pats: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>,
column_count: usize,
hir_id: HirId,
// The only admissible fixed-length slice is one of the array size. Whether `max_slice`
// is fixed-length or variable-length, it will be the only relevant slice to output
// here.
- Some(_) => (0..0), // empty range
+ Some(_) => 0..0, // empty range
// We cover all arities in the range `(self.arity..infinity)`. We split that range into
// two: lengths smaller than `max_slice.arity()` are treated independently as
// fixed-lengths slices, and lengths above are captured by `max_slice`.
/// `EvalResult::Deny { .. }`.
///
/// This means that the variant has a stdlib unstable feature marking it.
- pub(super) fn is_unstable_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+ pub(super) fn is_unstable_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool {
if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
let variant_def_id = adt.variant(*idx).def_id;
// Filter variants that depend on a disabled unstable feature.
/// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]`
/// attribute from a type not local to the current crate.
- pub(super) fn is_doc_hidden_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+ pub(super) fn is_doc_hidden_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool {
if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
let variant_def_id = adt.variants()[*idx].def_id;
return pcx.cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local();
/// 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 {
+ pub(super) fn arity(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> usize {
match self {
Single | Variant(_) => match pcx.ty.kind() {
ty::Tuple(fs) => fs.len(),
/// matrix, unless all of them are.
pub(super) fn split<'a>(
&self,
- pcx: PatCtxt<'_, '_, 'tcx>,
+ pcx: &PatCtxt<'_, '_, 'tcx>,
ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
) -> SmallVec<[Self; 1]>
where
/// this checks for inclusion.
// We inline because this has a single call site in `Matrix::specialize_constructor`.
#[inline]
- pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
+ pub(super) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
// This must be kept in sync with `is_covered_by_any`.
match (self, other) {
// Wildcards cover anything
/// assumed to have been split from a wildcard.
fn is_covered_by_any<'p>(
&self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
+ pcx: &PatCtxt<'_, 'p, 'tcx>,
used_ctors: &[Constructor<'tcx>],
) -> bool {
if used_ctors.is_empty() {
}
impl<'tcx> SplitWildcard<'tcx> {
- pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
+ pub(super) fn new<'p>(pcx: &PatCtxt<'_, 'p, 'tcx>) -> Self {
debug!("SplitWildcard::new({:?})", pcx.ty);
let cx = pcx.cx;
let make_range = |start, end| {
/// do what you want.
pub(super) fn split<'a>(
&mut self,
- pcx: PatCtxt<'_, '_, 'tcx>,
+ pcx: &PatCtxt<'_, '_, 'tcx>,
ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
) where
'tcx: 'a,
}
/// Whether there are any value constructors for this type that are not present in the matrix.
- fn any_missing(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+ fn any_missing(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool {
self.iter_missing(pcx).next().is_some()
}
/// Iterate over the constructors for this type that are not present in the matrix.
pub(super) fn iter_missing<'a, 'p>(
&'a self,
- pcx: PatCtxt<'a, 'p, 'tcx>,
+ pcx: &'a PatCtxt<'a, 'p, 'tcx>,
) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors))
}
/// Return the set of constructors resulting from splitting the wildcard. As explained at the
/// top of the file, if any constructors are missing we can ignore the present ones.
- fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
+ fn into_ctors(self, pcx: &PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
if self.any_missing(pcx) {
// Some constructors are missing, thus we can specialize with the special `Missing`
// constructor, which stands for those constructors that are not seen in the matrix,
/// 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 {
+ #[instrument(level = "trace")]
+ pub(super) fn wildcards(pcx: &PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
let ret = match constructor {
- Single | Variant(_) => match ty.kind() {
- ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()),
- ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
+ Single | Variant(_) => match pcx.ty.kind() {
+ ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
+ ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
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.
- Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
+ Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)))
} else {
let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
- let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
+ let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
.map(|(_, ty)| ty);
- Fields::wildcards_from_tys(cx, tys)
+ Fields::wildcards_from_tys(pcx.cx, tys)
}
}
- _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
+ _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
},
- Slice(slice) => match *ty.kind() {
+ Slice(slice) => match *pcx.ty.kind() {
ty::Slice(ty) | ty::Array(ty, _) => {
let arity = slice.arity();
- Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
+ Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
}
- _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
+ _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
},
Str(..)
| FloatRange(..)
bug!("called `Fields::wildcards` on an `Or` ctor")
}
};
- debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
+ debug!(?ret);
ret
}
/// 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);
+ pub(super) fn wild_from_ctor(pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
+ let fields = Fields::wildcards(pcx, &ctor);
DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
}
/// `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>,
+ pcx: &PatCtxt<'_, '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::wildcards(pcx, other_ctor).iter_patterns().collect()
}
(Slice(self_slice), Slice(other_slice))
if self_slice.arity() != other_slice.arity() =>
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));
+ pcx.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()
/// This is roughly the inverse of `Constructor::apply`.
fn pop_head_constructor(
&self,
- cx: &MatchCheckCtxt<'p, 'tcx>,
+ pcx: &PatCtxt<'_, '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: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
+ let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
new_fields.extend_from_slice(&self.pats[1..]);
PatStack::from_vec(new_fields)
}
/// This computes `S(constructor, self)`. See top of the file for explanations.
fn specialize_constructor(
&self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
+ pcx: &PatCtxt<'_, 'p, 'tcx>,
ctor: &Constructor<'tcx>,
) -> Matrix<'p, 'tcx> {
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);
+ let new_row = row.pop_head_constructor(pcx, ctor);
matrix.push(new_row);
}
}
/// with the results of specializing with the other constructors.
fn apply_constructor(
self,
- pcx: PatCtxt<'_, 'p, 'tcx>,
+ pcx: &PatCtxt<'_, 'p, 'tcx>,
matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors
ctor: &Constructor<'tcx>,
) -> Self {
///
/// left_ty: struct X { a: (bool, &'static str), b: usize}
/// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 }
- fn apply_constructor(mut self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'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.arity(pcx);
is_under_guard: bool,
is_top_level: bool,
) -> Usefulness<'p, 'tcx> {
- debug!("matrix,v={:?}{:?}", matrix, v);
+ debug!(?matrix, ?v);
let Matrix { patterns: rows, .. } = matrix;
// The base case. We are pattern-matching on () and the return value is
debug_assert!(rows.iter().all(|r| r.len() == v.len()));
- let ty = v.head().ty();
- let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
- debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
- 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 mut ret = Usefulness::new_not_useful(witness_preference);
if v.head().is_or_pat() {
}
}
} else {
+ let ty = v.head().ty();
+ let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
+ debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
+ let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
+
let v_ctor = v.head().ctor();
debug!(?v_ctor);
if let Constructor::IntRange(ctor_range) = &v_ctor {
debug!("specialize({:?})", ctor);
// We cache the result of `Fields::wildcards` because it is used a lot.
let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
- let v = v.pop_head_constructor(cx, &ctor);
+ let v = v.pop_head_constructor(pcx, &ctor);
let usefulness = ensure_sufficient_stack(|| {
is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
});
}
}
-struct TransferWrapper<'a>(&'a mut ChunkedBitSet<Local>);
-
-impl<'a> GenKill<Local> for TransferWrapper<'a> {
- fn gen(&mut self, l: Local) {
- self.0.insert(l);
- }
-
- fn kill(&mut self, l: Local) {
- self.0.remove(l);
- }
-}
-
impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
fn apply_statement_effect(
&self,
return;
}
}
- TransferFunction(&mut TransferWrapper(trans)).visit_statement(statement, location);
+ TransferFunction(trans).visit_statement(statement, location);
}
fn apply_terminator_effect(
terminator: &mir::Terminator<'tcx>,
location: Location,
) {
- TransferFunction(&mut TransferWrapper(trans)).visit_terminator(terminator, location);
+ TransferFunction(trans).visit_terminator(terminator, location);
}
fn apply_call_return_effect(
impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let mut delete = DeleteNonCodegenStatements { tcx };
- delete.visit_body(body);
+ delete.visit_body_preserves_cfg(body);
body.user_type_annotations.raw.clear();
for decl in &mut body.local_decls {
};
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{
- self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable,
-};
+use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable};
use rustc_span::{def_id::DefId, Span};
use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
use rustc_target::spec::abi::Abi as CallAbi;
);
let ret_layout = ecx
- .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
+ .layout_of(body.bound_return_ty().subst(tcx, substs))
.ok()
// Don't bother allocating memory for large values.
// I don't know how return types can seem to be unsized but this happens in the
}
fn visit_body(&mut self, body: &mut Body<'tcx>) {
- for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
+ for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
self.visit_basic_block_data(bb, data);
}
}
use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::{
- self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt,
- TypeVisitable,
+ self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitable,
};
use rustc_session::lint;
use rustc_span::Span;
);
let ret_layout = ecx
- .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
+ .layout_of(body.bound_return_ty().subst(tcx, substs))
.ok()
// Don't bother allocating memory for large values.
// I don't know how return types can seem to be unsized but this happens in the
let patch = MirPatch::new(body);
let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() };
- for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
+ for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
checker.visit_basic_block_data(bb, data);
}
build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did);
let ptr_local = self.patch.new_temp(ptr_ty, source_info.span);
- self.local_decls.push(LocalDecl::new(ptr_ty, source_info.span));
self.patch.add_statement(location, StatementKind::StorageLive(ptr_local));
ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch };
for (block, BasicBlockData { statements, terminator, .. }) in
- body.basic_blocks.as_mut().iter_enumerated_mut()
+ body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut()
{
let mut index = 0;
for statement in statements {
index += 1;
}
- if let Some(terminator) = terminator
- && !matches!(terminator.kind, TerminatorKind::Yield{..})
- {
- let location = Location { block, statement_index: index };
- visitor.visit_terminator(terminator, location);
- }
-
let location = Location { block, statement_index: index };
match terminator {
// yielding into a box is handled when lowering generators
use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
-use rustc_span::{Span, Symbol};
#[macro_use]
mod pass_manager;
set: &'a mut FxIndexSet<LocalDefId>,
}
impl<'tcx> Visitor<'tcx> for GatherCtors<'_, 'tcx> {
- fn visit_variant_data(
- &mut self,
- v: &'tcx hir::VariantData<'tcx>,
- _: Symbol,
- _: &'tcx hir::Generics<'tcx>,
- _: hir::HirId,
- _: Span,
- ) {
+ fn visit_variant_data(&mut self, v: &'tcx hir::VariantData<'tcx>) {
if let hir::VariantData::Tuple(_, hir_id) = *v {
self.set.insert(self.tcx.hir().local_def_id(hir_id));
}
def_id, returned_local
);
- RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body);
+ RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body_preserves_cfg(body);
// Clean up the `NOP`s we inserted for statements made useless by our renaming.
- for block_data in body.basic_blocks_mut() {
+ for block_data in body.basic_blocks.as_mut_preserves_cfg() {
block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop);
}
fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
debug!("body: {:#?}", body);
- // make sure there's a single resume block
+ // make sure there's a resume block
let resume_block = {
- let patch = MirPatch::new(body);
+ let mut patch = MirPatch::new(body);
let resume_block = patch.resume_block();
patch.apply(body);
resume_block
}
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
- RevealAllVisitor { tcx, param_env }.visit_body(body);
+ RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body);
}
}
if map.iter().any(Option::is_none) {
// Update references to all vars and tmps now
let mut updater = LocalUpdater { map, tcx };
- updater.visit_body(body);
+ updater.visit_body_preserves_cfg(body);
body.local_decls.shrink_to_fit();
}
while modified {
modified = false;
- for data in body.basic_blocks_mut() {
+ for data in body.basic_blocks.as_mut_preserves_cfg() {
// Remove unnecessary StorageLive and StorageDead annotations.
data.statements.retain(|statement| {
let keep = match &statement.kind {
use unescape_error_reporting::{emit_unescape_error, escaped_char};
+// This type is used a lot. Make sure it doesn't unintentionally get bigger.
+//
+// This assertion is in this crate, rather than in `rustc_lexer`, because that
+// crate cannot depend on `rustc_data_structures`.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12);
+
#[derive(Clone, Debug)]
pub struct UnmatchedBrace {
pub expected_delim: Delimiter,
start_pos: BytePos,
override_span: Option<Span>,
) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
- StringReader { sess, start_pos, pos: start_pos, end_src_index: src.len(), src, override_span }
- .into_token_trees()
+ StringReader { sess, start_pos, pos: start_pos, src, override_span }.into_token_trees()
}
struct StringReader<'a> {
start_pos: BytePos,
/// The absolute offset within the source_map of the current character.
pos: BytePos,
- /// Stop reading src at this index.
- end_src_index: usize,
/// Source text to tokenize.
src: &'a str,
override_span: Option<Span>,
let mut spacing = Spacing::Joint;
// Skip `#!` at the start of the file
- let start_src_index = self.src_index(self.pos);
- let text: &str = &self.src[start_src_index..self.end_src_index];
- let is_beginning_of_file = self.pos == self.start_pos;
- if is_beginning_of_file {
- if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
- self.pos = self.pos + BytePos::from_usize(shebang_len);
- spacing = Spacing::Alone;
- }
+ if self.pos == self.start_pos
+ && let Some(shebang_len) = rustc_lexer::strip_shebang(self.src)
+ {
+ self.pos = self.pos + BytePos::from_usize(shebang_len);
+ spacing = Spacing::Alone;
}
// Skip trivial (whitespace & comments) tokens
loop {
let start_src_index = self.src_index(self.pos);
- let text: &str = &self.src[start_src_index..self.end_src_index];
+ let text: &str = &self.src[start_src_index..];
if text.is_empty() {
let span = self.mk_sp(self.pos, self.pos);
let token = rustc_lexer::first_token(text);
let start = self.pos;
- self.pos = self.pos + BytePos::from_usize(token.len);
+ self.pos = self.pos + BytePos(token.len);
debug!("next_token: {:?}({:?})", token.kind, self.str_from(start));
token::Ident(sym, false)
}
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
- let suffix_start = start + BytePos(suffix_start as u32);
+ let suffix_start = start + BytePos(suffix_start);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
let suffix = if suffix_start < self.pos {
let string = self.str_from(suffix_start);
}
(token::ByteStr, Mode::ByteStr, 2, 1) // b" "
}
- rustc_lexer::LiteralKind::RawStr { n_hashes, err } => {
- self.report_raw_str_error(start, err);
- let n = u32::from(n_hashes);
- (token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "##
+ rustc_lexer::LiteralKind::RawStr { n_hashes } => {
+ if let Some(n_hashes) = n_hashes {
+ let n = u32::from(n_hashes);
+ (token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "##
+ } else {
+ self.report_raw_str_error(start, 1);
+ }
}
- rustc_lexer::LiteralKind::RawByteStr { n_hashes, err } => {
- self.report_raw_str_error(start, err);
- let n = u32::from(n_hashes);
- (token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "##
+ rustc_lexer::LiteralKind::RawByteStr { n_hashes } => {
+ if let Some(n_hashes) = n_hashes {
+ let n = u32::from(n_hashes);
+ (token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "##
+ } else {
+ self.report_raw_str_error(start, 2);
+ }
}
rustc_lexer::LiteralKind::Int { base, empty_int } => {
return if empty_int {
&self.src[self.src_index(start)..self.src_index(end)]
}
- fn report_raw_str_error(&self, start: BytePos, opt_err: Option<RawStrError>) {
- match opt_err {
- Some(RawStrError::InvalidStarter { bad_char }) => {
+ fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
+ match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
+ Err(RawStrError::InvalidStarter { bad_char }) => {
self.report_non_started_raw_string(start, bad_char)
}
- Some(RawStrError::NoTerminator { expected, found, possible_terminator_offset }) => self
+ Err(RawStrError::NoTerminator { expected, found, possible_terminator_offset }) => self
.report_unterminated_raw_string(start, expected, possible_terminator_offset, found),
- Some(RawStrError::TooManyDelimiters { found }) => {
+ Err(RawStrError::TooManyDelimiters { found }) => {
self.report_too_many_hashes(start, found)
}
- None => (),
+ Ok(()) => panic!("no error found for supposedly invalid raw string literal"),
}
}
fn report_unterminated_raw_string(
&self,
start: BytePos,
- n_hashes: usize,
- possible_offset: Option<usize>,
- found_terminators: usize,
+ n_hashes: u32,
+ possible_offset: Option<u32>,
+ found_terminators: u32,
) -> ! {
let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code(
self.mk_sp(start, start),
if n_hashes > 0 {
err.note(&format!(
"this raw string should be terminated with `\"{}`",
- "#".repeat(n_hashes)
+ "#".repeat(n_hashes as usize)
));
}
err.span_suggestion(
span,
"consider terminating the string here",
- "#".repeat(n_hashes),
+ "#".repeat(n_hashes as usize),
Applicability::MaybeIncorrect,
);
}
}
}
- fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! {
+ fn report_too_many_hashes(&self, start: BytePos, found: u32) -> ! {
self.fatal_span_(
start,
self.pos,
}
impl TokenStreamBuilder {
+ #[inline(always)]
fn push(&mut self, tree: TokenTree) {
if let Some(TokenTree::Token(prev_token, Spacing::Joint)) = self.buf.last()
&& let TokenTree::Token(token, joint) = &tree
{
self.buf.pop();
self.buf.push(TokenTree::Token(glued, *joint));
- return;
+ } else {
+ self.buf.push(tree)
}
- self.buf.push(tree);
}
fn into_token_stream(self) -> TokenStream {
use rustc_errors::{
fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
};
-use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed};
+use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, Ident};
}
impl MultiSugg {
- fn emit<G: EmissionGuarantee>(self, err: &mut DiagnosticBuilder<'_, G>) {
+ fn emit(self, err: &mut Diagnostic) {
err.multipart_suggestion(&self.msg, self.patches, self.applicability);
}
/// Overrides individual messages and applicabilities.
- fn emit_many<G: EmissionGuarantee>(
- err: &mut DiagnosticBuilder<'_, G>,
+ fn emit_many(
+ err: &mut Diagnostic,
msg: &str,
applicability: Applicability,
suggestions: impl Iterator<Item = Self>,
|| (sm.is_multiline(
self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo())
) && t == &token::Pound)
- }) {
+ }) && !expected.contains(&TokenType::Token(token::Comma))
+ {
// Missing semicolon typo. This is triggered if the next token could either start a
// new statement or is a block close. For example:
//
ExprKind::Index(_, _) => "indexing",
ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
- ExprKind::MethodCall(_, _, _) => "a method call",
+ ExprKind::MethodCall(_, _, _, _) => "a method call",
ExprKind::Call(_, _) => "a function call",
ExprKind::Await(_) => "`.await`",
ExprKind::Err => return Ok(with_postfix),
);
let mut err = self.struct_span_err(span, &msg);
- let suggest_parens = |err: &mut DiagnosticBuilder<'_, _>| {
+ let suggest_parens = |err: &mut Diagnostic| {
let suggestions = vec![
(span.shrink_to_lo(), "(".to_string()),
(span.shrink_to_hi(), ")".to_string()),
/// Parse an indexing expression `expr[...]`.
fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
+ let prev_span = self.prev_token.span;
+ let open_delim_span = self.token.span;
self.bump(); // `[`
let index = self.parse_expr()?;
+ self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;
self.expect(&token::CloseDelim(Delimiter::Bracket))?;
Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new()))
}
if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
// Method call `expr.f()`
- let mut args = self.parse_paren_expr_seq()?;
- args.insert(0, self_arg);
-
+ let args = self.parse_paren_expr_seq()?;
let fn_span = fn_span_lo.to(self.prev_token.span);
let span = lo.to(self.prev_token.span);
- Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span), AttrVec::new()))
+ Ok(self.mk_expr(
+ span,
+ ExprKind::MethodCall(segment, self_arg, args, fn_span),
+ AttrVec::new(),
+ ))
} else {
// Field access `expr.f`
if let Some(args) = segment.args {
} else if self.is_do_yeet() {
self.parse_yeet_expr(attrs)
} else if self.check_keyword(kw::Let) {
- self.manage_let_chains_context();
- self.bump();
self.parse_let_expr(attrs)
} else if self.eat_keyword(kw::Underscore) {
Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs))
}
}
+ fn suggest_missing_semicolon_before_array(
+ &self,
+ prev_span: Span,
+ open_delim_span: Span,
+ ) -> PResult<'a, ()> {
+ if self.token.kind == token::Comma {
+ let mut snapshot = self.create_snapshot_for_diagnostic();
+ snapshot.bump();
+ match snapshot.parse_seq_to_before_end(
+ &token::CloseDelim(Delimiter::Bracket),
+ SeqSep::trailing_allowed(token::Comma),
+ |p| p.parse_expr(),
+ ) {
+ Ok(_)
+ // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
+ // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
+ // This is because the `token.kind` of the close delim is treated as the same as
+ // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
+ // Therefore, `token.kind` should not be compared here.
+ if snapshot
+ .span_to_snippet(snapshot.token.span)
+ .map_or(false, |snippet| snippet == "]") =>
+ {
+ let mut err = self.struct_span_err(open_delim_span, "expected `;`, found `[`");
+ err.span_suggestion_verbose(
+ prev_span.shrink_to_hi(),
+ "consider adding `;` here",
+ ';',
+ Applicability::MaybeIncorrect,
+ );
+ return Err(err);
+ }
+ Ok(_) => (),
+ Err(err) => err.cancel(),
+ }
+ }
+ Ok(())
+ }
+
/// Parses a block or unsafe block.
pub(super) fn parse_block_expr(
&mut self,
/// Parses the condition of a `if` or `while` expression.
fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
- self.with_let_management(true, |local_self| {
- local_self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)
- })
+ self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)
}
- // Checks if `let` is in an invalid position like `let x = let y = 1;` or
- // if the current `let` is in a let_chains context but nested in another
- // expression like `if let Some(_) = _opt && [1, 2, 3][let _ = ()] = 1`.
- //
- // This method expects that the current token is `let`.
- fn manage_let_chains_context(&mut self) {
- debug_assert!(matches!(self.token.kind, TokenKind::Ident(kw::Let, _)));
- let is_in_a_let_chains_context_but_nested_in_other_expr = self.let_expr_allowed
- && !matches!(
- self.prev_token.kind,
- TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
- );
- if !self.let_expr_allowed || is_in_a_let_chains_context_but_nested_in_other_expr {
+ /// Parses a `let $pat = $expr` pseudo-expression.
+ fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ // This is a *approximate* heuristic that detects if `let` chains are
+ // being parsed in the right position. It's approximate because it
+ // doesn't deny all invalid `let` expressions, just completely wrong usages.
+ let not_in_chain = !matches!(
+ self.prev_token.kind,
+ TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
+ );
+ if !self.restrictions.contains(Restrictions::ALLOW_LET) || not_in_chain {
self.struct_span_err(self.token.span, "expected expression, found `let` statement")
.emit();
}
- }
- /// Parses a `let $pat = $expr` pseudo-expression.
- /// The `let` token has already been eaten.
- fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ self.bump(); // Eat `let` token
let lo = self.prev_token.span;
let pat = self.parse_pat_allow_top_alt(
None,
// `&&` tokens.
fn check_let_expr(expr: &Expr) -> bool {
match expr.kind {
- ExprKind::Binary(_, ref lhs, ref rhs) => check_let_expr(lhs) || check_let_expr(rhs),
+ ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, ref lhs, ref rhs) => {
+ check_let_expr(lhs) || check_let_expr(rhs)
+ }
ExprKind::Let(..) => true,
_ => false,
}
)?;
let guard = if this.eat_keyword(kw::If) {
let if_span = this.prev_token.span;
- let cond = this.with_let_management(true, |local_this| local_this.parse_expr())?;
- let has_let_expr = check_let_expr(&cond);
- if has_let_expr {
+ let cond = this.parse_expr_res(Restrictions::ALLOW_LET, None)?;
+ if check_let_expr(&cond) {
let span = if_span.to(cond.span);
this.sess.gated_spans.gate(sym::if_let_guard, span);
}
Ok((res, trailing))
})
}
-
- // Calls `f` with the internal `let_expr_allowed` set to `let_expr_allowed` and then
- // sets the internal `let_expr_allowed` back to its original value.
- fn with_let_management<T>(
- &mut self,
- let_expr_allowed: bool,
- f: impl FnOnce(&mut Self) -> T,
- ) -> T {
- let last_let_expr_allowed = mem::replace(&mut self.let_expr_allowed, let_expr_allowed);
- let rslt = f(self);
- self.let_expr_allowed = last_let_expr_allowed;
- rslt
- }
}
// MACRO_RULES ITEM
self.parse_item_macro_rules(vis, has_bang)?
} else if self.isnt_macro_invocation()
- && (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using))
+ && (self.token.is_ident_named(sym::import)
+ || self.token.is_ident_named(sym::using)
+ || self.token.is_ident_named(sym::include)
+ || self.token.is_ident_named(sym::require))
{
return self.recover_import_as_use();
} else if self.isnt_macro_invocation() && vis.kind.is_pub() {
// Parse the type of a `const` or `static mut?` item.
// That is, the `":" $ty` fragment.
- let ty = if self.eat(&token::Colon) {
- self.parse_ty()?
- } else {
- self.recover_missing_const_type(id, m)
+ let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi))
+ {
+ // If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type.
+ (true, false) => self.parse_ty()?,
+ (colon, _) => self.recover_missing_const_type(colon, m),
};
let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
Ok((id, ty, expr))
}
- /// We were supposed to parse `:` but the `:` was missing.
+ /// We were supposed to parse `":" $ty` but the `:` or the type was missing.
/// This means that the type is missing.
- fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> {
+ fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutability>) -> P<Ty> {
// Construct the error and stash it away with the hope
// that typeck will later enrich the error with a type.
let kind = match m {
Some(Mutability::Not) => "static",
None => "const",
};
- let mut err = self.struct_span_err(id.span, &format!("missing type for `{kind}` item"));
+
+ let colon = match colon_present {
+ true => "",
+ false => ":",
+ };
+
+ let span = self.prev_token.span.shrink_to_hi();
+ let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item"));
err.span_suggestion(
- id.span,
+ span,
"provide a type for the item",
- format!("{id}: <type>"),
+ format!("{colon} <type>"),
Applicability::HasPlaceholders,
);
- err.stash(id.span, StashKey::ItemNoType);
+ err.stash(span, StashKey::ItemNoType);
// The user intended that the type be inferred,
// so treat this as if the user wrote e.g. `const A: _ = expr;`.
- P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID, tokens: None })
+ P(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None })
}
/// Parses an enum declaration.
fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
+ if self.token.is_keyword(kw::Struct) {
+ let mut err = self.struct_span_err(
+ self.prev_token.span.to(self.token.span),
+ "`enum` and `struct` are mutually exclusive",
+ );
+ err.span_suggestion(
+ self.prev_token.span.to(self.token.span),
+ "replace `enum struct` with",
+ "enum",
+ Applicability::MachineApplicable,
+ );
+ if self.look_ahead(1, |t| t.is_ident()) {
+ self.bump();
+ err.emit();
+ } else {
+ return Err(err);
+ }
+ }
+
let id = self.parse_ident()?;
let mut generics = self.parse_generics()?;
generics.where_clause = self.parse_where_clause()?;
const STMT_EXPR = 1 << 0;
const NO_STRUCT_LITERAL = 1 << 1;
const CONST_EXPR = 1 << 2;
+ const ALLOW_LET = 1 << 3;
}
}
/// This allows us to recover when the user forget to add braces around
/// multiple statements in the closure body.
pub current_closure: Option<ClosureSpans>,
- /// Used to track where `let`s are allowed. For example, `if true && let 1 = 1` is valid
- /// but `[1, 2, 3][let _ = ()]` is not.
- let_expr_allowed: bool,
}
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
// it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 336);
+rustc_data_structures::static_assert_size!(Parser<'_>, 328);
/// Stores span information about a closure.
#[derive(Clone)]
inner_attr_ranges: Default::default(),
},
current_closure: None,
- let_expr_allowed: false,
};
// Make parser point to the first token.
self.bump(); // `in`
let path = self.parse_path(PathStyle::Mod)?; // `path`
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
- let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
+ let vis = VisibilityKind::Restricted {
+ path: P(path),
+ id: ast::DUMMY_NODE_ID,
+ shorthand: false,
+ };
return Ok(Visibility {
span: lo.to(self.prev_token.span),
kind: vis,
self.bump(); // `(`
let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self`
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
- let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
+ let vis = VisibilityKind::Restricted {
+ path: P(path),
+ id: ast::DUMMY_NODE_ID,
+ shorthand: true,
+ };
return Ok(Visibility {
span: lo.to(self.prev_token.span),
kind: vis,
pub struct Argument<'a> {
/// Where to find this argument
pub position: Position<'a>,
+ /// The span of the position indicator. Includes any whitespace in implicit
+ /// positions (`{ }`).
+ pub position_span: InnerSpan,
/// How to format the argument
pub format: FormatSpec<'a>,
}
/// The argument is implied to be located at an index
ArgumentImplicitlyIs(usize),
/// The argument is located at a specific index given in the format,
- ArgumentIs(usize, Option<InnerSpan>),
+ ArgumentIs(usize),
/// The argument has a name.
- ArgumentNamed(&'a str, InnerSpan),
+ ArgumentNamed(&'a str),
}
impl Position<'_> {
pub label: string::String,
pub span: InnerSpan,
pub secondary_label: Option<(string::String, InnerSpan)>,
+ pub should_be_replaced_with_positional_argument: bool,
}
/// The parser structure for interpreting the input format string. This is
'{' => {
let curr_last_brace = self.last_opening_brace;
let byte_pos = self.to_span_index(pos);
- self.last_opening_brace = Some(byte_pos.to(InnerOffset(byte_pos.0 + 1)));
+ let lbrace_end = InnerOffset(byte_pos.0 + 1);
+ self.last_opening_brace = Some(byte_pos.to(lbrace_end));
self.cur.next();
if self.consume('{') {
self.last_opening_brace = curr_last_brace;
Some(String(self.string(pos + 1)))
} else {
- let arg = self.argument();
+ let arg = self.argument(lbrace_end);
if let Some(rbrace_byte_idx) = self.must_consume('}') {
let lbrace_inner_offset = self.to_span_index(pos);
let rbrace_inner_offset = self.to_span_index(rbrace_byte_idx);
lbrace_inner_offset.to(InnerOffset(rbrace_inner_offset.0 + 1)),
);
}
+ } else {
+ self.suggest_positional_arg_instead_of_captured_arg(arg);
}
Some(NextArgument(arg))
}
label: label.into(),
span,
secondary_label: None,
+ should_be_replaced_with_positional_argument: false,
});
}
label: label.into(),
span,
secondary_label: None,
+ should_be_replaced_with_positional_argument: false,
});
}
label,
span: pos.to(pos),
secondary_label,
+ should_be_replaced_with_positional_argument: false,
});
None
}
label,
span: pos.to(pos),
secondary_label,
+ should_be_replaced_with_positional_argument: false,
});
} else {
self.err(description, format!("expected `{:?}`", c), pos.to(pos));
}
/// Parses an `Argument` structure, or what's contained within braces inside the format string.
- fn argument(&mut self) -> Argument<'a> {
+ fn argument(&mut self, start: InnerOffset) -> Argument<'a> {
let pos = self.position();
+
+ let end = self
+ .cur
+ .clone()
+ .find(|(_, ch)| !ch.is_whitespace())
+ .map_or(start, |(end, _)| self.to_span_index(end));
+ let position_span = start.to(end);
+
let format = match self.mode {
ParseMode::Format => self.format(),
ParseMode::InlineAsm => self.inline_asm(),
}
};
- Argument { position: pos, format }
+ Argument { position: pos, position_span, format }
}
/// Parses a positional argument for a format. This could either be an
/// Returns `Some(parsed_position)` if the position is not implicitly
/// consuming a macro argument, `None` if it's the case.
fn position(&mut self) -> Option<Position<'a>> {
- let start_position = self.cur.peek().map(|item| item.0);
if let Some(i) = self.integer() {
- let inner_span = start_position.and_then(|start| {
- self.cur
- .peek()
- .cloned()
- .and_then(|item| Some(self.to_span_index(start).to(self.to_span_index(item.0))))
- });
- Some(ArgumentIs(i, inner_span))
+ Some(ArgumentIs(i))
} else {
match self.cur.peek() {
- Some(&(start, c)) if rustc_lexer::is_id_start(c) => {
- let word = self.word();
- let end = start + word.len();
- let span = self.to_span_index(start).to(self.to_span_index(end));
- Some(ArgumentNamed(word, span))
- }
+ Some(&(_, c)) if rustc_lexer::is_id_start(c) => Some(ArgumentNamed(self.word())),
// This is an `ArgumentNext`.
// Record the fact and do the resolution after parsing the
}
if found { Some(cur) } else { None }
}
+
+ fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) {
+ if let Some(end) = self.consume_pos('.') {
+ let byte_pos = self.to_span_index(end);
+ let start = InnerOffset(byte_pos.0 + 1);
+ let field = self.argument(start);
+ // We can only parse `foo.bar` field access, any deeper nesting,
+ // or another type of expression, like method calls, are not supported
+ if !self.consume('}') {
+ return;
+ }
+ if let ArgumentNamed(_) = arg.position {
+ if let ArgumentNamed(_) = field.position {
+ self.errors.insert(
+ 0,
+ ParseError {
+ description: "field access isn't supported".to_string(),
+ note: None,
+ label: "not supported".to_string(),
+ span: InnerSpan::new(arg.position_span.start, field.position_span.end),
+ secondary_label: None,
+ should_be_replaced_with_positional_argument: true,
+ },
+ );
+ }
+ }
+ }
+ }
}
/// Finds the indices of all characters that have been processed and differ between the actual
#[test]
fn format_nothing() {
- same("{}", &[NextArgument(Argument { position: ArgumentImplicitlyIs(0), format: fmtdflt() })]);
+ same(
+ "{}",
+ &[NextArgument(Argument {
+ position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 2 },
+ format: fmtdflt(),
+ })],
+ );
}
#[test]
fn format_position() {
same(
"{3}",
&[NextArgument(Argument {
- position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+ position: ArgumentIs(3),
+ position_span: InnerSpan { start: 2, end: 3 },
format: fmtdflt(),
})],
);
same(
"{3:}",
&[NextArgument(Argument {
- position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+ position: ArgumentIs(3),
+ position_span: InnerSpan { start: 2, end: 3 },
format: fmtdflt(),
})],
);
}
#[test]
+fn format_named() {
+ same(
+ "{name}",
+ &[NextArgument(Argument {
+ position: ArgumentNamed("name"),
+ position_span: InnerSpan { start: 2, end: 6 },
+ format: fmtdflt(),
+ })],
+ )
+}
+#[test]
fn format_type() {
same(
"{3:x}",
&[NextArgument(Argument {
- position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+ position: ArgumentIs(3),
+ position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
same(
"{3:>}",
&[NextArgument(Argument {
- position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+ position: ArgumentIs(3),
+ position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: None,
align: AlignRight,
same(
"{3:0<}",
&[NextArgument(Argument {
- position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+ position: ArgumentIs(3),
+ position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: Some('0'),
align: AlignLeft,
same(
"{3:*<abcd}",
&[NextArgument(Argument {
- position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+ position: ArgumentIs(3),
+ position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: Some('*'),
align: AlignLeft,
"{:10x}",
&[NextArgument(Argument {
position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
"{:10$.10x}",
&[NextArgument(Argument {
position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
same(
"{1:0$.10x}",
&[NextArgument(Argument {
- position: ArgumentIs(1, Some(InnerSpan { start: 2, end: 3 })),
+ position: ArgumentIs(1),
+ position_span: InnerSpan { start: 2, end: 3 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
"{:.*x}",
&[NextArgument(Argument {
position: ArgumentImplicitlyIs(1),
+ position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
"{:.10$x}",
&[NextArgument(Argument {
position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
"{:a$.b$?}",
&[NextArgument(Argument {
position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
"{:-}",
&[NextArgument(Argument {
position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
"{:+#}",
&[NextArgument(Argument {
position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 2 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
&[
String("abcd "),
NextArgument(Argument {
- position: ArgumentIs(3, Some(InnerSpan { start: 7, end: 8 })),
+ position: ArgumentIs(3),
+ position_span: InnerSpan { start: 7, end: 8 },
format: FormatSpec {
fill: None,
align: AlignUnknown,
],
);
}
+#[test]
+fn format_whitespace() {
+ same(
+ "{ }",
+ &[NextArgument(Argument {
+ position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 3 },
+ format: fmtdflt(),
+ })],
+ );
+ same(
+ "{ }",
+ &[NextArgument(Argument {
+ position: ArgumentImplicitlyIs(0),
+ position_span: InnerSpan { start: 2, end: 4 },
+ format: fmtdflt(),
+ })],
+ );
+}
#[derive(Clone, Copy)]
enum ItemLike<'tcx> {
Item(&'tcx Item<'tcx>),
- ForeignItem(&'tcx ForeignItem<'tcx>),
+ ForeignItem,
}
struct CheckAttrVisitor<'tcx> {
| sym::stable
| sym::rustc_allowed_through_unstable_modules
| sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
+ sym::link_ordinal => self.check_link_ordinal(&attr, span, target),
_ => true,
};
is_valid &= attr_is_valid;
}
// FIXME(@lcnr): this doesn't belong here.
- if matches!(target, Target::Closure | Target::Fn | Target::Method(_) | Target::ForeignFn) {
+ if matches!(
+ target,
+ Target::Closure
+ | Target::Fn
+ | Target::Method(_)
+ | Target::ForeignFn
+ | Target::ForeignStatic
+ ) {
self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id));
}
let span = meta.span();
if let Some(location) = match target {
- Target::Impl => Some("implementation block"),
- Target::ForeignMod => Some("extern block"),
Target::AssocTy => {
let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
let containing_item = self.tcx.hir().expect_item(parent_hir_id);
}
// we check the validity of params elsewhere
Target::Param => return false,
- _ => None,
+ Target::Expression
+ | Target::Statement
+ | Target::Arm
+ | Target::ForeignMod
+ | Target::Closure
+ | Target::Impl => Some(target.name()),
+ Target::ExternCrate
+ | Target::Use
+ | Target::Static
+ | Target::Const
+ | Target::Fn
+ | Target::Mod
+ | Target::GlobalAsm
+ | Target::TyAlias
+ | Target::OpaqueTy
+ | Target::Enum
+ | Target::Variant
+ | Target::Struct
+ | Target::Field
+ | Target::Union
+ | Target::Trait
+ | Target::TraitAlias
+ | Target::Method(..)
+ | Target::ForeignFn
+ | Target::ForeignStatic
+ | Target::ForeignTy
+ | Target::GenericParam(..)
+ | Target::MacroDef => None,
} {
tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location });
return false;
}
}
+ fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
+ match target {
+ Target::ForeignFn | Target::ForeignStatic => true,
+ _ => {
+ self.tcx.sess.emit_err(errors::LinkOrdinal { attr_span: attr.span });
+ false
+ }
+ }
+ }
+
fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
match target {
Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
let target = Target::from_foreign_item(f_item);
- self.check_attributes(
- f_item.hir_id(),
- f_item.span,
- target,
- Some(ItemLike::ForeignItem(f_item)),
- );
+ self.check_attributes(f_item.hir_id(), f_item.span, target, Some(ItemLike::ForeignItem));
intravisit::walk_foreign_item(self, f_item)
}
intravisit::walk_expr(self, expr)
}
- fn visit_variant(
- &mut self,
- variant: &'tcx hir::Variant<'tcx>,
- generics: &'tcx hir::Generics<'tcx>,
- item_id: HirId,
- ) {
+ fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) {
self.check_attributes(variant.id, variant.span, Target::Variant, None);
- intravisit::walk_variant(self, variant, generics, item_id)
+ intravisit::walk_variant(self, variant)
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
// If the function belongs to a trait, then it must enable the const_trait_impl
// feature to use that trait function (with a const default body).
- if tcx.trait_of_item(def_id).is_some() {
+ if tcx.trait_of_item(def_id.to_def_id()).is_some() {
return true;
}
use itertools::Itertools;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, MultiSpan};
+use rustc_errors::{pluralize, Applicability, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
live_symbols: FxHashSet<LocalDefId>,
repr_has_repr_c: bool,
+ repr_has_repr_simd: bool,
in_pat: bool,
ignore_variant_stack: Vec<DefId>,
// maps from tuple struct constructors to tuple struct items
}
}
+ fn handle_tuple_field_pattern_match(
+ &mut self,
+ lhs: &hir::Pat<'_>,
+ res: Res,
+ pats: &[hir::Pat<'_>],
+ dotdot: Option<usize>,
+ ) {
+ let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
+ ty::Adt(adt, _) => adt.variant_of_res(res),
+ _ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
+ };
+ let first_n = pats.iter().enumerate().take(dotdot.unwrap_or(pats.len()));
+ let missing = variant.fields.len() - pats.len();
+ let last_n = pats
+ .iter()
+ .enumerate()
+ .skip(dotdot.unwrap_or(pats.len()))
+ .map(|(idx, pat)| (idx + missing, pat));
+ for (idx, pat) in first_n.chain(last_n) {
+ if let PatKind::Wild = pat.kind {
+ continue;
+ }
+ self.insert_def_id(variant.fields[idx].did);
+ }
+ }
+
fn mark_live_symbols(&mut self) {
let mut scanned = FxHashSet::default();
while let Some(id) = self.worklist.pop() {
}
let had_repr_c = self.repr_has_repr_c;
+ let had_repr_simd = self.repr_has_repr_simd;
self.repr_has_repr_c = false;
+ self.repr_has_repr_simd = false;
match node {
Node::Item(item) => match item.kind {
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
let def = self.tcx.adt_def(item.def_id);
self.repr_has_repr_c = def.repr().c();
+ self.repr_has_repr_simd = def.repr().simd();
intravisit::walk_item(self, &item)
}
}
_ => {}
}
+ self.repr_has_repr_simd = had_repr_simd;
self.repr_has_repr_c = had_repr_c;
}
self.maybe_typeck_results = old_maybe_typeck_results;
}
- fn visit_variant_data(
- &mut self,
- def: &'tcx hir::VariantData<'tcx>,
- _: Symbol,
- _: &hir::Generics<'_>,
- _: hir::HirId,
- _: rustc_span::Span,
- ) {
+ fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) {
let tcx = self.tcx;
let has_repr_c = self.repr_has_repr_c;
+ let has_repr_simd = self.repr_has_repr_simd;
let live_fields = def.fields().iter().filter_map(|f| {
let def_id = tcx.hir().local_def_id(f.hir_id);
- if has_repr_c {
+ if has_repr_c || (f.is_positional() && has_repr_simd) {
return Some(def_id);
}
if !tcx.visibility(f.hir_id.owner).is_public() {
let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
self.handle_res(res);
}
+ PatKind::TupleStruct(ref qpath, ref fields, dotdot) => {
+ let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
+ self.handle_tuple_field_pattern_match(pat, res, fields, dotdot);
+ }
_ => (),
}
}
}
-fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+fn has_allow_dead_code_or_lang_attr_helper(
+ tcx: TyCtxt<'_>,
+ id: hir::HirId,
+ lint: &'static lint::Lint,
+) -> bool {
let attrs = tcx.hir().attrs(id);
if tcx.sess.contains_name(attrs, sym::lang) {
return true;
}
}
- tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
+ tcx.lint_level_at_node(lint, id).0 == lint::Allow
+}
+
+fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+ has_allow_dead_code_or_lang_attr_helper(tcx, id, lint::builtin::DEAD_CODE)
}
// These check_* functions seeds items that
maybe_typeck_results: None,
live_symbols: Default::default(),
repr_has_repr_c: false,
+ repr_has_repr_simd: false,
in_pat: false,
ignore_variant_stack: vec![],
struct_constructors,
ignored_derived_traits: &'tcx FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
}
+enum ShouldWarnAboutField {
+ Yes(bool), // positional?
+ No,
+}
+
impl<'tcx> DeadVisitor<'tcx> {
- fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> bool {
+ fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> ShouldWarnAboutField {
if self.live_symbols.contains(&field.did.expect_local()) {
- return false;
+ return ShouldWarnAboutField::No;
+ }
+ let field_type = self.tcx.type_of(field.did);
+ if field_type.is_phantom_data() {
+ return ShouldWarnAboutField::No;
}
let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
- if is_positional {
- return false;
+ if is_positional
+ && self
+ .tcx
+ .layout_of(self.tcx.param_env(field.did).and(field_type))
+ .map_or(true, |layout| layout.is_zst())
+ {
+ return ShouldWarnAboutField::No;
}
- let field_type = self.tcx.type_of(field.did);
- !field_type.is_phantom_data()
+ ShouldWarnAboutField::Yes(is_positional)
}
fn warn_multiple_dead_codes(
dead_codes: &[LocalDefId],
participle: &str,
parent_item: Option<LocalDefId>,
+ is_positional: bool,
) {
if let Some(&first_id) = dead_codes.first() {
let tcx = self.tcx;
.iter()
.map(|&def_id| tcx.item_name(def_id.to_def_id()).to_string())
.collect();
- let spans = dead_codes
+ let spans: Vec<_> = dead_codes
.iter()
.map(|&def_id| match tcx.def_ident_span(def_id) {
Some(s) => s.with_ctxt(tcx.def_span(def_id).ctxt()),
.collect();
tcx.struct_span_lint_hir(
- lint::builtin::DEAD_CODE,
+ if is_positional {
+ lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
+ } else {
+ lint::builtin::DEAD_CODE
+ },
tcx.hir().local_def_id_to_hir_id(first_id),
- MultiSpan::from_spans(spans),
+ MultiSpan::from_spans(spans.clone()),
|lint| {
let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
let span_len = dead_codes.len();
are = pluralize!("is", span_len),
));
+ if is_positional {
+ err.multipart_suggestion(
+ &format!(
+ "consider changing the field{s} to be of unit type to \
+ suppress this warning while preserving the field \
+ numbering, or remove the field{s}",
+ s = pluralize!(span_len)
+ ),
+ spans.iter().map(|sp| (*sp, "()".to_string())).collect(),
+ // "HasPlaceholders" because applying this fix by itself isn't
+ // enough: All constructor calls have to be adjusted as well
+ Applicability::HasPlaceholders,
+ );
+ }
+
if let Some(parent_item) = parent_item {
let parent_descr = tcx.def_kind(parent_item).descr(parent_item.to_def_id());
err.span_label(
def_id: LocalDefId,
participle: &str,
dead_codes: Vec<DeadVariant>,
+ is_positional: bool,
) {
let mut dead_codes = dead_codes
.iter()
&group.map(|v| v.def_id).collect::<Vec<_>>(),
participle,
Some(def_id),
+ is_positional,
);
}
}
fn warn_dead_code(&mut self, id: LocalDefId, participle: &str) {
- self.warn_multiple_dead_codes(&[id], participle, None);
+ self.warn_multiple_dead_codes(&[id], participle, None, false);
}
fn check_definition(&mut self, def_id: LocalDefId) {
continue;
}
+ let mut is_positional = false;
let dead_fields = variant
.fields
.iter()
.filter_map(|field| {
let def_id = field.did.expect_local();
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- if visitor.should_warn_about_field(&field) {
- let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
+ if let ShouldWarnAboutField::Yes(is_pos) =
+ visitor.should_warn_about_field(&field)
+ {
+ let level = tcx
+ .lint_level_at_node(
+ if is_pos {
+ is_positional = true;
+ lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
+ } else {
+ lint::builtin::DEAD_CODE
+ },
+ hir_id,
+ )
+ .0;
Some(DeadVariant { def_id, name: field.name, level })
} else {
None
}
})
.collect();
- visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields)
+ visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional)
}
- visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants);
+ visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants, false);
}
}
pub attr_span: Span,
}
+#[derive(SessionDiagnostic)]
+#[error(passes::link_ordinal)]
+pub struct LinkOrdinal {
+ #[primary_span]
+ pub attr_span: Span,
+}
+
#[derive(SessionDiagnostic)]
#[error(passes::stability_promotable)]
pub struct StabilityPromotable {
None,
}
-struct NodeData {
+struct NodeStats {
count: usize,
size: usize,
}
+impl NodeStats {
+ fn new() -> NodeStats {
+ NodeStats { count: 0, size: 0 }
+ }
+}
+
+struct Node {
+ stats: NodeStats,
+ subnodes: FxHashMap<&'static str, NodeStats>,
+}
+
+impl Node {
+ fn new() -> Node {
+ Node { stats: NodeStats::new(), subnodes: FxHashMap::default() }
+ }
+}
+
+/// This type measures the size of AST and HIR nodes, by implementing the AST
+/// and HIR `Visitor` traits. But we don't measure every visited type because
+/// that could cause double counting.
+///
+/// For example, `ast::Visitor` has `visit_ident`, but `Ident`s are always
+/// stored inline within other AST nodes, so we don't implement `visit_ident`
+/// here. In constrast, we do implement `visit_expr` because `ast::Expr` is
+/// always stored as `P<ast::Expr>`, and every such expression should be
+/// measured separately.
+///
+/// In general, a `visit_foo` method should be implemented here if the
+/// corresponding `Foo` type is always stored on its own, e.g.: `P<Foo>`,
+/// `Box<Foo>`, `Vec<Foo>`, `Box<[Foo]>`.
+///
+/// There are some types in the AST and HIR tree that the visitors do not have
+/// a `visit_*` method for, and so we cannot measure these, which is
+/// unfortunate.
struct StatCollector<'k> {
krate: Option<Map<'k>>,
- data: FxHashMap<&'static str, NodeData>,
+ nodes: FxHashMap<&'static str, Node>,
seen: FxHashSet<Id>,
}
pub fn print_hir_stats(tcx: TyCtxt<'_>) {
let mut collector = StatCollector {
krate: Some(tcx.hir()),
- data: FxHashMap::default(),
+ nodes: FxHashMap::default(),
seen: FxHashSet::default(),
};
tcx.hir().walk_toplevel_module(&mut collector);
}
pub fn print_ast_stats(krate: &ast::Crate, title: &str) {
+ use rustc_ast::visit::Visitor;
+
let mut collector =
- StatCollector { krate: None, data: FxHashMap::default(), seen: FxHashSet::default() };
- ast_visit::walk_crate(&mut collector, krate);
+ StatCollector { krate: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
+ collector.visit_crate(krate);
collector.print(title);
}
impl<'k> StatCollector<'k> {
- fn record<T>(&mut self, label: &'static str, id: Id, node: &T) {
+ // Record a top-level node.
+ fn record<T>(&mut self, label: &'static str, id: Id, val: &T) {
+ self.record_inner(label, None, id, val);
+ }
+
+ // Record a two-level entry, with a top-level enum type and a variant.
+ fn record_variant<T>(&mut self, label1: &'static str, label2: &'static str, id: Id, val: &T) {
+ self.record_inner(label1, Some(label2), id, val);
+ }
+
+ fn record_inner<T>(
+ &mut self,
+ label1: &'static str,
+ label2: Option<&'static str>,
+ id: Id,
+ val: &T,
+ ) {
if id != Id::None && !self.seen.insert(id) {
return;
}
- let entry = self.data.entry(label).or_insert(NodeData { count: 0, size: 0 });
+ let node = self.nodes.entry(label1).or_insert(Node::new());
+ node.stats.count += 1;
+ node.stats.size = std::mem::size_of_val(val);
- entry.count += 1;
- entry.size = std::mem::size_of_val(node);
+ if let Some(label2) = label2 {
+ let subnode = node.subnodes.entry(label2).or_insert(NodeStats::new());
+ subnode.count += 1;
+ subnode.size = std::mem::size_of_val(val);
+ }
}
fn print(&self, title: &str) {
- let mut stats: Vec<_> = self.data.iter().collect();
+ let mut nodes: Vec<_> = self.nodes.iter().collect();
+ nodes.sort_by_key(|&(_, ref node)| node.stats.count * node.stats.size);
- stats.sort_by_key(|&(_, ref d)| d.count * d.size);
-
- let mut total_size = 0;
+ let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum();
eprintln!("\n{}\n", title);
eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
eprintln!("----------------------------------------------------------------");
- for (label, data) in stats {
+ let percent = |m, n| (m * 100) as f64 / n as f64;
+
+ for (label, node) in nodes {
+ let size = node.stats.count * node.stats.size;
eprintln!(
- "{:<18}{:>18}{:>14}{:>14}",
+ "{:<18}{:>10} ({:4.1}%){:>14}{:>14}",
label,
- to_readable_str(data.count * data.size),
- to_readable_str(data.count),
- to_readable_str(data.size)
+ to_readable_str(size),
+ percent(size, total_size),
+ to_readable_str(node.stats.count),
+ to_readable_str(node.stats.size)
);
-
- total_size += data.count * data.size;
+ if !node.subnodes.is_empty() {
+ let mut subnodes: Vec<_> = node.subnodes.iter().collect();
+ subnodes.sort_by_key(|&(_, ref subnode)| subnode.count * subnode.size);
+
+ for (label, subnode) in subnodes {
+ let size = subnode.count * subnode.size;
+ eprintln!(
+ "- {:<18}{:>10} ({:4.1}%){:>14}",
+ label,
+ to_readable_str(size),
+ percent(size, total_size),
+ to_readable_str(subnode.count),
+ );
+ }
+ }
}
eprintln!("----------------------------------------------------------------");
- eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
+ eprintln!("{:<18}{:>10}\n", "Total", to_readable_str(total_size));
}
}
hir_visit::walk_field_def(self, s)
}
- fn visit_variant(
- &mut self,
- v: &'v hir::Variant<'v>,
- g: &'v hir::Generics<'v>,
- item_id: hir::HirId,
- ) {
+ fn visit_variant(&mut self, v: &'v hir::Variant<'v>) {
self.record("Variant", Id::None, v);
- hir_visit::walk_variant(self, v, g, item_id)
+ hir_visit::walk_variant(self, v)
}
fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
hir_visit::walk_path(self, path)
}
+ // `PathSegment` has one inline use (in `ast::ExprKind::MethodCall`) and
+ // one non-inline use (in `Path::segments`). The latter case is more common
+ // than the former case, so we implement this visitor and tolerate the
+ // double counting in the former case.
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment<'v>) {
self.record("PathSegment", Id::None, path_segment);
hir_visit::walk_path_segment(self, path_span, path_segment)
}
}
+// Used to avoid boilerplate for types with many variants.
+macro_rules! record_variants {
+ (
+ ($self:ident, $val:expr, $kind:expr, $ty:ty, $tykind:ident), // mandatory pieces
+ [$($variant:ident),*]
+ ) => {
+ match $kind {
+ $(
+ ast::$tykind::$variant { .. } => {
+ $self.record_variant(stringify!($ty), stringify!($variant), Id::None, $val)
+ }
+ )*
+ }
+ };
+}
+
impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
- self.record("ForeignItem", Id::None, i);
+ record_variants!(
+ (self, i, i.kind, ForeignItem, ForeignItemKind),
+ [Static, Fn, TyAlias, MacCall]
+ );
ast_visit::walk_foreign_item(self, i)
}
fn visit_item(&mut self, i: &'v ast::Item) {
- self.record("Item", Id::None, i);
+ record_variants!(
+ (self, i, i.kind, Item, ItemKind),
+ [
+ ExternCrate,
+ Use,
+ Static,
+ Const,
+ Fn,
+ Mod,
+ ForeignMod,
+ GlobalAsm,
+ TyAlias,
+ Enum,
+ Struct,
+ Union,
+ Trait,
+ TraitAlias,
+ Impl,
+ MacCall,
+ MacroDef
+ ]
+ );
ast_visit::walk_item(self, i)
}
}
fn visit_stmt(&mut self, s: &'v ast::Stmt) {
- self.record("Stmt", Id::None, s);
+ record_variants!(
+ (self, s, s.kind, Stmt, StmtKind),
+ [Local, Item, Expr, Semi, Empty, MacCall]
+ );
ast_visit::walk_stmt(self, s)
}
+ fn visit_param(&mut self, p: &'v ast::Param) {
+ self.record("Param", Id::None, p);
+ ast_visit::walk_param(self, p)
+ }
+
fn visit_arm(&mut self, a: &'v ast::Arm) {
self.record("Arm", Id::None, a);
ast_visit::walk_arm(self, a)
}
fn visit_pat(&mut self, p: &'v ast::Pat) {
- self.record("Pat", Id::None, p);
+ record_variants!(
+ (self, p, p.kind, Pat, PatKind),
+ [
+ Wild,
+ Ident,
+ Struct,
+ TupleStruct,
+ Or,
+ Path,
+ Tuple,
+ Box,
+ Ref,
+ Lit,
+ Range,
+ Slice,
+ Rest,
+ Paren,
+ MacCall
+ ]
+ );
ast_visit::walk_pat(self, p)
}
- fn visit_expr(&mut self, ex: &'v ast::Expr) {
- self.record("Expr", Id::None, ex);
- ast_visit::walk_expr(self, ex)
+ fn visit_expr(&mut self, e: &'v ast::Expr) {
+ record_variants!(
+ (self, e, e.kind, Expr, ExprKind),
+ [
+ Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
+ If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
+ AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
+ InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, Err
+ ]
+ );
+ ast_visit::walk_expr(self, e)
}
fn visit_ty(&mut self, t: &'v ast::Ty) {
- self.record("Ty", Id::None, t);
+ record_variants!(
+ (self, t, t.kind, Ty, TyKind),
+ [
+ Slice,
+ Array,
+ Ptr,
+ Rptr,
+ BareFn,
+ Never,
+ Tup,
+ Path,
+ TraitObject,
+ ImplTrait,
+ Paren,
+ Typeof,
+ Infer,
+ ImplicitSelf,
+ MacCall,
+ Err,
+ CVarArgs
+ ]
+ );
+
ast_visit::walk_ty(self, t)
}
+ fn visit_generic_param(&mut self, g: &'v ast::GenericParam) {
+ self.record("GenericParam", Id::None, g);
+ ast_visit::walk_generic_param(self, g)
+ }
+
+ fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) {
+ record_variants!(
+ (self, p, p, WherePredicate, WherePredicate),
+ [BoundPredicate, RegionPredicate, EqPredicate]
+ );
+ ast_visit::walk_where_predicate(self, p)
+ }
+
fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) {
self.record("FnDecl", Id::None, fk.decl());
ast_visit::walk_fn(self, fk, s)
}
- fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
- let label = match ctxt {
- ast_visit::AssocCtxt::Trait => "TraitItem",
- ast_visit::AssocCtxt::Impl => "ImplItem",
- };
- self.record(label, Id::None, item);
- ast_visit::walk_assoc_item(self, item, ctxt);
+ fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
+ record_variants!(
+ (self, i, i.kind, AssocItem, AssocItemKind),
+ [Const, Fn, TyAlias, MacCall]
+ );
+ ast_visit::walk_assoc_item(self, i, ctxt);
}
- fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound, _ctxt: BoundKind) {
- self.record("GenericBound", Id::None, bounds);
- ast_visit::walk_param_bound(self, bounds)
+ fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) {
+ record_variants!((self, b, b, GenericBound, GenericBound), [Trait, Outlives]);
+ ast_visit::walk_param_bound(self, b)
}
fn visit_field_def(&mut self, s: &'v ast::FieldDef) {
ast_visit::walk_variant(self, v)
}
- fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime, _: ast_visit::LifetimeCtxt) {
- self.record("Lifetime", Id::None, lifetime);
- ast_visit::walk_lifetime(self, lifetime)
- }
-
- fn visit_mac_call(&mut self, mac: &'v ast::MacCall) {
- self.record("MacCall", Id::None, mac);
- ast_visit::walk_mac(self, mac)
- }
+ // `UseTree` has one inline use (in `ast::ItemKind::Use`) and one
+ // non-inline use (in `ast::UseTreeKind::Nested). The former case is more
+ // common, so we don't implement `visit_use_tree` and tolerate the missed
+ // coverage in the latter case.
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) {
self.record("PathSegment", Id::None, path_segment);
ast_visit::walk_path_segment(self, path_span, path_segment)
}
- fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
- self.record("AssocConstraint", Id::None, constraint);
- ast_visit::walk_assoc_constraint(self, constraint)
+ // `GenericArgs` has one inline use (in `ast::AssocConstraint::gen_args`) and one
+ // non-inline use (in `ast::PathSegment::args`). The latter case is more
+ // common, so we implement `visit_generic_args` and tolerate the double
+ // counting in the former case.
+ fn visit_generic_args(&mut self, sp: Span, g: &'v ast::GenericArgs) {
+ record_variants!((self, g, g, GenericArgs, GenericArgs), [AngleBracketed, Parenthesized]);
+ ast_visit::walk_generic_args(self, sp, g)
}
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
- self.record("Attribute", Id::None, attr);
+ record_variants!((self, attr, attr.kind, Attribute, AttrKind), [Normal, DocComment]);
+ ast_visit::walk_attribute(self, attr)
+ }
+
+ fn visit_expr_field(&mut self, f: &'v ast::ExprField) {
+ self.record("ExprField", Id::None, f);
+ ast_visit::walk_expr_field(self, f)
+ }
+
+ fn visit_crate(&mut self, krate: &'v ast::Crate) {
+ self.record("Crate", Id::None, krate);
+ ast_visit::walk_crate(self, krate)
+ }
+
+ fn visit_inline_asm(&mut self, asm: &'v ast::InlineAsm) {
+ self.record("InlineAsm", Id::None, asm);
+ ast_visit::walk_inline_asm(self, asm)
}
}
}
fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
- let stab_attrs =
- [sym::stable, sym::unstable, sym::rustc_const_stable, sym::rustc_const_unstable];
+ let stab_attrs = [
+ sym::stable,
+ sym::unstable,
+ sym::rustc_const_stable,
+ sym::rustc_const_unstable,
+ sym::rustc_default_body_unstable,
+ ];
// Find a stability attribute: one of #[stable(…)], #[unstable(…)],
- // #[rustc_const_stable(…)], or #[rustc_const_unstable(…)].
+ // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable].
if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
let meta_kind = attr.meta_kind();
if let Some(MetaItemKind::List(ref metas)) = meta_kind {
// This additional check for stability is to make sure we
// don't emit additional, irrelevant errors for malformed
// attributes.
- let is_unstable =
- matches!(*stab_attr, sym::unstable | sym::rustc_const_unstable);
+ let is_unstable = matches!(
+ *stab_attr,
+ sym::unstable
+ | sym::rustc_const_unstable
+ | sym::rustc_default_body_unstable
+ );
if since.is_some() || is_unstable {
return Some((feature, since, attr.span));
}
//! Checks validity of naked functions.
-use rustc_ast::{Attribute, InlineAsmOptions};
+use rustc_ast::InlineAsmOptions;
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{FnKind, Visitor};
-use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
-fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
- tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
-}
-
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_naked_functions, ..*providers };
}
-struct CheckNakedFunctions<'tcx> {
- tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
- fn visit_fn(
- &mut self,
- fk: FnKind<'_>,
- _fd: &'tcx hir::FnDecl<'tcx>,
- body_id: hir::BodyId,
- span: Span,
- hir_id: HirId,
- ) {
- let ident_span;
- let fn_header;
-
- match fk {
- FnKind::Closure => {
- // Closures with a naked attribute are rejected during attribute
- // check. Don't validate them any further.
- return;
- }
- FnKind::ItemFn(ident, _, ref header, ..) => {
- ident_span = ident.span;
- fn_header = header;
- }
-
- FnKind::Method(ident, ref sig, ..) => {
- ident_span = ident.span;
- fn_header = &sig.header;
- }
+fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
+ let items = tcx.hir_module_items(module_def_id);
+ for def_id in items.definitions() {
+ if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
+ continue;
}
- let attrs = self.tcx.hir().attrs(hir_id);
- let naked = attrs.iter().any(|attr| attr.has_name(sym::naked));
- if naked {
- let body = self.tcx.hir().body(body_id);
- check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
- check_no_patterns(self.tcx, body.params);
- check_no_parameters_use(self.tcx, body);
- check_asm(self.tcx, body, span);
- check_inline(self.tcx, attrs);
+ let naked = tcx.has_attr(def_id.to_def_id(), sym::naked);
+ if !naked {
+ continue;
}
+
+ let (fn_header, body_id) = match tcx.hir().get_by_def_id(def_id) {
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })
+ | hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)),
+ ..
+ })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(sig, body_id),
+ ..
+ }) => (sig.header, *body_id),
+ _ => continue,
+ };
+
+ let body = tcx.hir().body(body_id);
+ check_abi(tcx, def_id, fn_header.abi);
+ check_no_patterns(tcx, body.params);
+ check_no_parameters_use(tcx, body);
+ check_asm(tcx, def_id, body);
+ check_inline(tcx, def_id);
}
}
/// Check that the function isn't inlined.
-fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
- for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
+fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+ let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
+ for attr in attrs {
tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
}
}
/// Checks that function uses non-Rust ABI.
-fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
+fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
if abi == Abi::Rust {
- tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, fn_ident_span, |lint| {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let span = tcx.def_span(def_id);
+ tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| {
lint.build("Rust ABI is unsupported in naked functions").emit();
});
}
}
/// Checks that function body contains a single inline assembly block.
-fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
+fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
this.visit_body(body);
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
} else {
let mut diag = struct_span_err!(
tcx.sess,
- fn_span,
+ tcx.def_span(def_id),
E0787,
"naked functions must contain a single asm block"
);
//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.
-use attr::StabilityLevel;
-use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason};
+use rustc_attr::{
+ self as attr, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason,
+};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{FieldDef, Generics, HirId, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
+use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
return;
}
- let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
+ let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
let mut const_span = None;
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
}
}
+ if let Some((body_stab, _span)) = body_stab {
+ // FIXME: check that this item can have body stability
+
+ self.index.default_body_stab_map.insert(def_id, body_stab);
+ debug!(?self.index.default_body_stab_map);
+ }
+
let stab = stab.map(|(stab, span)| {
// Error if prohibited, or can't inherit anything from a container.
if kind == AnnotationKind::Prohibited
);
}
- fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
+ fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
self.annotate(
self.tcx.hir().local_def_id(var.id),
var.span,
);
}
- intravisit::walk_variant(v, var, g, item_id)
+ intravisit::walk_variant(v, var)
},
)
}
intravisit::walk_impl_item(self, ii);
}
- fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
+ fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
self.check_missing_stability(self.tcx.hir().local_def_id(var.id), var.span);
- intravisit::walk_variant(self, var, g, item_id);
+ intravisit::walk_variant(self, var);
}
fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
let mut index = Index {
stab_map: Default::default(),
const_stab_map: Default::default(),
+ default_body_stab_map: Default::default(),
depr_map: Default::default(),
implications: Default::default(),
};
stability_implications: |tcx, _| tcx.stability().implications.clone(),
lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
+ lookup_default_body_stability: |tcx, id| {
+ tcx.stability().local_default_body_stability(id.expect_local())
+ },
lookup_deprecation_entry: |tcx, id| {
tcx.stability().local_deprecation_entry(id.expect_local())
},
let features = self.tcx.features();
if features.staged_api {
let attrs = self.tcx.hir().attrs(item.hir_id());
- let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span);
+ let (stab, const_stab, _) =
+ attr::find_stability(&self.tcx.sess, attrs, item.span);
// If this impl block has an #[unstable] attribute, give an
// error if all involved types and traits are stable, because
+use rustc_errors::DiagnosticArgFromDisplay;
use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
use rustc_span::{Span, Symbol};
#[label]
pub span: Span,
pub kind: &'a str,
- pub descr: String,
+ pub descr: DiagnosticArgFromDisplay<'a>,
}
#[derive(SessionDiagnostic)]
pub span: Span,
pub vis_descr: &'static str,
pub kind: &'a str,
- pub descr: String,
+ pub descr: DiagnosticArgFromDisplay<'a>,
#[label(privacy::visibility_label)]
pub vis_span: Span,
}
pub span: Span,
pub vis_descr: &'static str,
pub kind: &'a str,
- pub descr: String,
+ pub descr: DiagnosticArgFromDisplay<'a>,
#[label(privacy::visibility_label)]
pub vis_span: Span,
}
#[lint(privacy::from_private_dep_in_public_interface)]
pub struct FromPrivateDependencyInPublicInterface<'a> {
pub kind: &'a str,
- pub descr: String,
+ pub descr: DiagnosticArgFromDisplay<'a>,
pub krate: Symbol,
}
pub struct PrivateInPublicLint<'a> {
pub vis_descr: &'static str,
pub kind: &'a str,
- pub descr: String,
+ pub descr: DiagnosticArgFromDisplay<'a>,
}
// `impl Pub<Priv> { pub fn my_method() {} }` is considered a private type,
// so we need to visit the self type additionally.
if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
- if let ty::ImplContainer(impl_def_id) = assoc_item.container {
+ if let Some(impl_def_id) = assoc_item.impl_container(tcx) {
tcx.type_of(impl_def_id).visit_with(self)?;
}
}
self.reach(item.def_id, item_level).generics().predicates();
for trait_item_ref in trait_item_refs {
+ let tcx = self.tcx;
let mut reach = self.reach(trait_item_ref.id.def_id, item_level);
reach.generics().predicates();
if trait_item_ref.kind == AssocItemKind::Type
- && !trait_item_ref.defaultness.has_value()
+ && !tcx.impl_defaultness(trait_item_ref.id.def_id).has_value()
{
// No type to visit.
} else {
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
let is_error = !self.item_is_accessible(def_id);
if is_error {
- self.tcx.sess.emit_err(ItemIsPrivate {
- span: self.span,
- kind,
- descr: descr.to_string(),
- });
+ self.tcx.sess.emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
}
is_error
}
};
let kind = kind.descr(def_id);
let _ = match name {
- Some(name) => sess.emit_err(ItemIsPrivate { span, kind, descr: name }),
+ Some(name) => {
+ sess.emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
+ }
None => sess.emit_err(UnnamedItemIsPrivate { span, kind }),
};
return;
intravisit::walk_ty(self, t)
}
- fn visit_variant(
- &mut self,
- v: &'tcx hir::Variant<'tcx>,
- g: &'tcx hir::Generics<'tcx>,
- item_id: hir::HirId,
- ) {
+ fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) {
self.in_variant = true;
- intravisit::walk_variant(self, v, g, item_id);
+ intravisit::walk_variant(self, v);
self.in_variant = false;
}
}
self.tcx.def_span(self.item_def_id.to_def_id()),
FromPrivateDependencyInPublicInterface {
kind,
- descr: descr.to_string(),
+ descr: descr.into(),
krate: self.tcx.crate_name(def_id.krate),
},
);
}
};
let span = self.tcx.def_span(self.item_def_id.to_def_id());
- let descr = descr.to_string();
if self.has_old_errors
|| self.in_assoc_ty
|| self.tcx.resolutions(()).has_pub_restricted
{
- let vis_span =
- self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
+ let vis_span = self.tcx.def_span(def_id);
if kind == "trait" {
self.tcx.sess.emit_err(InPublicInterfaceTraits {
span,
vis_descr,
kind,
- descr,
+ descr: descr.into(),
vis_span,
});
} else {
span,
vis_descr,
kind,
- descr,
+ descr: descr.into(),
vis_span,
});
}
lint::builtin::PRIVATE_IN_PUBLIC,
hir_id,
span,
- PrivateInPublicLint { vis_descr, kind, descr },
+ PrivateInPublicLint { vis_descr, kind, descr: descr.into() },
);
}
}
&self,
def_id: LocalDefId,
assoc_item_kind: AssocItemKind,
- defaultness: hir::Defaultness,
vis: ty::Visibility,
) {
let mut check = self.check(def_id, vis);
let (check_ty, is_assoc_ty) = match assoc_item_kind {
AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false),
- AssocItemKind::Type => (defaultness.has_value(), true),
+ AssocItemKind::Type => (self.tcx.impl_defaultness(def_id).has_value(), true),
};
check.in_assoc_ty = is_assoc_ty;
check.generics().predicates();
self.check_assoc_item(
trait_item_ref.id.def_id,
trait_item_ref.kind,
- trait_item_ref.defaultness,
item_visibility,
);
self.check_assoc_item(
impl_item_ref.id.def_id,
impl_item_ref.kind,
- impl_item_ref.defaultness,
impl_item_vis,
);
}
-use crate::dep_graph::DepContext;
use crate::query::plumbing::CycleError;
use crate::query::{QueryContext, QueryStackFrame};
use rustc_hir::def::DefKind;
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
assert!(!stack.is_empty());
- let fix_span = |span: Span, query: &QueryStackFrame| {
- sess.source_map().guess_head_span(query.default_span(span))
- };
-
- let span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
+ let span = stack[0].query.default_span(stack[1 % stack.len()].span);
let mut err =
struct_span_err!(sess, span, E0391, "cycle detected when {}", stack[0].query.description);
for i in 1..stack.len() {
let query = &stack[i].query;
- let span = fix_span(stack[(i + 1) % stack.len()].span, query);
+ let span = query.default_span(stack[(i + 1) % stack.len()].span);
err.span_note(span, &format!("...which requires {}...", query.description));
}
}
if let Some((span, query)) = usage {
- err.span_note(fix_span(span, &query), &format!("cycle used when {}", query.description));
+ err.span_note(query.default_span(span), &format!("cycle used when {}", query.description));
}
err
Level::FailureNote,
&format!("#{} [{}] {}", i, query_info.query.name, query_info.query.description),
);
- diag.span =
- tcx.dep_context().sess().source_map().guess_head_span(query_info.job.span).into();
+ diag.span = query_info.job.span.into();
handler.force_print_diagnostic(diag);
current_query = query_info.job.parent;
};
let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
LOCAL_CRATE => self.opt_span(def_id),
- _ => Some(
- self.session
- .source_map()
- .guess_head_span(self.cstore().get_span_untracked(def_id, self.session)),
- ),
+ _ => Some(self.cstore().get_span_untracked(def_id, self.session)),
});
if let Some(def_span) = def_span {
if span.overlaps(def_span) {
Applicability::MaybeIncorrect,
);
if let [first, .., last] = &path[..] {
- err.span_suggestion_verbose(
- first.ident.span.until(last.ident.span),
- &format!("if you import `{}`, refer to it directly", last.ident),
- "",
- Applicability::Unspecified,
- );
+ let sp = first.ident.span.until(last.ident.span);
+ if sp.can_be_used_for_suggestions() {
+ err.span_suggestion_verbose(
+ sp,
+ &format!("if you import `{}`, refer to it directly", last.ident),
+ "",
+ Applicability::Unspecified,
+ );
+ }
}
} else {
msg.push(':');
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
// NodeId `ty.id`.
// This span will be used in case of elision failure.
- let span = self.r.session.source_map().next_point(ty.span.shrink_to_lo());
+ let span = self.r.session.source_map().start_point(ty.span);
self.resolve_elided_lifetime(ty.id, span);
visit::walk_ty(self, ty);
}
self.diagnostic_metadata.current_trait_object = prev;
self.diagnostic_metadata.current_type_path = prev_ty;
}
- fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) {
+ fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef) {
let span = tref.span.shrink_to_lo().to(tref.trait_ref.path.span.shrink_to_lo());
self.with_generic_param_rib(
&tref.bound_generic_params,
continue;
}
- let missing = match source {
- PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
+ let node_ids = self.r.next_node_ids(expected_lifetimes);
+ self.record_lifetime_res(
+ segment_id,
+ LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
+ LifetimeElisionCandidate::Ignore,
+ );
+
+ let inferred = match source {
+ PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => false,
PathSource::Expr(..)
| PathSource::Pat
| PathSource::Struct
- | PathSource::TupleStruct(..) => false,
+ | PathSource::TupleStruct(..) => true,
};
- if !missing && !segment.has_generic_args {
+ if inferred {
+ // Do not create a parameter for patterns and expressions: type checking can infer
+ // the appropriate lifetime for us.
+ for id in node_ids {
+ self.record_lifetime_res(
+ id,
+ LifetimeRes::Infer,
+ LifetimeElisionCandidate::Named,
+ );
+ }
continue;
}
};
let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
- let node_ids = self.r.next_node_ids(expected_lifetimes);
- self.record_lifetime_res(
- segment_id,
- LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
- LifetimeElisionCandidate::Ignore,
- );
-
- if !missing {
- // Do not create a parameter for patterns and expressions.
- for id in node_ids {
- self.record_lifetime_res(
- id,
- LifetimeRes::Infer,
- LifetimeElisionCandidate::Named,
- );
- }
- continue;
- }
-
let missing_lifetime = MissingLifetime {
id: node_ids.start,
span: elided_lifetime_span,
ExprKind::Field(ref subexpression, _) => {
self.resolve_expr(subexpression, Some(expr));
}
- ExprKind::MethodCall(ref segment, ref arguments, _) => {
- let mut arguments = arguments.iter();
- self.resolve_expr(arguments.next().unwrap(), Some(expr));
+ ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _) => {
+ self.resolve_expr(receiver, Some(expr));
for argument in arguments {
self.resolve_expr(argument, None);
}
fn def_span(&self, def_id: DefId) -> Option<Span> {
match def_id.krate {
LOCAL_CRATE => self.r.opt_span(def_id),
- _ => Some(
- self.r
- .session
- .source_map()
- .guess_head_span(self.r.cstore().get_span_untracked(def_id, self.r.session)),
- ),
+ _ => Some(self.r.cstore().get_span_untracked(def_id, self.r.session)),
}
}
fn suggest_introducing_lifetime(
&self,
- err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ err: &mut Diagnostic,
name: Option<&str>,
- suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool,
+ suggest: impl Fn(&mut Diagnostic, bool, Span, &str, String) -> bool,
) {
let mut suggest_note = true;
for rib in self.lifetime_ribs.iter().rev() {
pub(crate) fn add_missing_lifetime_specifiers_label(
&mut self,
- err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ err: &mut Diagnostic,
lifetime_refs: Vec<MissingLifetime>,
function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
) {
label_res_map: NodeMap<NodeId>,
/// Resolutions for lifetimes.
lifetimes_res_map: NodeMap<LifetimeRes>,
+ /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
+ /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
+ /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
+ /// field from the original parameter 'a to the new parameter 'a1.
+ generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
/// Lifetime parameters that lowering will have to introduce.
extra_lifetime_params_map: NodeMap<Vec<(Ident, NodeId, LifetimeRes)>>,
import_res_map: Default::default(),
label_res_map: Default::default(),
lifetimes_res_map: Default::default(),
+ generics_def_id_map: Vec::new(),
extra_lifetime_params_map: Default::default(),
extern_crate_map: Default::default(),
reexport_map: FxHashMap::default(),
import_res_map: self.import_res_map,
label_res_map: self.label_res_map,
lifetimes_res_map: self.lifetimes_res_map,
+ generics_def_id_map: self.generics_def_id_map,
extra_lifetime_params_map: self.extra_lifetime_params_map,
next_node_id: self.next_node_id,
node_id_to_def_id: self.node_id_to_def_id,
import_res_map: self.import_res_map.clone(),
label_res_map: self.label_res_map.clone(),
lifetimes_res_map: self.lifetimes_res_map.clone(),
+ generics_def_id_map: self.generics_def_id_map.clone(),
extra_lifetime_params_map: self.extra_lifetime_params_map.clone(),
next_node_id: self.next_node_id.clone(),
node_id_to_def_id: self.node_id_to_def_id.clone(),
return None;
};
let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
- ty::ImplContainer(_) => (Some(method_id), None),
- ty::TraitContainer(_) => (None, Some(method_id)),
+ ty::ImplContainer => (Some(method_id), None),
+ ty::TraitContainer => (None, Some(method_id)),
};
let sub_span = seg.ident.span;
filter!(self.span_utils, sub_span);
}
Res::Def(HirDefKind::AssocFn, decl_id) => {
let def_id = if decl_id.is_local() {
- if self.tcx.associated_item(decl_id).defaultness.has_value() {
+ if self.tcx.impl_defaultness(decl_id).has_value() {
Some(decl_id)
} else {
None
repr_packed,
repr_simd,
repr_transparent,
+ require,
residual,
result,
rhs,
rustc_conversion_suggestion,
rustc_deallocator,
rustc_def_path,
+ rustc_default_body_unstable,
rustc_diagnostic_item,
rustc_diagnostic_macros,
rustc_dirty,
trait_alias,
trait_upcasting,
transmute,
+ transmute_trait,
transparent,
transparent_enums,
transparent_unions,
mod mips;
mod mips64;
mod msp430;
-mod nvptx;
mod nvptx64;
mod powerpc;
mod powerpc64;
match &cx.target_spec().arch[..] {
"x86" => {
- let flavor = if let spec::abi::Abi::Fastcall { .. } = abi {
- x86::Flavor::Fastcall
+ let flavor = if let spec::abi::Abi::Fastcall { .. }
+ | spec::abi::Abi::Vectorcall { .. } = abi
+ {
+ x86::Flavor::FastcallOrVectorcall
} else {
x86::Flavor::General
};
"msp430" => msp430::compute_abi_info(self),
"sparc" => sparc::compute_abi_info(cx, self),
"sparc64" => sparc64::compute_abi_info(cx, self),
- "nvptx" => nvptx::compute_abi_info(self),
"nvptx64" => {
if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel {
nvptx64::compute_ptx_kernel_abi_info(cx, self)
+++ /dev/null
-// Reference: PTX Writer's Guide to Interoperability
-// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
-
-use crate::abi::call::{ArgAbi, FnAbi};
-
-fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
- if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 {
- ret.make_indirect();
- } else {
- ret.extend_integer_width_to(32);
- }
-}
-
-fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
- if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 {
- arg.make_indirect();
- } else {
- arg.extend_integer_width_to(32);
- }
-}
-
-pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
- if !fn_abi.ret.is_ignore() {
- classify_ret(&mut fn_abi.ret);
- }
-
- for arg in &mut fn_abi.args {
- if arg.is_ignore() {
- continue;
- }
- classify_arg(arg);
- }
-}
#[derive(PartialEq)]
pub enum Flavor {
General,
- Fastcall,
+ FastcallOrVectorcall,
}
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
}
}
- if flavor == Flavor::Fastcall {
+ if flavor == Flavor::FastcallOrVectorcall {
// Mark arguments as InReg like clang does it,
- // so our fastcall is compatible with C/C++ fastcall.
+ // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall.
// Clang reference: lib/CodeGen/TargetInfo.cpp
// See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
impl Align {
pub const ONE: Align = Align { pow2: 0 };
+ pub const MAX: Align = Align { pow2: 29 };
#[inline]
pub fn from_bits(bits: u64) -> Result<Align, String> {
if bytes != 1 {
return Err(not_power_of_2(align));
}
- if pow2 > 29 {
+ if pow2 > Self::MAX.pow2 {
return Err(too_large(align));
}
-use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
pub fn target() -> Target {
- let mut base = super::apple_base::opts("macos");
+ let arch = "arm64";
+ let mut base = super::apple_base::opts("macos", arch, "");
base.cpu = "apple-a14".into();
base.max_atomic_width = Some(128);
// FIXME: The leak sanitizer currently fails the tests, see #88132.
base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-arch", "arm64"]);
base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
// correctly, we do too.
- let llvm_target = super::apple_base::macos_llvm_target("arm64");
+ let llvm_target = super::apple_base::macos_llvm_target(arch);
Target {
llvm_target: llvm_target.into(),
use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{FramePointer, Target, TargetOptions};
+use crate::spec::{FramePointer, LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
+ let llvm_target = "arm64-apple-ios14.0-macabi";
+
+ let mut base = opts("ios", Arch::Arm64_macabi);
+ base.add_pre_link_args(LinkerFlavor::Gcc, &["-target", llvm_target]);
+
Target {
- llvm_target: "arm64-apple-ios14.0-macabi".into(),
+ llvm_target: llvm_target.into(),
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
arch: "aarch64".into(),
-disable-llvm-passes\0\
-Os\0"
.into(),
- ..opts("ios", Arch::Arm64_macabi)
+ ..base
},
}
}
// for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
// was to always emit `uwtable`).
base.default_uwtable = true;
- base.crt_static_respected = false;
+ base.crt_static_respected = true;
base
}
use std::{borrow::Cow, env};
-use crate::spec::{cvs, FramePointer, LldFlavor, SplitDebuginfo, TargetOptions};
+use crate::spec::{cvs, FramePointer, SplitDebuginfo, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor};
+
+fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
+ let mut args = LinkArgs::new();
+
+ let platform_name = match abi {
+ "sim" => format!("{}-simulator", os),
+ "macabi" => "mac-catalyst".to_string(),
+ _ => os.to_string(),
+ };
+
+ let platform_version = match os.as_ref() {
+ "ios" => ios_lld_platform_version(),
+ "tvos" => tvos_lld_platform_version(),
+ "watchos" => watchos_lld_platform_version(),
+ "macos" => macos_lld_platform_version(arch),
+ _ => unreachable!(),
+ };
+
+ if abi != "macabi" {
+ args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch.into()]);
+ }
+
+ args.insert(
+ LinkerFlavor::Lld(LldFlavor::Ld64),
+ vec![
+ "-arch".into(),
+ arch.into(),
+ "-platform_version".into(),
+ platform_name.into(),
+ platform_version.clone().into(),
+ platform_version.into(),
+ ],
+ );
+
+ args
+}
-pub fn opts(os: &'static str) -> TargetOptions {
+pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOptions {
// ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
// either the linker will complain if it is used or the binary will end up
// segfaulting at runtime when run on 10.6. Rust by default supports macOS
// macOS has -dead_strip, which doesn't rely on function_sections
function_sections: false,
dynamic_linking: true,
+ pre_link_args: pre_link_args(os, arch, abi),
linker_is_gnu: false,
families: cvs!["unix"],
is_like_osx: true,
.unwrap_or_else(|| macos_default_deployment_target(arch))
}
+fn macos_lld_platform_version(arch: &str) -> String {
+ let (major, minor) = macos_deployment_target(arch);
+ format!("{}.{}", major, minor)
+}
+
pub fn macos_llvm_target(arch: &str) -> String {
let (major, minor) = macos_deployment_target(arch);
format!("{}-apple-macosx{}.{}.0", arch, major, minor)
format!("{}-apple-ios{}.{}.0", arch, major, minor)
}
+fn ios_lld_platform_version() -> String {
+ let (major, minor) = ios_deployment_target();
+ format!("{}.{}", major, minor)
+}
+
pub fn ios_sim_llvm_target(arch: &str) -> String {
let (major, minor) = ios_deployment_target();
format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
}
+fn tvos_deployment_target() -> (u32, u32) {
+ deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
+}
+
+fn tvos_lld_platform_version() -> String {
+ let (major, minor) = tvos_deployment_target();
+ format!("{}.{}", major, minor)
+}
+
fn watchos_deployment_target() -> (u32, u32) {
deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
}
+fn watchos_lld_platform_version() -> String {
+ let (major, minor) = watchos_deployment_target();
+ format!("{}.{}", major, minor)
+}
+
pub fn watchos_sim_llvm_target(arch: &str) -> String {
let (major, minor) = watchos_deployment_target();
format!("{}-apple-watchos{}.{}.0-simulator", arch, major, minor)
-use crate::{spec::cvs, spec::TargetOptions};
+use crate::spec::{cvs, TargetOptions};
use std::borrow::Cow;
use Arch::*;
Arm64_sim,
}
+fn target_arch_name(arch: Arch) -> &'static str {
+ match arch {
+ Armv7 => "armv7",
+ Armv7k => "armv7k",
+ Armv7s => "armv7s",
+ Arm64 | Arm64_macabi | Arm64_sim => "arm64",
+ Arm64_32 => "arm64_32",
+ I386 => "i386",
+ X86_64 | X86_64_macabi => "x86_64",
+ }
+}
+
fn target_abi(arch: Arch) -> &'static str {
match arch {
Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 => "",
dynamic_linking: false,
link_env_remove: link_env_remove(arch),
has_thread_local: false,
- ..super::apple_base::opts(os)
+ ..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch))
}
}
--- /dev/null
+//! Targets the ARMv4T, with code as `a32` code by default.
+//!
+//! Primarily of use for the GBA, but usable with other devices too.
+//!
+//! Please ping @Lokathor if changes are needed.
+//!
+//! This target profile assumes that you have the ARM binutils in your path
+//! (specifically the linker, `arm-none-eabi-ld`). They can be obtained for free
+//! for all major OSes from the ARM developer's website, and they may also be
+//! available in your system's package manager. Unfortunately, the standard
+//! linker that Rust uses (`lld`) only supports as far back as `ARMv5TE`, so we
+//! must use the GNU `ld` linker.
+//!
+//! **Important:** This target profile **does not** specify a linker script. You
+//! just get the default link script when you build a binary for this target.
+//! The default link script is very likely wrong, so you should use
+//! `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
+
+use crate::spec::{cvs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "armv4t-none-eabi".into(),
+ pointer_width: 32,
+ arch: "arm".into(),
+ /* Data layout args are '-' separated:
+ * little endian
+ * stack is 64-bit aligned (EABI)
+ * pointers are 32-bit
+ * i64 must be 64-bit aligned (EABI)
+ * mangle names with ELF style
+ * native integers are 32-bit
+ * All other elements are default
+ */
+ data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+ options: TargetOptions {
+ abi: "eabi".into(),
+ linker_flavor: LinkerFlavor::Ld,
+ linker: Some("arm-none-eabi-ld".into()),
+ asm_args: cvs!["-mthumb-interwork", "-march=armv4t", "-mlittle-endian",],
+ features: "+soft-float,+strict-align".into(),
+ main_needs_argc_argv: false,
+ atomic_cas: false,
+ has_thumb_interworking: true,
+ relocation_model: RelocModel::Static,
+ panic_strategy: PanicStrategy::Abort,
+ // from thumb_base, rust-lang/rust#44993.
+ emit_debug_gdb_scripts: false,
+ // from thumb_base, apparently gcc/clang give enums a minimum of 8 bits on no-os targets
+ c_enum_min_bits: 8,
+ ..Default::default()
+ },
+ }
+}
use crate::spec::{crt_objects, cvs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions};
pub fn opts() -> TargetOptions {
+ // This mirrors the linker options provided by clang. We presume lld for
+ // now. When using clang as the linker it will supply these options for us,
+ // so we only list them for ld/lld.
+ //
+ // https://github.com/llvm/llvm-project/blob/db9322b2066c55254e7691efeab863f43bfcc084/clang/lib/Driver/ToolChains/Fuchsia.cpp#L31
let pre_link_args = TargetOptions::link_args(
LinkerFlavor::Ld,
&[
use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
- let mut base = super::apple_base::opts("macos");
+ // ld64 only understand i386 and not i686
+ let mut base = super::apple_base::opts("macos", "i386", "");
base.cpu = "yonah".into();
base.max_atomic_width = Some(64);
base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
)
}
(LinkerFlavor::Gcc, LldFlavor::Ld64) => {
- assert_matches!(flavor, LinkerFlavor::Gcc)
+ assert_matches!(
+ flavor,
+ LinkerFlavor::Lld(LldFlavor::Ld64) | LinkerFlavor::Gcc
+ )
}
(LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link), LldFlavor::Link) => {
assert_matches!(
abi: "eabi".into(),
// The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
// with +strict-align.
- features: "+strict-align".into(),
+ // Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
+ // The resulting atomics are ABI incompatible with atomics backed by libatomic.
+ features: "+strict-align,+atomics-32".into(),
// There are no atomic CAS instructions available in the instruction set of the ARMv6-M
// architecture
atomic_cas: false,
use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, StackProbeType, Target};
pub fn target() -> Target {
- let mut base = super::apple_base::opts("macos");
+ let arch = "x86_64";
+ let mut base = super::apple_base::opts("macos", arch, "");
base.cpu = "core2".into();
base.max_atomic_width = Some(128); // core2 support cmpxchg16b
base.frame_pointer = FramePointer::Always;
- base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-arch", "x86_64"]);
+ base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
// correctly, we do too.
- let arch = "x86_64";
let llvm_target = super::apple_base::macos_llvm_target(&arch);
Target {
use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{StackProbeType, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
- let base = opts("ios", Arch::X86_64_macabi);
+ let llvm_target = "x86_64-apple-ios13.0-macabi";
+
+ let mut base = opts("ios", Arch::X86_64_macabi);
+ base.add_pre_link_args(LinkerFlavor::Gcc, &["-target", llvm_target]);
+
Target {
- llvm_target: "x86_64-apple-ios13.0-macabi".into(),
+ llvm_target: llvm_target.into(),
pointer_width: 64,
data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
.into(),
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
+rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
// At this point, we already have all of the bounds we need. FulfillmentContext is used
// to store all of the necessary region/lifetime bounds in the InferContext, as well as
// an additional sanity check.
- let mut fulfill = FulfillmentContext::new();
- fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
- let errors = fulfill.select_all_or_error(&infcx);
-
+ let errors =
+ super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
if !errors.is_empty() {
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
}
use crate::infer::{DefiningAnchor, TyCtxtInferExt};
use crate::traits::{
- FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
+ ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
Unimplemented,
};
use rustc_middle::traits::CodegenObligationError;
tcx: TyCtxt<'tcx>,
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
- // Remove any references to regions; this helps improve caching.
- let trait_ref = tcx.erase_regions(trait_ref);
// We expect the input to be fully normalized.
debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
// Currently, we use a fulfillment context to completely resolve
// all nested obligations. This is because they can inform the
// inference of the impl's type parameters.
- let mut fulfill_cx = FulfillmentContext::new();
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
let impl_source = selection.map(|predicate| {
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
use crate::traits::util::impl_subject_and_oblig;
use crate::traits::SkipLeakCheck;
use crate::traits::{
- self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
- PredicateObligations, SelectionContext,
+ self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
+ SelectionContext,
};
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::{util, TraitEngine};
+use rustc_infer::traits::util;
use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::subst::Subst;
let impl_env = tcx.param_env(impl1_def_id);
let subject1 = match traits::fully_normalize(
&infcx,
- FulfillmentContext::new(),
ObligationCause::dummy(),
impl_env,
tcx.impl_subject(impl1_def_id),
return false;
};
- let mut fulfillment_cx = FulfillmentContext::new();
- fulfillment_cx.register_predicate_obligation(infcx, o);
-
- let errors = fulfillment_cx.select_all_or_error(infcx);
-
+ let errors = super::fully_solve_obligation(infcx, o);
if !errors.is_empty() {
return false;
}
- // FIXME -- also add "assumed to be well formed" types into the `outlives_env`
let outlives_env = OutlivesEnvironment::new(param_env);
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
error: &MismatchedProjectionTypes<'tcx>,
);
+ fn maybe_detailed_projection_msg(
+ &self,
+ pred: ty::ProjectionPredicate<'tcx>,
+ normalized_ty: ty::Term<'tcx>,
+ expected_ty: ty::Term<'tcx>,
+ ) -> Option<String>;
+
fn fuzzy_match_tys(
&self,
a: Ty<'tcx>,
normalized_ty,
data.term,
) {
- values = Some(infer::ValuePairs::Terms(ExpectedFound::new(
- is_normalized_ty_expected,
- normalized_ty,
- data.term,
- )));
+ values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
err_buf = error;
err = &err_buf;
}
}
- let mut diag = struct_span_err!(
- self.tcx.sess,
- obligation.cause.span,
- E0271,
- "type mismatch resolving `{}`",
- predicate
- );
+ let msg = values
+ .and_then(|(predicate, _, normalized_ty, expected_ty)| {
+ self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
+ })
+ .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
+ let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
+
let secondary_span = match predicate.kind().skip_binder() {
ty::PredicateKind::Projection(proj) => self
.tcx
&mut diag,
&obligation.cause,
secondary_span,
- values,
+ values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| {
+ infer::ValuePairs::Terms(ExpectedFound::new(
+ is_normalized_ty_expected,
+ normalized_ty,
+ term,
+ ))
+ }),
err,
true,
false,
});
}
+ fn maybe_detailed_projection_msg(
+ &self,
+ pred: ty::ProjectionPredicate<'tcx>,
+ normalized_ty: ty::Term<'tcx>,
+ expected_ty: ty::Term<'tcx>,
+ ) -> Option<String> {
+ let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
+ let self_ty = pred.projection_ty.self_ty();
+
+ if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() {
+ Some(format!(
+ "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`",
+ fn_kind = self_ty.prefix_string(self.tcx)
+ ))
+ } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
+ Some(format!(
+ "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
+ ))
+ } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
+ Some(format!(
+ "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
+ ))
+ } else {
+ None
+ }
+ }
+
fn fuzzy_match_tys(
&self,
mut a: Ty<'tcx>,
}
] = path.segments
&& data.trait_ref.def_id == *trait_id
- && self.tcx.trait_of_item(item_id) == Some(*trait_id)
+ && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
&& !self.is_tainted_by_errors()
{
let (verb, noun) = match self.tcx.associated_item(item_id).kind {
if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the slice's type's original
// signature with no type arguments resolved
- let type_string = self.tcx.type_of(def.did()).to_string();
- flags.push((sym::_Self, Some(format!("[{type_string}]"))));
+ flags.push((sym::_Self, Some(format!("[{}]", self.tcx.type_of(def.did())))));
}
if aty.is_integral() {
flags.push((sym::_Self, Some("[{integral}]".to_string())));
if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the array's type's original
// signature with no type arguments resolved
- let type_string = self.tcx.type_of(def.did()).to_string();
- flags.push((sym::_Self, Some(format!("[{type_string}; _]"))));
+ let def_ty = self.tcx.type_of(def.did());
+ flags.push((sym::_Self, Some(format!("[{def_ty}; _]"))));
if let Some(n) = len {
- flags.push((sym::_Self, Some(format!("[{type_string}; {n}]"))));
+ flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]"))));
}
}
if aty.is_integral() {
));
let original_span = err.span.primary_span().unwrap();
- let original_span = self.tcx.sess.source_map().guess_head_span(original_span);
let mut span = MultiSpan::from_span(original_span);
let message = outer_generator
if let Some(ident) = self
.tcx
.opt_associated_item(trait_item_def_id)
- .and_then(|i| self.tcx.opt_item_ident(i.container.id()))
+ .and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx)))
{
assoc_span.push_span_label(ident.span, "in this trait");
}
} else {
ObligationCause::dummy_with_span(span)
};
- let ctx = traits::FulfillmentContext::new();
- match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) {
+ match traits::fully_normalize(&infcx, cause, param_env, ty) {
Ok(ty) => {
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
infringing.push((field, ty));
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
+use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::visit::TypeVisitable;
-use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
+use rustc_middle::ty::{
+ self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
+ VtblEntry,
+};
use rustc_span::{sym, Span};
use smallvec::SmallVec;
// this function's result remains infallible, we must confirm
// that guess. While imperfect, I believe this is sound.
- // The handling of regions in this area of the code is terrible,
- // see issue #29149. We should be able to improve on this with
- // NLL.
- let mut fulfill_cx = FulfillmentContext::new();
-
// We can use a dummy node-id here because we won't pay any mind
// to region obligations that arise (there shouldn't really be any
// anyhow).
let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID);
- fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
+ // The handling of regions in this area of the code is terrible,
+ // see issue #29149. We should be able to improve on this with
+ // NLL.
+ let errors = fully_solve_bound(infcx, cause, param_env, ty, def_id);
// Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok.
- match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ match &errors[..] {
[] => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
// them here too, and we will remove this function when
// we move over to lazy normalization *anyway*.
tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
- let fulfill_cx = FulfillmentContext::new();
- let predicates =
- match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
- Ok(predicates) => predicates,
- Err(errors) => {
- let reported = infcx.report_fulfillment_errors(&errors, None, false);
- return Err(reported);
- }
- };
+ let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
+ Ok(predicates) => predicates,
+ Err(errors) => {
+ let reported = infcx.report_fulfillment_errors(&errors, None, false);
+ return Err(reported);
+ }
+ };
debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
)
}
+/// Normalize a type and process all resulting obligations, returning any errors
pub fn fully_normalize<'a, 'tcx, T>(
infcx: &InferCtxt<'a, 'tcx>,
- mut fulfill_cx: FulfillmentContext<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: T,
"fully_normalize: normalized_value={:?} obligations={:?}",
normalized_value, obligations
);
+
+ let mut fulfill_cx = FulfillmentContext::new();
for obligation in obligations {
- fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
+ fulfill_cx.register_predicate_obligation(infcx, obligation);
}
debug!("fully_normalize: select_all_or_error start");
Ok(resolved_value)
}
+/// Process an obligation (and any nested obligations that come from it) to
+/// completion, returning any errors
+pub fn fully_solve_obligation<'a, 'tcx>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ obligation: PredicateObligation<'tcx>,
+) -> Vec<FulfillmentError<'tcx>> {
+ let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ engine.register_predicate_obligation(infcx, obligation);
+ engine.select_all_or_error(infcx)
+}
+
+/// Process a set of obligations (and any nested obligations that come from them)
+/// to completion
+pub fn fully_solve_obligations<'a, 'tcx>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
+) -> Vec<FulfillmentError<'tcx>> {
+ let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ engine.register_predicate_obligations(infcx, obligations);
+ engine.select_all_or_error(infcx)
+}
+
+/// Process a bound (and any nested obligations that come from it) to completion.
+/// This is a convenience function for traits that have no generic arguments, such
+/// as auto traits, and builtin traits like Copy or Sized.
+pub fn fully_solve_bound<'a, 'tcx>(
+ infcx: &InferCtxt<'a, 'tcx>,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+ bound: DefId,
+) -> Vec<FulfillmentError<'tcx>> {
+ let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+ engine.register_bound(infcx, param_env, ty, bound, cause);
+ engine.select_all_or_error(infcx)
+}
+
/// Normalizes the predicates and checks whether they hold in an empty environment. If this
/// returns true, then either normalize encountered an error or one of the predicates did not
/// hold. Used when creating vtables to check for unsatisfiable methods.
infcx.set_tainted_by_errors();
let param_env = ty::ParamEnv::reveal_all();
- let mut selcx = SelectionContext::new(&infcx);
- let mut fulfill_cx = FulfillmentContext::new();
- let cause = ObligationCause::dummy();
- let Normalized { value: predicates, obligations } =
- normalize(&mut selcx, param_env, cause.clone(), predicates);
- for obligation in obligations {
- fulfill_cx.register_predicate_obligation(&infcx, obligation);
- }
+ let ocx = ObligationCtxt::new(&infcx);
+ let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
for predicate in predicates {
- let obligation = Obligation::new(cause.clone(), param_env, predicate);
- fulfill_cx.register_predicate_obligation(&infcx, obligation);
+ let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
+ ocx.register_obligation(obligation);
}
-
- let errors = fulfill_cx.select_all_or_error(&infcx);
+ let errors = ocx.select_all_or_error();
// Clean up after ourselves
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
result
}
+/// Checks whether a trait's method is impossible to call on a given impl.
+///
+/// This only considers predicates that reference the impl's generics, and not
+/// those that reference the method's generics.
+fn is_impossible_method<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ (impl_def_id, trait_item_def_id): (DefId, DefId),
+) -> bool {
+ struct ReferencesOnlyParentGenerics<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ generics: &'tcx ty::Generics,
+ trait_item_def_id: DefId,
+ }
+ impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> {
+ type BreakTy = ();
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // If this is a parameter from the trait item's own generics, then bail
+ if let ty::Param(param) = t.kind()
+ && let param_def_id = self.generics.type_param(param, self.tcx).def_id
+ && self.tcx.parent(param_def_id) == self.trait_item_def_id
+ {
+ return ControlFlow::BREAK;
+ }
+ t.super_visit_with(self)
+ }
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::ReEarlyBound(param) = r.kind()
+ && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id
+ && self.tcx.parent(param_def_id) == self.trait_item_def_id
+ {
+ return ControlFlow::BREAK;
+ }
+ r.super_visit_with(self)
+ }
+ fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if let ty::ConstKind::Param(param) = ct.kind()
+ && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id
+ && self.tcx.parent(param_def_id) == self.trait_item_def_id
+ {
+ return ControlFlow::BREAK;
+ }
+ ct.super_visit_with(self)
+ }
+ }
+
+ let generics = tcx.generics_of(trait_item_def_id);
+ let predicates = tcx.predicates_of(trait_item_def_id);
+ let impl_trait_ref =
+ tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
+ let param_env = tcx.param_env(impl_def_id);
+
+ let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
+ let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| {
+ if pred.visit_with(&mut visitor).is_continue() {
+ Some(Obligation::new(
+ ObligationCause::dummy_with_span(*span),
+ param_env,
+ ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
+ ))
+ } else {
+ None
+ }
+ });
+
+ tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
+ let mut fulfill_ctxt = <dyn TraitEngine<'_>>::new(tcx);
+ fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait);
+ !fulfill_ctxt.select_all_or_error(infcx).is_empty()
+ })
+}
+
#[derive(Clone, Debug)]
enum VtblSegment<'tcx> {
MetadataDSA,
vtable_entries,
vtable_trait_upcasting_coercion_new_vptr_slot,
subst_and_check_impossible_predicates,
+ is_impossible_method,
try_unify_abstract_consts: |tcx, param_env_and| {
let (param_env, (a, b)) = param_env_and.into_parts();
const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)
// U: Trait<Arg1, ..., ArgN>
let trait_predicate = {
let substs =
- InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| {
+ InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| {
if param.index == 0 {
unsized_self_ty.into()
} else {
match token {
Piece::String(_) => (), // Normal string, no need to check it
Piece::NextArgument(a) => match a.position {
- Position::ArgumentNamed(s, _) => {
+ Position::ArgumentNamed(s) => {
match Symbol::intern(s) {
// `{Self}` is allowed
kw::SelfUpper => (),
.map(|p| match p {
Piece::String(s) => s,
Piece::NextArgument(a) => match a.position {
- Position::ArgumentNamed(s, _) => {
+ Position::ArgumentNamed(s) => {
let s = Symbol::intern(s);
match generic_map.get(&s) {
Some(val) => val,
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
-use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::sym;
use std::collections::BTreeMap;
constant.eval(self.selcx.tcx(), self.param_env)
}
}
+
+ #[inline]
+ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+ p.super_fold_with(self)
+ } else {
+ p
+ }
+ }
}
pub struct BoundVarReplacer<'me, 'tcx> {
}
ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
let universe = self.universe_for(debruijn);
- let p = ty::PlaceholderConst {
- universe,
- name: ty::BoundConst { var: bound_const, ty: ct.ty() },
- };
+ let p = ty::PlaceholderConst { universe, name: bound_const };
self.mapped_consts.insert(p, bound_const);
self.infcx
.tcx
return Progress { term: tcx.ty_error().into(), obligations: nested };
};
- if !assoc_ty.item.defaultness.has_value() {
+ if !assoc_ty.item.defaultness(tcx).has_value() {
// This means that the impl is missing a definition for the
// associated type. This error will be reported by the type
// checker method `check_impl_items_against_trait`, so here we
let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
let substs =
translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
- let ty = tcx.type_of(assoc_ty.item.def_id);
+ let ty = tcx.bound_type_of(assoc_ty.item.def_id);
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
- let term: ty::Term<'tcx> = if is_const {
+ let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
let identity_substs =
crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
let kind = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
- tcx.mk_const(ty::ConstS { ty, kind }).into()
+ ty.map_bound(|ty| tcx.mk_const(ty::ConstS { ty, kind }).into())
} else {
- ty.into()
+ ty.map_bound(|ty| ty.into())
};
if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
let err = tcx.ty_error_with_message(
Progress { term: err.into(), obligations: nested }
} else {
assoc_ty_own_obligations(selcx, obligation, &mut nested);
- Progress { term: EarlyBinder(term).subst(tcx, substs), obligations: nested }
+ Progress { term: term.subst(tcx, substs), obligations: nested }
}
}
return Ok(specialization_graph::LeafDef {
item: *item,
defining_node: impl_node,
- finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
+ finalizing_node: if item.defaultness(tcx).is_default() {
+ None
+ } else {
+ Some(impl_node)
+ },
});
}
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
- Ok(result.normalized_ty)
+
+ let res = result.normalized_ty;
+ // `tcx.normalize_projection_ty` may normalize to a type that still has
+ // unevaluated consts, so keep normalizing here if that's the case.
+ if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
+ Ok(res.try_super_fold_with(self)?)
+ } else {
+ Ok(res)
+ }
}
ty::Projection(data) => {
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
- Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+
+ let res = crate::traits::project::PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result.normalized_ty,
- ))
+ );
+ // `tcx.normalize_projection_ty` may normalize to a type that still has
+ // unevaluated consts, so keep normalizing here if that's the case.
+ if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
+ Ok(res.try_super_fold_with(self)?)
+ } else {
+ Ok(res)
+ }
}
_ => ty.try_super_fold_with(self),
})()?;
+
self.cache.insert(ty, res);
Ok(res)
}
mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?,
})
}
+
+ #[inline]
+ fn try_fold_predicate(
+ &mut self,
+ p: ty::Predicate<'tcx>,
+ ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+ if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+ p.try_super_fold_with(self)
+ } else {
+ Ok(p)
+ }
+ }
}
use crate::infer::canonical::query_response;
use crate::infer::{InferCtxt, InferOk};
-use crate::traits::engine::TraitEngineExt as _;
+use crate::traits;
use crate::traits::query::type_op::TypeOpOutput;
use crate::traits::query::Fallible;
-use crate::traits::TraitEngine;
use rustc_infer::infer::region_constraints::RegionConstraintData;
-use rustc_infer::traits::TraitEngineExt as _;
use rustc_span::source_map::DUMMY_SP;
use std::fmt;
infcx: &InferCtxt<'_, 'tcx>,
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
// During NLL, we expect that nobody will register region
// obligations **except** as part of a custom type op (and, at the
// end of each custom type op, we scrape out the region
);
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
- fulfill_cx.register_predicate_obligations(infcx, obligations);
- let errors = fulfill_cx.select_all_or_error(infcx);
+ let errors = traits::fully_solve_obligations(infcx, obligations);
if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
use hir::LangItem;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::ObligationCause;
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;
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
} else if lang_items.destruct_trait() == Some(def_id) {
self.assemble_const_destruct_candidates(obligation, &mut candidates);
+ } else if lang_items.transmute_trait() == Some(def_id) {
+ // User-defined transmutability impls are permitted.
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+ self.assemble_candidates_for_transmutability(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
fn need_migrate_deref_output_trait_object(
&mut self,
ty: Ty<'tcx>,
- cause: &traits::ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
+ cause: &ObligationCause<'tcx>,
) -> Option<(Ty<'tcx>, DefId)> {
let tcx = self.tcx();
if tcx.features().trait_upcasting {
return None;
}
- let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
- let normalized_ty = fulfillcx.normalize_projection_type(
- &self.infcx,
+ let ty = traits::normalize_projection_type(
+ self,
param_env,
ty::ProjectionTy {
item_def_id: tcx.lang_items().deref_target()?,
substs: trait_ref.substs,
},
cause.clone(),
- );
-
- let ty::Dynamic(data, ..) = normalized_ty.kind() else {
- return None;
- };
-
- let def_id = data.principal_def_id()?;
-
- return Some((normalized_ty, def_id));
+ 0,
+ // We're *intentionally* throwing these away,
+ // since we don't actually use them.
+ &mut vec![],
+ )
+ .ty()
+ .unwrap();
+
+ if let ty::Dynamic(data, ..) = ty.kind() {
+ Some((ty, data.principal_def_id()?))
+ } else {
+ None
+ }
}
/// Searches for unsizing that might apply to `obligation`.
if let Some((deref_output_ty, deref_output_trait_did)) = self
.need_migrate_deref_output_trait_object(
source,
- &obligation.cause,
obligation.param_env,
+ &obligation.cause,
)
{
if deref_output_trait_did == target_trait_did {
};
}
+ #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+ fn assemble_candidates_for_transmutability(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ candidates: &mut SelectionCandidateSet<'tcx>,
+ ) {
+ if obligation.has_param_types_or_consts() {
+ return;
+ }
+
+ if obligation.has_infer_types_or_consts() {
+ candidates.ambiguous = true;
+ return;
+ }
+
+ candidates.vec.push(TransmutabilityCandidate);
+ }
+
#[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
fn assemble_candidates_for_trait_alias(
&mut self,
ImplSource::Builtin(data)
}
+ TransmutabilityCandidate => {
+ let data = self.confirm_transmutability_candidate(obligation)?;
+ ImplSource::Builtin(data)
+ }
+
ParamCandidate(param) => {
let obligations =
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
obligation: &TraitObligation<'tcx>,
idx: usize,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
- self.infcx.commit_unconditionally(|_| {
- let tcx = self.tcx();
-
- let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
- let placeholder_trait_predicate =
- self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
- 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),
- _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
- };
+ let tcx = self.tcx();
- let candidate_predicate =
- tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
- let candidate = candidate_predicate
- .to_opt_poly_trait_pred()
- .expect("projection candidate is not a trait predicate")
- .map_bound(|t| t.trait_ref);
- let mut obligations = Vec::new();
- let candidate = normalize_with_depth_to(
- self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- candidate,
- &mut obligations,
- );
+ let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
+ let placeholder_trait_predicate =
+ self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
+ 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),
+ _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
+ };
- obligations.extend(self.infcx.commit_if_ok(|_| {
- self.infcx
- .at(&obligation.cause, obligation.param_env)
- .sup(placeholder_trait_predicate, candidate)
- .map(|InferOk { obligations, .. }| obligations)
- .map_err(|_| Unimplemented)
- })?);
-
- if let ty::Projection(..) = placeholder_self_ty.kind() {
- let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
- debug!(?predicates, "projection predicates");
- for predicate in predicates {
- let normalized = normalize_with_depth_to(
- self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- predicate,
- &mut obligations,
- );
- obligations.push(Obligation::with_depth(
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- obligation.param_env,
- normalized,
- ));
- }
+ let candidate_predicate =
+ tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
+ let candidate = candidate_predicate
+ .to_opt_poly_trait_pred()
+ .expect("projection candidate is not a trait predicate")
+ .map_bound(|t| t.trait_ref);
+ let mut obligations = Vec::new();
+ let candidate = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ candidate,
+ &mut obligations,
+ );
+
+ obligations.extend(self.infcx.commit_if_ok(|_| {
+ self.infcx
+ .at(&obligation.cause, obligation.param_env)
+ .sup(placeholder_trait_predicate, candidate)
+ .map(|InferOk { obligations, .. }| obligations)
+ .map_err(|_| Unimplemented)
+ })?);
+
+ if let ty::Projection(..) = placeholder_self_ty.kind() {
+ let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
+ debug!(?predicates, "projection predicates");
+ for predicate in predicates {
+ let normalized = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ predicate,
+ &mut obligations,
+ );
+ obligations.push(Obligation::with_depth(
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ normalized,
+ ));
}
+ }
- Ok(obligations)
- })
+ Ok(obligations)
}
fn confirm_param_candidate(
ImplSourceBuiltinData { nested: obligations }
}
+ fn confirm_transmutability_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+ debug!(?obligation, "confirm_transmutability_candidate");
+
+ let predicate = obligation.predicate;
+
+ let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
+ let bool_at = |i| {
+ predicate
+ .skip_binder()
+ .trait_ref
+ .substs
+ .const_at(i)
+ .try_eval_bool(self.tcx(), obligation.param_env)
+ .unwrap_or(true)
+ };
+
+ let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
+ src: p.trait_ref.substs.type_at(1),
+ dst: p.trait_ref.substs.type_at(0),
+ });
+
+ let scope = type_at(2).skip_binder();
+
+ let assume = rustc_transmute::Assume {
+ alignment: bool_at(3),
+ lifetimes: bool_at(4),
+ validity: bool_at(5),
+ visibility: bool_at(6),
+ };
+
+ let cause = obligation.cause.clone();
+
+ let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
+
+ let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);
+
+ use rustc_transmute::Answer;
+
+ match maybe_transmutable {
+ Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
+ _ => Err(Unimplemented),
+ }
+ }
+
/// This handles the case where an `auto trait Foo` impl is being used.
/// The idea is that the impl applies to `X : Foo` if the following conditions are met:
///
ensure_sufficient_stack(|| {
let cause = obligation.derived_cause(BuiltinDerivedObligation);
- let trait_obligations: Vec<PredicateObligation<'_>> =
- self.infcx.commit_unconditionally(|_| {
- let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
- let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
- self.impl_or_trait_obligations(
- &cause,
- obligation.recursion_depth + 1,
- obligation.param_env,
- trait_def_id,
- &trait_ref.substs,
- obligation.predicate,
- )
- });
+ let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
+ let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
+ let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations(
+ &cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ trait_def_id,
+ &trait_ref.substs,
+ obligation.predicate,
+ );
let mut obligations = self.collect_predicates_for_types(
obligation.param_env,
// First, create the substitutions by matching the impl again,
// this time not in a probe.
- self.infcx.commit_unconditionally(|_| {
- let substs = self.rematch_impl(impl_def_id, obligation);
- debug!(?substs, "impl substs");
- ensure_sufficient_stack(|| {
- self.vtable_impl(
- impl_def_id,
- substs,
- &obligation.cause,
- obligation.recursion_depth + 1,
- obligation.param_env,
- obligation.predicate,
- )
- })
+ let substs = self.rematch_impl(impl_def_id, obligation);
+ debug!(?substs, "impl substs");
+ ensure_sufficient_stack(|| {
+ self.vtable_impl(
+ impl_def_id,
+ substs,
+ &obligation.cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ obligation.predicate,
+ )
})
}
) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> {
debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate");
- self.infcx.commit_unconditionally(|_| {
- let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
- let trait_ref = predicate.trait_ref;
- let trait_def_id = trait_ref.def_id;
- let substs = trait_ref.substs;
+ let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
+ let trait_ref = predicate.trait_ref;
+ let trait_def_id = trait_ref.def_id;
+ let substs = trait_ref.substs;
- let trait_obligations = self.impl_or_trait_obligations(
- &obligation.cause,
- obligation.recursion_depth,
- obligation.param_env,
- trait_def_id,
- &substs,
- obligation.predicate,
- );
+ let trait_obligations = self.impl_or_trait_obligations(
+ &obligation.cause,
+ obligation.recursion_depth,
+ obligation.param_env,
+ trait_def_id,
+ &substs,
+ obligation.predicate,
+ );
- debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
+ debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
- ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }
- })
+ ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }
}
fn confirm_generator_candidate(
// Normalize the obligation and expected trait refs together, because why not
let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
ensure_sufficient_stack(|| {
- self.infcx.commit_unconditionally(|_| {
- normalize_with_depth(
- self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- (obligation_trait_ref, expected_trait_ref),
- )
- })
+ normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ (obligation_trait_ref, expected_trait_ref),
+ )
});
self.infcx
// first check it like a regular impl candidate.
// This is copied from confirm_impl_candidate but remaps the predicate to `~const Drop` beforehand.
if let Some(impl_def_id) = impl_def_id {
- let obligations = self.infcx.commit_unconditionally(|_| {
- let mut new_obligation = obligation.clone();
- new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| {
- trait_pred.trait_ref.def_id = drop_trait;
- trait_pred
- });
- let substs = self.rematch_impl(impl_def_id, &new_obligation);
- debug!(?substs, "impl substs");
-
- let cause = obligation.derived_cause(|derived| {
- ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
- derived,
- impl_def_id,
- span: obligation.cause.span,
- }))
- });
- ensure_sufficient_stack(|| {
- self.vtable_impl(
- impl_def_id,
- substs,
- &cause,
- new_obligation.recursion_depth + 1,
- new_obligation.param_env,
- obligation.predicate,
- )
- })
+ let mut new_obligation = obligation.clone();
+ new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| {
+ trait_pred.trait_ref.def_id = drop_trait;
+ trait_pred
+ });
+ let substs = self.rematch_impl(impl_def_id, &new_obligation);
+ debug!(?substs, "impl substs");
+
+ let cause = obligation.derived_cause(|derived| {
+ ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+ derived,
+ impl_def_id,
+ span: obligation.cause.span,
+ }))
+ });
+ let obligations = ensure_sufficient_stack(|| {
+ self.vtable_impl(
+ impl_def_id,
+ substs,
+ &cause,
+ new_obligation.recursion_depth + 1,
+ new_obligation.param_env,
+ obligation.predicate,
+ )
});
nested.extend(obligations.nested);
}
// If we have a projection type, make sure to normalize it so we replace it
// with a fresh infer variable
ty::Projection(..) => {
- self.infcx.commit_unconditionally(|_| {
- let predicate = normalize_with_depth_to(
- self,
- obligation.param_env,
- cause.clone(),
- obligation.recursion_depth + 1,
- self_ty
- .rebind(ty::TraitPredicate {
- trait_ref: ty::TraitRef {
- def_id: self
- .tcx()
- .require_lang_item(LangItem::Destruct, None),
- substs: self.tcx().mk_substs_trait(nested_ty, &[]),
- },
- constness: ty::BoundConstness::ConstIfConst,
- polarity: ty::ImplPolarity::Positive,
- })
- .to_predicate(tcx),
- &mut nested,
- );
-
- nested.push(Obligation::with_depth(
- cause.clone(),
- obligation.recursion_depth + 1,
- obligation.param_env,
- predicate,
- ));
- });
+ let predicate = normalize_with_depth_to(
+ self,
+ obligation.param_env,
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ self_ty
+ .rebind(ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: self.tcx().require_lang_item(LangItem::Destruct, None),
+ substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+ },
+ constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
+ })
+ .to_predicate(tcx),
+ &mut nested,
+ );
+
+ nested.push(Obligation::with_depth(
+ cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ predicate,
+ ));
}
// If we have any other type (e.g. an ADT), just register a nested obligation
);
}
+ // FIXME(@jswrenn): this should probably be more sophisticated
+ (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
+
// (*)
(
BuiltinCandidate { has_nested: false }
let sized_crit = def.sized_constraint(self.tcx());
// (*) binder moved here
Where(obligation.predicate.rebind({
- sized_crit.iter().map(|ty| EarlyBinder(*ty).subst(self.tcx(), substs)).collect()
+ sized_crit
+ .0
+ .iter()
+ .map(|ty| sized_crit.rebind(*ty).subst(self.tcx(), substs))
+ .collect()
}))
}
.flat_map(|ty| {
let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/
- self.infcx.commit_unconditionally(|_| {
- let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
- let Normalized { value: normalized_ty, mut obligations } =
- ensure_sufficient_stack(|| {
- project::normalize_with_depth(
- self,
- param_env,
- cause.clone(),
- recursion_depth,
- placeholder_ty,
- )
- });
- let placeholder_obligation = predicate_for_trait_def(
- self.tcx(),
- param_env,
- cause.clone(),
- trait_def_id,
- recursion_depth,
- normalized_ty,
- &[],
- );
- obligations.push(placeholder_obligation);
- obligations
- })
+ let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
+ let Normalized { value: normalized_ty, mut obligations } =
+ ensure_sufficient_stack(|| {
+ project::normalize_with_depth(
+ self,
+ param_env,
+ cause.clone(),
+ recursion_depth,
+ placeholder_ty,
+ )
+ });
+ let placeholder_obligation = predicate_for_trait_def(
+ self.tcx(),
+ param_env,
+ cause.clone(),
+ trait_def_id,
+ recursion_depth,
+ normalized_ty,
+ &[],
+ );
+ obligations.push(placeholder_obligation);
+ obligations
})
.collect()
}
// obligation will normalize to `<$0 as Iterator>::Item = $1` and
// `$1: Copy`, so we must ensure the obligations are emitted in
// that order.
- let predicates = tcx.predicates_of(def_id);
+ let predicates = tcx.bound_predicates_of(def_id);
debug!(?predicates);
- assert_eq!(predicates.parent, None);
- let mut obligations = Vec::with_capacity(predicates.predicates.len());
- for (predicate, span) in predicates.predicates {
+ assert_eq!(predicates.0.parent, None);
+ let mut obligations = Vec::with_capacity(predicates.0.predicates.len());
+ for (predicate, span) in predicates.0.predicates {
let span = *span;
let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
param_env,
cause.clone(),
recursion_depth,
- EarlyBinder(*predicate).subst(tcx, substs),
+ predicates.rebind(*predicate).subst(tcx, substs),
&mut obligations,
);
obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
+use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_span::{Span, DUMMY_SP};
use super::util;
-use super::{FulfillmentContext, SelectionContext};
+use super::SelectionContext;
/// Information pertinent to an overlapping impl error.
#[derive(Debug)]
// Create an infcx, taking the predicates of impl1 as assumptions:
tcx.infer_ctxt().enter(|infcx| {
- // Normalize the trait reference. The WF rules ought to ensure
- // that this always succeeds.
let impl1_trait_ref = match traits::fully_normalize(
&infcx,
- FulfillmentContext::new(),
ObligationCause::dummy(),
penv,
impl1_trait_ref,
) {
Ok(impl1_trait_ref) => impl1_trait_ref,
- Err(err) => {
- bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
+ Err(_errors) => {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(impl1_def_id),
+ format!("failed to fully normalize {impl1_trait_ref}"),
+ );
+ impl1_trait_ref
}
};
// (which are packed up in penv)
infcx.save_and_restore_in_snapshot_flag(|infcx| {
- let mut fulfill_cx = FulfillmentContext::new();
- for oblig in obligations.chain(more_obligations) {
- fulfill_cx.register_predicate_obligation(&infcx, oblig);
- }
- match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
+ match &errors[..] {
[] => {
debug!(
"fulfill_implication: an impl for {:?} specializes {:?}",
use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::ObligationCause;
-use crate::traits::{self, TraitEngine};
+use crate::traits::{TraitEngine, TraitEngineExt};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
adt_ty: Ty<'tcx>,
cause: ObligationCause<'tcx>,
) -> bool {
- let mut fulfillment_cx = traits::FulfillmentContext::new();
+ let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
// require `#[derive(PartialEq)]`
let structural_peq_def_id =
infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
-use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable};
use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
pub use rustc_infer::traits::{self, util::*};
impl_def_id: DefId,
impl_substs: SubstsRef<'tcx>,
) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
- let subject = selcx.tcx().impl_subject(impl_def_id);
- let subject = EarlyBinder(subject).subst(selcx.tcx(), impl_substs);
+ let subject = selcx.tcx().bound_impl_subject(impl_def_id);
+ let subject = subject.subst(selcx.tcx(), impl_substs);
let Normalized { value: subject, obligations: normalization_obligations1 } =
super::normalize(selcx, param_env, ObligationCause::dummy(), subject);
}
pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
- assoc_item.defaultness.is_final() && tcx.impl_defaultness(assoc_item.container.id()).is_final()
+ assoc_item.defaultness(tcx).is_final()
+ && tcx.impl_defaultness(assoc_item.container_id(tcx)).is_final()
}
pub enum TupleArgumentsFlag {
use rustc_middle::traits::ChalkRustInterner as RustInterner;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{
- self, AssocItemContainer, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
-};
+use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
use rustc_ast::ast;
use rustc_attr as attr;
where
ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>,
{
- self.interner
- .tcx
- .explicit_item_bounds(def_id)
+ let bounds = self.interner.tcx.bound_explicit_item_bounds(def_id);
+ bounds
+ .0
.iter()
- .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars))
+ .map(|(bound, _)| bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars))
.filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, self.interner))
.collect()
}
) -> Arc<chalk_solve::rust_ir::AssociatedTyDatum<RustInterner<'tcx>>> {
let def_id = assoc_type_id.0;
let assoc_item = self.interner.tcx.associated_item(def_id);
- let AssocItemContainer::TraitContainer(trait_def_id) = assoc_item.container else {
+ let Some(trait_def_id) = assoc_item.trait_container(self.interner.tcx) else {
unimplemented!("Not possible??");
};
match assoc_item.kind {
let where_clauses = self.where_clauses_for(def_id, bound_vars);
- let sig = self.interner.tcx.fn_sig(def_id);
+ let sig = self.interner.tcx.bound_fn_sig(def_id);
let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars(
self.interner,
self.interner.tcx,
- EarlyBinder(sig.inputs_and_output()).subst(self.interner.tcx, bound_vars),
+ sig.map_bound(|s| s.inputs_and_output()).subst(self.interner.tcx, bound_vars),
);
let argument_types = inputs_and_output[..inputs_and_output.len() - 1]
.iter()
- .map(|t| {
- EarlyBinder(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner)
- })
+ .map(|t| sig.rebind(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner))
.collect();
- let return_type = EarlyBinder(inputs_and_output[inputs_and_output.len() - 1])
+ let return_type = sig
+ .rebind(inputs_and_output[inputs_and_output.len() - 1])
.subst(self.interner.tcx, &bound_vars)
.lower_into(self.interner);
};
Arc::new(chalk_solve::rust_ir::FnDefDatum {
id: fn_def_id,
- sig: sig.lower_into(self.interner),
+ sig: sig.0.lower_into(self.interner),
binders: chalk_ir::Binders::new(binders, bound),
})
}
) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
let def_id = associated_ty_id.0;
let assoc_item = self.interner.tcx.associated_item(def_id);
- let impl_id = assoc_item.container.id();
+ let impl_id = assoc_item.container_id(self.interner.tcx);
match assoc_item.kind {
AssocKind::Type => {}
_ => unimplemented!("Not possible??"),
let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0);
+ let explicit_item_bounds = self.interner.tcx.bound_explicit_item_bounds(opaque_ty_id.0);
let bounds =
- self.interner
- .tcx
- .explicit_item_bounds(opaque_ty_id.0)
+ explicit_item_bounds
+ .0
.iter()
- .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars))
+ .map(|(bound, _)| {
+ explicit_item_bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars)
+ })
.map(|bound| {
bound.fold_with(&mut ReplaceOpaqueTyFolder {
tcx: self.interner.tcx,
chalk_ir::UniverseIndex { counter: ui.index() },
),
CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
- CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
+ CanonicalVarKind::PlaceholderConst(_pc, _ty) => unimplemented!(),
}),
),
value: obligation.value.lower_into(interner),
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
use rustc_trait_selection::traits::wf;
-use rustc_trait_selection::traits::FulfillmentContext;
-use rustc_trait_selection::traits::TraitEngine;
+use rustc_trait_selection::traits::{TraitEngine, TraitEngineExt};
use smallvec::{smallvec, SmallVec};
pub(crate) fn provide(p: &mut Providers) {
let mut implied_bounds = vec![];
- let mut fulfill_cx = FulfillmentContext::new();
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
while let Some(arg) = wf_args.pop() {
if !checked_wf_args.insert(arg) {
--- /dev/null
+[package]
+name = "rustc_transmute"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+tracing = "0.1"
+rustc_data_structures = { path = "../rustc_data_structures", optional = true}
+rustc_infer = { path = "../rustc_infer", optional = true}
+rustc_macros = { path = "../rustc_macros", optional = true}
+rustc_middle = { path = "../rustc_middle", optional = true}
+rustc_span = { path = "../rustc_span", optional = true}
+rustc_target = { path = "../rustc_target", optional = true}
+
+[features]
+rustc = [
+ "rustc_middle",
+ "rustc_data_structures",
+ "rustc_infer",
+ "rustc_macros",
+ "rustc_span",
+ "rustc_target",
+]
+
+[dev-dependencies]
+itertools = "0.10.1"
\ No newline at end of file
--- /dev/null
+use super::{nfa, Byte, Nfa, Ref};
+use crate::Map;
+use std::fmt;
+use std::sync::atomic::{AtomicU32, Ordering};
+
+#[derive(PartialEq, Clone, Debug)]
+pub(crate) struct Dfa<R>
+where
+ R: Ref,
+{
+ pub(crate) transitions: Map<State, Transitions<R>>,
+ pub(crate) start: State,
+ pub(crate) accepting: State,
+}
+
+#[derive(PartialEq, Clone, Debug)]
+pub(crate) struct Transitions<R>
+where
+ R: Ref,
+{
+ byte_transitions: Map<Byte, State>,
+ ref_transitions: Map<R, State>,
+}
+
+impl<R> Default for Transitions<R>
+where
+ R: Ref,
+{
+ fn default() -> Self {
+ Self { byte_transitions: Map::default(), ref_transitions: Map::default() }
+ }
+}
+
+impl<R> Transitions<R>
+where
+ R: Ref,
+{
+ fn insert(&mut self, transition: Transition<R>, state: State) {
+ match transition {
+ Transition::Byte(b) => {
+ self.byte_transitions.insert(b, state);
+ }
+ Transition::Ref(r) => {
+ self.ref_transitions.insert(r, state);
+ }
+ }
+ }
+}
+
+/// The states in a `Nfa` represent byte offsets.
+#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
+pub(crate) struct State(u32);
+
+#[derive(Hash, Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Transition<R>
+where
+ R: Ref,
+{
+ Byte(Byte),
+ Ref(R),
+}
+
+impl fmt::Debug for State {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "S_{}", self.0)
+ }
+}
+
+impl<R> fmt::Debug for Transition<R>
+where
+ R: Ref,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match &self {
+ Self::Byte(b) => b.fmt(f),
+ Self::Ref(r) => r.fmt(f),
+ }
+ }
+}
+
+impl<R> Dfa<R>
+where
+ R: Ref,
+{
+ pub(crate) fn unit() -> Self {
+ let transitions: Map<State, Transitions<R>> = Map::default();
+ let start = State::new();
+ let accepting = start;
+
+ Self { transitions, start, accepting }
+ }
+
+ #[cfg(test)]
+ pub(crate) fn bool() -> Self {
+ let mut transitions: Map<State, Transitions<R>> = Map::default();
+ let start = State::new();
+ let accepting = State::new();
+
+ transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x00)), accepting);
+
+ transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x01)), accepting);
+
+ Self { transitions, start, accepting }
+ }
+
+ #[instrument(level = "debug")]
+ #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+ pub(crate) fn from_nfa(nfa: Nfa<R>) -> Self {
+ let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa;
+
+ let mut dfa_transitions: Map<State, Transitions<R>> = Map::default();
+ let mut nfa_to_dfa: Map<nfa::State, State> = Map::default();
+ let dfa_start = State::new();
+ nfa_to_dfa.insert(nfa_start, dfa_start);
+
+ let mut queue = vec![(nfa_start, dfa_start)];
+
+ while let Some((nfa_state, dfa_state)) = queue.pop() {
+ if nfa_state == nfa_accepting {
+ continue;
+ }
+
+ for (nfa_transition, next_nfa_states) in nfa_transitions[&nfa_state].iter() {
+ let dfa_transitions =
+ dfa_transitions.entry(dfa_state).or_insert_with(Default::default);
+
+ let mapped_state = next_nfa_states.iter().find_map(|x| nfa_to_dfa.get(x).copied());
+
+ let next_dfa_state = match nfa_transition {
+ &nfa::Transition::Byte(b) => *dfa_transitions
+ .byte_transitions
+ .entry(b)
+ .or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
+ &nfa::Transition::Ref(r) => *dfa_transitions
+ .ref_transitions
+ .entry(r)
+ .or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
+ };
+
+ for &next_nfa_state in next_nfa_states {
+ nfa_to_dfa.entry(next_nfa_state).or_insert_with(|| {
+ queue.push((next_nfa_state, next_dfa_state));
+ next_dfa_state
+ });
+ }
+ }
+ }
+
+ let dfa_accepting = nfa_to_dfa[&nfa_accepting];
+
+ Self { transitions: dfa_transitions, start: dfa_start, accepting: dfa_accepting }
+ }
+
+ pub(crate) fn bytes_from(&self, start: State) -> Option<&Map<Byte, State>> {
+ Some(&self.transitions.get(&start)?.byte_transitions)
+ }
+
+ pub(crate) fn byte_from(&self, start: State, byte: Byte) -> Option<State> {
+ self.transitions.get(&start)?.byte_transitions.get(&byte).copied()
+ }
+
+ pub(crate) fn refs_from(&self, start: State) -> Option<&Map<R, State>> {
+ Some(&self.transitions.get(&start)?.ref_transitions)
+ }
+}
+
+impl State {
+ pub(crate) fn new() -> Self {
+ static COUNTER: AtomicU32 = AtomicU32::new(0);
+ Self(COUNTER.fetch_add(1, Ordering::SeqCst))
+ }
+}
+
+impl<R> From<nfa::Transition<R>> for Transition<R>
+where
+ R: Ref,
+{
+ fn from(nfa_transition: nfa::Transition<R>) -> Self {
+ match nfa_transition {
+ nfa::Transition::Byte(byte) => Transition::Byte(byte),
+ nfa::Transition::Ref(r) => Transition::Ref(r),
+ }
+ }
+}
--- /dev/null
+use std::fmt::{self, Debug};
+use std::hash::Hash;
+
+pub(crate) mod tree;
+pub(crate) use tree::Tree;
+
+pub(crate) mod nfa;
+pub(crate) use nfa::Nfa;
+
+pub(crate) mod dfa;
+pub(crate) use dfa::Dfa;
+
+#[derive(Debug)]
+pub(crate) struct Uninhabited;
+
+/// An instance of a byte is either initialized to a particular value, or uninitialized.
+#[derive(Hash, Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Byte {
+ Uninit,
+ Init(u8),
+}
+
+impl fmt::Debug for Byte {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match &self {
+ Self::Uninit => f.write_str("??u8"),
+ Self::Init(b) => write!(f, "{:#04x}u8", b),
+ }
+ }
+}
+
+pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {}
+pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {}
+
+impl Def for ! {}
+impl Ref for ! {}
+
+#[cfg(feature = "rustc")]
+pub(crate) mod rustc {
+ use rustc_middle::mir::Mutability;
+ use rustc_middle::ty;
+ use rustc_middle::ty::Region;
+ use rustc_middle::ty::Ty;
+
+ /// A reference in the layout.
+ #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
+ pub struct Ref<'tcx> {
+ lifetime: Region<'tcx>,
+ ty: Ty<'tcx>,
+ mutability: Mutability,
+ }
+
+ impl<'tcx> super::Ref for Ref<'tcx> {}
+
+ impl<'tcx> Ref<'tcx> {
+ pub fn min_align(&self) -> usize {
+ todo!()
+ }
+ }
+
+ /// A visibility node in the layout.
+ #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+ pub enum Def<'tcx> {
+ Adt(ty::AdtDef<'tcx>),
+ Variant(&'tcx ty::VariantDef),
+ Field(&'tcx ty::FieldDef),
+ Primitive,
+ }
+
+ impl<'tcx> super::Def for Def<'tcx> {}
+}
--- /dev/null
+use super::{Byte, Ref, Tree, Uninhabited};
+use crate::{Map, Set};
+use std::fmt;
+use std::sync::atomic::{AtomicU32, Ordering};
+
+/// A non-deterministic finite automaton (NFA) that represents the layout of a type.
+/// The transmutability of two given types is computed by comparing their `Nfa`s.
+#[derive(PartialEq, Debug)]
+pub(crate) struct Nfa<R>
+where
+ R: Ref,
+{
+ pub(crate) transitions: Map<State, Map<Transition<R>, Set<State>>>,
+ pub(crate) start: State,
+ pub(crate) accepting: State,
+}
+
+/// The states in a `Nfa` represent byte offsets.
+#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
+pub(crate) struct State(u32);
+
+/// The transitions between states in a `Nfa` reflect bit validity.
+#[derive(Hash, Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Transition<R>
+where
+ R: Ref,
+{
+ Byte(Byte),
+ Ref(R),
+}
+
+impl fmt::Debug for State {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "S_{}", self.0)
+ }
+}
+
+impl<R> fmt::Debug for Transition<R>
+where
+ R: Ref,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match &self {
+ Self::Byte(b) => b.fmt(f),
+ Self::Ref(r) => r.fmt(f),
+ }
+ }
+}
+
+impl<R> Nfa<R>
+where
+ R: Ref,
+{
+ pub(crate) fn unit() -> Self {
+ let transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
+ let start = State::new();
+ let accepting = start;
+
+ Nfa { transitions, start, accepting }
+ }
+
+ pub(crate) fn from_byte(byte: Byte) -> Self {
+ let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
+ let start = State::new();
+ let accepting = State::new();
+
+ let source = transitions.entry(start).or_default();
+ let edge = source.entry(Transition::Byte(byte)).or_default();
+ edge.insert(accepting);
+
+ Nfa { transitions, start, accepting }
+ }
+
+ pub(crate) fn from_ref(r: R) -> Self {
+ let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
+ let start = State::new();
+ let accepting = State::new();
+
+ let source = transitions.entry(start).or_default();
+ let edge = source.entry(Transition::Ref(r)).or_default();
+ edge.insert(accepting);
+
+ Nfa { transitions, start, accepting }
+ }
+
+ pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
+ Ok(match tree {
+ Tree::Byte(b) => Self::from_byte(b),
+ Tree::Def(..) => unreachable!(),
+ Tree::Ref(r) => Self::from_ref(r),
+ Tree::Alt(alts) => {
+ let mut alts = alts.into_iter().map(Self::from_tree);
+ let mut nfa = alts.next().ok_or(Uninhabited)??;
+ for alt in alts {
+ nfa = nfa.union(alt?);
+ }
+ nfa
+ }
+ Tree::Seq(elts) => {
+ let mut nfa = Self::unit();
+ for elt in elts.into_iter().map(Self::from_tree) {
+ nfa = nfa.concat(elt?);
+ }
+ nfa
+ }
+ })
+ }
+
+ /// Concatenate two `Nfa`s.
+ pub(crate) fn concat(self, other: Self) -> Self {
+ if self.start == self.accepting {
+ return other;
+ } else if other.start == other.accepting {
+ return self;
+ }
+
+ let start = self.start;
+ let accepting = other.accepting;
+
+ let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions;
+
+ // the iteration order doesn't matter
+ #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+ for (source, transition) in other.transitions {
+ let fix_state = |state| if state == other.start { self.accepting } else { state };
+ let entry = transitions.entry(fix_state(source)).or_default();
+ for (edge, destinations) in transition {
+ let entry = entry.entry(edge.clone()).or_default();
+ for destination in destinations {
+ entry.insert(fix_state(destination));
+ }
+ }
+ }
+
+ Self { transitions, start, accepting }
+ }
+
+ /// Compute the union of two `Nfa`s.
+ pub(crate) fn union(self, other: Self) -> Self {
+ let start = self.start;
+ let accepting = self.accepting;
+
+ let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions.clone();
+
+ // the iteration order doesn't matter
+ #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+ for (&(mut source), transition) in other.transitions.iter() {
+ // if source is starting state of `other`, replace with starting state of `self`
+ if source == other.start {
+ source = self.start;
+ }
+ let entry = transitions.entry(source).or_default();
+ for (edge, destinations) in transition {
+ let entry = entry.entry(edge.clone()).or_default();
+ // the iteration order doesn't matter
+ #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+ for &(mut destination) in destinations {
+ // if dest is accepting state of `other`, replace with accepting state of `self`
+ if destination == other.accepting {
+ destination = self.accepting;
+ }
+ entry.insert(destination);
+ }
+ }
+ }
+ Self { transitions, start, accepting }
+ }
+
+ pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> {
+ self.transitions.get(&start)
+ }
+}
+
+impl State {
+ pub(crate) fn new() -> Self {
+ static COUNTER: AtomicU32 = AtomicU32::new(0);
+ Self(COUNTER.fetch_add(1, Ordering::SeqCst))
+ }
+}
--- /dev/null
+use super::{Byte, Def, Ref};
+
+#[cfg(test)]
+mod tests;
+
+/// A tree-based representation of a type layout.
+///
+/// Invariants:
+/// 1. All paths through the layout have the same length (in bytes).
+///
+/// Nice-to-haves:
+/// 1. An `Alt` is never directly nested beneath another `Alt`.
+/// 2. A `Seq` is never directly nested beneath another `Seq`.
+/// 3. `Seq`s and `Alt`s with a single member do not exist.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub(crate) enum Tree<D, R>
+where
+ D: Def,
+ R: Ref,
+{
+ /// A sequence of successive layouts.
+ Seq(Vec<Self>),
+ /// A choice between alternative layouts.
+ Alt(Vec<Self>),
+ /// A definition node.
+ Def(D),
+ /// A reference node.
+ Ref(R),
+ /// A byte node.
+ Byte(Byte),
+}
+
+impl<D, R> Tree<D, R>
+where
+ D: Def,
+ R: Ref,
+{
+ /// A `Tree` consisting only of a definition node.
+ pub(crate) fn def(def: D) -> Self {
+ Self::Def(def)
+ }
+
+ /// A `Tree` representing an uninhabited type.
+ pub(crate) fn uninhabited() -> Self {
+ Self::Alt(vec![])
+ }
+
+ /// A `Tree` representing a zero-sized type.
+ pub(crate) fn unit() -> Self {
+ Self::Seq(Vec::new())
+ }
+
+ /// A `Tree` containing a single, uninitialized byte.
+ pub(crate) fn uninit() -> Self {
+ Self::Byte(Byte::Uninit)
+ }
+
+ /// A `Tree` representing the layout of `bool`.
+ pub(crate) fn bool() -> Self {
+ Self::from_bits(0x00).or(Self::from_bits(0x01))
+ }
+
+ /// A `Tree` whose layout matches that of a `u8`.
+ pub(crate) fn u8() -> Self {
+ Self::Alt((0u8..=255).map(Self::from_bits).collect())
+ }
+
+ /// A `Tree` whose layout accepts exactly the given bit pattern.
+ pub(crate) fn from_bits(bits: u8) -> Self {
+ Self::Byte(Byte::Init(bits))
+ }
+
+ /// A `Tree` whose layout is a number of the given width.
+ pub(crate) fn number(width_in_bytes: usize) -> Self {
+ Self::Seq(vec![Self::u8(); width_in_bytes])
+ }
+
+ /// A `Tree` whose layout is entirely padding of the given width.
+ pub(crate) fn padding(width_in_bytes: usize) -> Self {
+ Self::Seq(vec![Self::uninit(); width_in_bytes])
+ }
+
+ /// Remove all `Def` nodes, and all branches of the layout for which `f` produces false.
+ pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R>
+ where
+ F: Fn(D) -> bool,
+ {
+ match self {
+ Self::Seq(elts) => elts
+ .into_iter()
+ .map(|elt| elt.prune(f))
+ .try_fold(Tree::unit(), |elts, elt| {
+ if elt == Tree::uninhabited() {
+ Err(Tree::uninhabited())
+ } else {
+ Ok(elts.then(elt))
+ }
+ })
+ .into_ok_or_err(),
+ Self::Alt(alts) => alts
+ .into_iter()
+ .map(|alt| alt.prune(f))
+ .fold(Tree::uninhabited(), |alts, alt| alts.or(alt)),
+ Self::Byte(b) => Tree::Byte(b),
+ Self::Ref(r) => Tree::Ref(r),
+ Self::Def(d) => {
+ if !f(d) {
+ Tree::uninhabited()
+ } else {
+ Tree::unit()
+ }
+ }
+ }
+ }
+
+ /// Produces `true` if `Tree` is an inhabited type; otherwise false.
+ pub(crate) fn is_inhabited(&self) -> bool {
+ match self {
+ Self::Seq(elts) => elts.into_iter().all(|elt| elt.is_inhabited()),
+ Self::Alt(alts) => alts.into_iter().any(|alt| alt.is_inhabited()),
+ Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true,
+ }
+ }
+}
+
+impl<D, R> Tree<D, R>
+where
+ D: Def,
+ R: Ref,
+{
+ /// Produces a new `Tree` where `other` is sequenced after `self`.
+ pub(crate) fn then(self, other: Self) -> Self {
+ match (self, other) {
+ (Self::Seq(elts), other) | (other, Self::Seq(elts)) if elts.len() == 0 => other,
+ (Self::Seq(mut lhs), Self::Seq(mut rhs)) => {
+ lhs.append(&mut rhs);
+ Self::Seq(lhs)
+ }
+ (Self::Seq(mut lhs), rhs) => {
+ lhs.push(rhs);
+ Self::Seq(lhs)
+ }
+ (lhs, Self::Seq(mut rhs)) => {
+ rhs.insert(0, lhs);
+ Self::Seq(rhs)
+ }
+ (lhs, rhs) => Self::Seq(vec![lhs, rhs]),
+ }
+ }
+
+ /// Produces a new `Tree` accepting either `self` or `other` as alternative layouts.
+ pub(crate) fn or(self, other: Self) -> Self {
+ match (self, other) {
+ (Self::Alt(alts), other) | (other, Self::Alt(alts)) if alts.len() == 0 => other,
+ (Self::Alt(mut lhs), Self::Alt(rhs)) => {
+ lhs.extend(rhs);
+ Self::Alt(lhs)
+ }
+ (Self::Alt(mut alts), alt) | (alt, Self::Alt(mut alts)) => {
+ alts.push(alt);
+ Self::Alt(alts)
+ }
+ (lhs, rhs) => Self::Alt(vec![lhs, rhs]),
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum Err {
+ /// The layout of the type is unspecified.
+ Unspecified,
+ /// This error will be surfaced elsewhere by rustc, so don't surface it.
+ Unknown,
+}
+
+#[cfg(feature = "rustc")]
+pub(crate) mod rustc {
+ use super::{Err, Tree};
+ use crate::layout::rustc::{Def, Ref};
+
+ use rustc_middle::ty;
+ use rustc_middle::ty::layout::LayoutError;
+ use rustc_middle::ty::util::Discr;
+ use rustc_middle::ty::AdtDef;
+ use rustc_middle::ty::ParamEnv;
+ use rustc_middle::ty::SubstsRef;
+ use rustc_middle::ty::Ty;
+ use rustc_middle::ty::TyCtxt;
+ use rustc_middle::ty::VariantDef;
+ use rustc_target::abi::Align;
+ use std::alloc;
+
+ impl<'tcx> From<LayoutError<'tcx>> for Err {
+ fn from(err: LayoutError<'tcx>) -> Self {
+ match err {
+ LayoutError::Unknown(..) => Self::Unknown,
+ err @ _ => unimplemented!("{:?}", err),
+ }
+ }
+ }
+
+ trait LayoutExt {
+ fn clamp_align(&self, min_align: Align, max_align: Align) -> Self;
+ }
+
+ impl LayoutExt for alloc::Layout {
+ fn clamp_align(&self, min_align: Align, max_align: Align) -> Self {
+ let min_align = min_align.bytes().try_into().unwrap();
+ let max_align = max_align.bytes().try_into().unwrap();
+ Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap()
+ }
+ }
+
+ struct LayoutSummary {
+ total_align: Align,
+ total_size: usize,
+ discriminant_size: usize,
+ discriminant_align: Align,
+ }
+
+ impl LayoutSummary {
+ fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, LayoutError<'tcx>> {
+ use rustc_middle::ty::ParamEnvAnd;
+ use rustc_target::abi::{TyAndLayout, Variants};
+
+ let param_env = ParamEnv::reveal_all();
+ let param_env_and_type = ParamEnvAnd { param_env, value: ty };
+ let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
+
+ let total_size: usize = layout.size().bytes_usize();
+ let total_align: Align = layout.align().abi;
+ let discriminant_align: Align;
+ let discriminant_size: usize;
+
+ if let Variants::Multiple { tag, .. } = layout.variants() {
+ discriminant_align = tag.align(&ctx).abi;
+ discriminant_size = tag.size(&ctx).bytes_usize();
+ } else {
+ discriminant_align = Align::ONE;
+ discriminant_size = 0;
+ };
+
+ Ok(Self { total_align, total_size, discriminant_align, discriminant_size })
+ }
+
+ fn into(&self) -> alloc::Layout {
+ alloc::Layout::from_size_align(
+ self.total_size,
+ self.total_align.bytes().try_into().unwrap(),
+ )
+ .unwrap()
+ }
+ }
+
+ impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
+ pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result<Self, Err> {
+ use rustc_middle::ty::FloatTy::*;
+ use rustc_middle::ty::IntTy::*;
+ use rustc_middle::ty::UintTy::*;
+ use rustc_target::abi::HasDataLayout;
+
+ let target = tcx.data_layout();
+
+ match ty.kind() {
+ ty::Bool => Ok(Self::bool()),
+
+ ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()),
+ ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)),
+ ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)),
+ ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)),
+ ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)),
+ ty::Int(Isize) | ty::Uint(Usize) => {
+ Ok(Self::number(target.pointer_size.bytes_usize()))
+ }
+
+ ty::Tuple(members) => {
+ if members.len() == 0 {
+ Ok(Tree::unit())
+ } else {
+ Err(Err::Unspecified)
+ }
+ }
+
+ ty::Array(ty, len) => {
+ let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap();
+ let elt = Tree::from_ty(*ty, tcx)?;
+ Ok(std::iter::repeat(elt)
+ .take(len as usize)
+ .fold(Tree::unit(), |tree, elt| tree.then(elt)))
+ }
+
+ ty::Adt(adt_def, substs_ref) => {
+ use rustc_middle::ty::AdtKind;
+
+ // If the layout is ill-specified, halt.
+ if !(adt_def.repr().c() || adt_def.repr().int.is_some()) {
+ return Err(Err::Unspecified);
+ }
+
+ // Compute a summary of the type's layout.
+ let layout_summary = LayoutSummary::from_ty(ty, tcx)?;
+
+ // The layout begins with this adt's visibility.
+ let vis = Self::def(Def::Adt(*adt_def));
+
+ // And is followed the layout(s) of its variants
+ Ok(vis.then(match adt_def.adt_kind() {
+ AdtKind::Struct => Self::from_repr_c_variant(
+ ty,
+ *adt_def,
+ substs_ref,
+ &layout_summary,
+ None,
+ adt_def.non_enum_variant(),
+ tcx,
+ )?,
+ AdtKind::Enum => {
+ tracing::trace!(?adt_def, "treeifying enum");
+ let mut tree = Tree::uninhabited();
+
+ for (idx, discr) in adt_def.discriminants(tcx) {
+ tree = tree.or(Self::from_repr_c_variant(
+ ty,
+ *adt_def,
+ substs_ref,
+ &layout_summary,
+ Some(discr),
+ adt_def.variant(idx),
+ tcx,
+ )?);
+ }
+
+ tree
+ }
+ AdtKind::Union => {
+ // is the layout well-defined?
+ if !adt_def.repr().c() {
+ return Err(Err::Unspecified);
+ }
+
+ let ty_layout = layout_of(tcx, ty)?;
+
+ let mut tree = Tree::uninhabited();
+
+ for field in adt_def.all_fields() {
+ let variant_ty = field.ty(tcx, substs_ref);
+ let variant_layout = layout_of(tcx, variant_ty)?;
+ let padding_needed = ty_layout.size() - variant_layout.size();
+ let variant = Self::def(Def::Field(field))
+ .then(Self::from_ty(variant_ty, tcx)?)
+ .then(Self::padding(padding_needed));
+
+ tree = tree.or(variant);
+ }
+
+ tree
+ }
+ }))
+ }
+ _ => Err(Err::Unspecified),
+ }
+ }
+
+ fn from_repr_c_variant(
+ ty: Ty<'tcx>,
+ adt_def: AdtDef<'tcx>,
+ substs_ref: SubstsRef<'tcx>,
+ layout_summary: &LayoutSummary,
+ discr: Option<Discr<'tcx>>,
+ variant_def: &'tcx VariantDef,
+ tcx: TyCtxt<'tcx>,
+ ) -> Result<Self, Err> {
+ let mut tree = Tree::unit();
+
+ let repr = adt_def.repr();
+ let min_align = repr.align.unwrap_or(Align::ONE);
+ let max_align = repr.pack.unwrap_or(Align::MAX);
+
+ let clamp =
+ |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap();
+
+ let variant_span = tracing::trace_span!(
+ "treeifying variant",
+ min_align = ?min_align,
+ max_align = ?max_align,
+ )
+ .entered();
+
+ let mut variant_layout = alloc::Layout::from_size_align(
+ 0,
+ layout_summary.total_align.bytes().try_into().unwrap(),
+ )
+ .unwrap();
+
+ // The layout of the variant is prefixed by the discriminant, if any.
+ if let Some(discr) = discr {
+ tracing::trace!(?discr, "treeifying discriminant");
+ let discr_layout = alloc::Layout::from_size_align(
+ layout_summary.discriminant_size,
+ clamp(layout_summary.discriminant_align),
+ )
+ .unwrap();
+ tracing::trace!(?discr_layout, "computed discriminant layout");
+ variant_layout = variant_layout.extend(discr_layout).unwrap().0;
+ tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size));
+ }
+
+ // Next come fields.
+ let fields_span = tracing::trace_span!("treeifying fields").entered();
+ for field_def in variant_def.fields.iter() {
+ let field_ty = field_def.ty(tcx, substs_ref);
+ let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered();
+
+ // begin with the field's visibility
+ tree = tree.then(Self::def(Def::Field(field_def)));
+
+ // compute the field's layout charactaristics
+ let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align);
+
+ // next comes the field's padding
+ let padding_needed = variant_layout.padding_needed_for(field_layout.align());
+ if padding_needed > 0 {
+ tree = tree.then(Self::padding(padding_needed));
+ }
+
+ // finally, the field's layout
+ tree = tree.then(Self::from_ty(field_ty, tcx)?);
+
+ // extend the variant layout with the field layout
+ variant_layout = variant_layout.extend(field_layout).unwrap().0;
+ }
+ drop(fields_span);
+
+ // finally: padding
+ let padding_span = tracing::trace_span!("adding trailing padding").entered();
+ let padding_needed = layout_summary.total_size - variant_layout.size();
+ if padding_needed > 0 {
+ tree = tree.then(Self::padding(padding_needed));
+ };
+ drop(padding_span);
+ drop(variant_span);
+ Ok(tree)
+ }
+
+ pub fn from_disr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self {
+ // FIXME(@jswrenn): I'm certain this is missing needed endian nuance.
+ let bytes = discr.val.to_ne_bytes();
+ let bytes = &bytes[..size];
+ Self::Seq(bytes.into_iter().copied().map(|b| Self::from_bits(b)).collect())
+ }
+ }
+
+ fn layout_of<'tcx>(
+ ctx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> Result<alloc::Layout, LayoutError<'tcx>> {
+ use rustc_middle::ty::ParamEnvAnd;
+ use rustc_target::abi::TyAndLayout;
+
+ let param_env = ParamEnv::reveal_all();
+ let param_env_and_type = ParamEnvAnd { param_env, value: ty };
+ let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
+ let layout = alloc::Layout::from_size_align(
+ layout.size().bytes_usize(),
+ layout.align().abi.bytes().try_into().unwrap(),
+ )
+ .unwrap();
+ tracing::trace!(?ty, ?layout, "computed layout for type");
+ Ok(layout)
+ }
+}
--- /dev/null
+use super::Tree;
+
+#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+pub enum Def {
+ Visible,
+ Invisible,
+}
+
+impl super::Def for Def {}
+
+mod prune {
+ use super::*;
+
+ mod should_simplify {
+ use super::*;
+
+ #[test]
+ fn seq_1() {
+ let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::from_bits(0x00));
+ assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
+ }
+
+ #[test]
+ fn seq_2() {
+ let layout: Tree<Def, !> =
+ Tree::from_bits(0x00).then(Tree::def(Def::Visible)).then(Tree::from_bits(0x01));
+
+ assert_eq!(
+ layout.prune(&|d| matches!(d, Def::Visible)),
+ Tree::from_bits(0x00).then(Tree::from_bits(0x01))
+ );
+ }
+ }
+
+ mod should_reject {
+ use super::*;
+
+ #[test]
+ fn invisible_def() {
+ let layout: Tree<Def, !> = Tree::def(Def::Invisible);
+ assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
+ }
+
+ #[test]
+ fn invisible_def_in_seq_len_2() {
+ let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Invisible));
+ assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
+ }
+
+ #[test]
+ fn invisible_def_in_seq_len_3() {
+ let layout: Tree<Def, !> =
+ Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Invisible));
+ assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
+ }
+ }
+
+ mod should_accept {
+ use super::*;
+
+ #[test]
+ fn visible_def() {
+ let layout: Tree<Def, !> = Tree::def(Def::Visible);
+ assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
+ }
+
+ #[test]
+ fn visible_def_in_seq_len_2() {
+ let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Visible));
+ assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
+ }
+
+ #[test]
+ fn visible_def_in_seq_len_3() {
+ let layout: Tree<Def, !> =
+ Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Visible));
+ assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
+ }
+ }
+}
--- /dev/null
+#![feature(
+ alloc_layout_extra,
+ control_flow_enum,
+ decl_macro,
+ iterator_try_reduce,
+ never_type,
+ result_into_ok_or_err
+)]
+#![allow(dead_code, unused_variables)]
+
+#[macro_use]
+extern crate tracing;
+
+#[cfg(feature = "rustc")]
+pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set};
+
+#[cfg(not(feature = "rustc"))]
+pub(crate) use std::collections::{HashMap as Map, HashSet as Set};
+
+pub(crate) mod layout;
+pub(crate) mod maybe_transmutable;
+
+#[derive(Default)]
+pub struct Assume {
+ pub alignment: bool,
+ pub lifetimes: bool,
+ pub validity: bool,
+ pub visibility: bool,
+}
+
+/// The type encodes answers to the question: "Are these types transmutable?"
+#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
+pub enum Answer<R>
+where
+ R: layout::Ref,
+{
+ /// `Src` is transmutable into `Dst`.
+ Yes,
+
+ /// `Src` is NOT transmutable into `Dst`.
+ No(Reason),
+
+ /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
+ IfTransmutable { src: R, dst: R },
+
+ /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
+ IfAll(Vec<Answer<R>>),
+
+ /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
+ IfAny(Vec<Answer<R>>),
+}
+
+/// Answers: Why wasn't the source type transmutable into the destination type?
+#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
+pub enum Reason {
+ /// The layout of the source type is unspecified.
+ SrcIsUnspecified,
+ /// The layout of the destination type is unspecified.
+ DstIsUnspecified,
+ /// The layout of the destination type is bit-incompatible with the source type.
+ DstIsBitIncompatible,
+ /// There aren't any public constructors for `Dst`.
+ DstIsPrivate,
+ /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
+ DstIsTooBig,
+}
+
+#[cfg(feature = "rustc")]
+mod rustc {
+ use rustc_infer::infer::InferCtxt;
+ use rustc_macros::{TypeFoldable, TypeVisitable};
+ use rustc_middle::traits::ObligationCause;
+ use rustc_middle::ty::Binder;
+ use rustc_middle::ty::Ty;
+
+ /// The source and destination types of a transmutation.
+ #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
+ pub struct Types<'tcx> {
+ /// The source type.
+ pub src: Ty<'tcx>,
+ /// The destination type.
+ pub dst: Ty<'tcx>,
+ }
+
+ pub struct TransmuteTypeEnv<'cx, 'tcx> {
+ infcx: &'cx InferCtxt<'cx, 'tcx>,
+ }
+
+ impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
+ pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> Self {
+ Self { infcx }
+ }
+
+ #[allow(unused)]
+ pub fn is_transmutable(
+ &mut self,
+ cause: ObligationCause<'tcx>,
+ src_and_dst: Binder<'tcx, Types<'tcx>>,
+ scope: Ty<'tcx>,
+ assume: crate::Assume,
+ ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
+ let src = src_and_dst.map_bound(|types| types.src).skip_binder();
+ let dst = src_and_dst.map_bound(|types| types.dst).skip_binder();
+ crate::maybe_transmutable::MaybeTransmutableQuery::new(
+ src,
+ dst,
+ scope,
+ assume,
+ self.infcx.tcx,
+ )
+ .answer()
+ }
+ }
+}
+
+#[cfg(feature = "rustc")]
+pub use rustc::*;
--- /dev/null
+use crate::Map;
+use crate::{Answer, Reason};
+
+#[cfg(test)]
+mod tests;
+
+mod query_context;
+use query_context::QueryContext;
+
+use crate::layout::{self, dfa, Byte, Dfa, Nfa, Tree, Uninhabited};
+pub(crate) struct MaybeTransmutableQuery<L, C>
+where
+ C: QueryContext,
+{
+ src: L,
+ dst: L,
+ scope: <C as QueryContext>::Scope,
+ assume: crate::Assume,
+ context: C,
+}
+
+impl<L, C> MaybeTransmutableQuery<L, C>
+where
+ C: QueryContext,
+{
+ pub(crate) fn new(
+ src: L,
+ dst: L,
+ scope: <C as QueryContext>::Scope,
+ assume: crate::Assume,
+ context: C,
+ ) -> Self {
+ Self { src, dst, scope, assume, context }
+ }
+
+ pub(crate) fn map_layouts<F, M>(
+ self,
+ f: F,
+ ) -> Result<MaybeTransmutableQuery<M, C>, Answer<<C as QueryContext>::Ref>>
+ where
+ F: FnOnce(
+ L,
+ L,
+ <C as QueryContext>::Scope,
+ &C,
+ ) -> Result<(M, M), Answer<<C as QueryContext>::Ref>>,
+ {
+ let Self { src, dst, scope, assume, context } = self;
+
+ let (src, dst) = f(src, dst, scope, &context)?;
+
+ Ok(MaybeTransmutableQuery { src, dst, scope, assume, context })
+ }
+}
+
+#[cfg(feature = "rustc")]
+mod rustc {
+ use super::*;
+ use crate::layout::tree::Err;
+
+ use rustc_middle::ty::Ty;
+ use rustc_middle::ty::TyCtxt;
+
+ impl<'tcx> MaybeTransmutableQuery<Ty<'tcx>, TyCtxt<'tcx>> {
+ /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s,
+ /// then computes an answer using those trees.
+ #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
+ pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
+ let query_or_answer = self.map_layouts(|src, dst, scope, &context| {
+ // Convert `src` and `dst` from their rustc representations, to `Tree`-based
+ // representations. If these conversions fail, conclude that the transmutation is
+ // unacceptable; the layouts of both the source and destination types must be
+ // well-defined.
+ let src = Tree::from_ty(src, context).map_err(|err| match err {
+ // Answer `Yes` here, because "Unknown Type" will already be reported by
+ // rustc. No need to spam the user with more errors.
+ Err::Unknown => Answer::Yes,
+ Err::Unspecified => Answer::No(Reason::SrcIsUnspecified),
+ })?;
+
+ let dst = Tree::from_ty(dst, context).map_err(|err| match err {
+ Err::Unknown => Answer::Yes,
+ Err::Unspecified => Answer::No(Reason::DstIsUnspecified),
+ })?;
+
+ Ok((src, dst))
+ });
+
+ match query_or_answer {
+ Ok(query) => query.answer(),
+ Err(answer) => answer,
+ }
+ }
+ }
+}
+
+impl<C> MaybeTransmutableQuery<Tree<<C as QueryContext>::Def, <C as QueryContext>::Ref>, C>
+where
+ C: QueryContext,
+{
+ /// Answers whether a `Tree` is transmutable into another `Tree`.
+ ///
+ /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`,
+ /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs.
+ #[inline(always)]
+ #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
+ pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+ let assume_visibility = self.assume.visibility;
+ let query_or_answer = self.map_layouts(|src, dst, scope, context| {
+ // Remove all `Def` nodes from `src`, without checking their visibility.
+ let src = src.prune(&|def| true);
+
+ tracing::trace!(?src, "pruned src");
+
+ // Remove all `Def` nodes from `dst`, additionally...
+ let dst = if assume_visibility {
+ // ...if visibility is assumed, don't check their visibility.
+ dst.prune(&|def| true)
+ } else {
+ // ...otherwise, prune away all unreachable paths through the `Dst` layout.
+ dst.prune(&|def| context.is_accessible_from(def, scope))
+ };
+
+ tracing::trace!(?dst, "pruned dst");
+
+ // Convert `src` from a tree-based representation to an NFA-based representation.
+ // If the conversion fails because `src` is uninhabited, conclude that the transmutation
+ // is acceptable, because instances of the `src` type do not exist.
+ let src = Nfa::from_tree(src).map_err(|Uninhabited| Answer::Yes)?;
+
+ // Convert `dst` from a tree-based representation to an NFA-based representation.
+ // If the conversion fails because `src` is uninhabited, conclude that the transmutation
+ // is unacceptable, because instances of the `dst` type do not exist.
+ let dst =
+ Nfa::from_tree(dst).map_err(|Uninhabited| Answer::No(Reason::DstIsPrivate))?;
+
+ Ok((src, dst))
+ });
+
+ match query_or_answer {
+ Ok(query) => query.answer(),
+ Err(answer) => answer,
+ }
+ }
+}
+
+impl<C> MaybeTransmutableQuery<Nfa<<C as QueryContext>::Ref>, C>
+where
+ C: QueryContext,
+{
+ /// Answers whether a `Nfa` is transmutable into another `Nfa`.
+ ///
+ /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
+ #[inline(always)]
+ #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
+ pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+ let query_or_answer = self
+ .map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst))));
+
+ match query_or_answer {
+ Ok(query) => query.answer(),
+ Err(answer) => answer,
+ }
+ }
+}
+
+impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Ref>, C>
+where
+ C: QueryContext,
+{
+ /// Answers whether a `Nfa` is transmutable into another `Nfa`.
+ ///
+ /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
+ pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+ MaybeTransmutableQuery {
+ src: &self.src,
+ dst: &self.dst,
+ scope: self.scope,
+ assume: self.assume,
+ context: self.context,
+ }
+ .answer()
+ }
+}
+
+impl<'l, C> MaybeTransmutableQuery<&'l Dfa<<C as QueryContext>::Ref>, C>
+where
+ C: QueryContext,
+{
+ pub(crate) fn answer(&mut self) -> Answer<<C as QueryContext>::Ref> {
+ self.answer_memo(&mut Map::default(), self.src.start, self.dst.start)
+ }
+
+ #[inline(always)]
+ #[instrument(level = "debug", skip(self))]
+ fn answer_memo(
+ &self,
+ cache: &mut Map<(dfa::State, dfa::State), Answer<<C as QueryContext>::Ref>>,
+ src_state: dfa::State,
+ dst_state: dfa::State,
+ ) -> Answer<<C as QueryContext>::Ref> {
+ if let Some(answer) = cache.get(&(src_state, dst_state)) {
+ answer.clone()
+ } else {
+ let answer = if dst_state == self.dst.accepting {
+ // truncation: `size_of(Src) >= size_of(Dst)`
+ Answer::Yes
+ } else if src_state == self.src.accepting {
+ // extension: `size_of(Src) >= size_of(Dst)`
+ if let Some(dst_state_prime) = self.dst.byte_from(dst_state, Byte::Uninit) {
+ self.answer_memo(cache, src_state, dst_state_prime)
+ } else {
+ Answer::No(Reason::DstIsTooBig)
+ }
+ } else {
+ let src_quantification = if self.assume.validity {
+ // if the compiler may assume that the programmer is doing additional validity checks,
+ // (e.g.: that `src != 3u8` when the destination type is `bool`)
+ // then there must exist at least one transition out of `src_state` such that the transmute is viable...
+ there_exists
+ } else {
+ // if the compiler cannot assume that the programmer is doing additional validity checks,
+ // then for all transitions out of `src_state`, such that the transmute is viable...
+ // then there must exist at least one transition out of `src_state` such that the transmute is viable...
+ for_all
+ };
+
+ src_quantification(
+ self.src.bytes_from(src_state).unwrap_or(&Map::default()),
+ |(&src_validity, &src_state_prime)| {
+ if let Some(dst_state_prime) = self.dst.byte_from(dst_state, src_validity) {
+ self.answer_memo(cache, src_state_prime, dst_state_prime)
+ } else if let Some(dst_state_prime) =
+ self.dst.byte_from(dst_state, Byte::Uninit)
+ {
+ self.answer_memo(cache, src_state_prime, dst_state_prime)
+ } else {
+ Answer::No(Reason::DstIsBitIncompatible)
+ }
+ },
+ )
+ };
+ cache.insert((src_state, dst_state), answer.clone());
+ answer
+ }
+ }
+}
+
+impl<R> Answer<R>
+where
+ R: layout::Ref,
+{
+ pub(crate) fn and(self, rhs: Self) -> Self {
+ match (self, rhs) {
+ (Self::No(reason), _) | (_, Self::No(reason)) => Self::No(reason),
+ (Self::Yes, Self::Yes) => Self::Yes,
+ (Self::IfAll(mut lhs), Self::IfAll(ref mut rhs)) => {
+ lhs.append(rhs);
+ Self::IfAll(lhs)
+ }
+ (constraint, Self::IfAll(mut constraints))
+ | (Self::IfAll(mut constraints), constraint) => {
+ constraints.push(constraint);
+ Self::IfAll(constraints)
+ }
+ (lhs, rhs) => Self::IfAll(vec![lhs, rhs]),
+ }
+ }
+
+ pub(crate) fn or(self, rhs: Self) -> Self {
+ match (self, rhs) {
+ (Self::Yes, _) | (_, Self::Yes) => Self::Yes,
+ (Self::No(lhr), Self::No(rhr)) => Self::No(lhr),
+ (Self::IfAny(mut lhs), Self::IfAny(ref mut rhs)) => {
+ lhs.append(rhs);
+ Self::IfAny(lhs)
+ }
+ (constraint, Self::IfAny(mut constraints))
+ | (Self::IfAny(mut constraints), constraint) => {
+ constraints.push(constraint);
+ Self::IfAny(constraints)
+ }
+ (lhs, rhs) => Self::IfAny(vec![lhs, rhs]),
+ }
+ }
+}
+
+pub fn for_all<R, I, F>(iter: I, f: F) -> Answer<R>
+where
+ R: layout::Ref,
+ I: IntoIterator,
+ F: FnMut(<I as IntoIterator>::Item) -> Answer<R>,
+{
+ use std::ops::ControlFlow::{Break, Continue};
+ let (Continue(result) | Break(result)) =
+ iter.into_iter().map(f).try_fold(Answer::Yes, |constraints, constraint| {
+ match constraint.and(constraints) {
+ Answer::No(reason) => Break(Answer::No(reason)),
+ maybe => Continue(maybe),
+ }
+ });
+ result
+}
+
+pub fn there_exists<R, I, F>(iter: I, f: F) -> Answer<R>
+where
+ R: layout::Ref,
+ I: IntoIterator,
+ F: FnMut(<I as IntoIterator>::Item) -> Answer<R>,
+{
+ use std::ops::ControlFlow::{Break, Continue};
+ let (Continue(result) | Break(result)) = iter.into_iter().map(f).try_fold(
+ Answer::No(Reason::DstIsBitIncompatible),
+ |constraints, constraint| match constraint.or(constraints) {
+ Answer::Yes => Break(Answer::Yes),
+ maybe => Continue(maybe),
+ },
+ );
+ result
+}
--- /dev/null
+use crate::layout;
+
+/// Context necessary to answer the question "Are these types transmutable?".
+pub(crate) trait QueryContext {
+ type Def: layout::Def;
+ type Ref: layout::Ref;
+ type Scope: Copy;
+
+ /// Is `def` accessible from the defining module of `scope`?
+ fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool;
+
+ fn min_align(&self, reference: Self::Ref) -> usize;
+}
+
+#[cfg(test)]
+pub(crate) mod test {
+ use super::QueryContext;
+
+ pub(crate) struct UltraMinimal;
+
+ #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+ pub(crate) enum Def {
+ Visible,
+ Invisible,
+ }
+
+ impl crate::layout::Def for Def {}
+
+ impl QueryContext for UltraMinimal {
+ type Def = Def;
+ type Ref = !;
+ type Scope = ();
+
+ fn is_accessible_from(&self, def: Def, scope: ()) -> bool {
+ matches!(Def::Visible, def)
+ }
+
+ fn min_align(&self, reference: !) -> usize {
+ unimplemented!()
+ }
+ }
+}
+
+#[cfg(feature = "rustc")]
+mod rustc {
+ use super::*;
+ use rustc_middle::ty::{Ty, TyCtxt};
+
+ impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
+ type Def = layout::rustc::Def<'tcx>;
+ type Ref = layout::rustc::Ref<'tcx>;
+
+ type Scope = Ty<'tcx>;
+
+ #[instrument(level = "debug", skip(self))]
+ fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool {
+ use layout::rustc::Def;
+ use rustc_middle::ty;
+
+ let parent = if let ty::Adt(adt_def, ..) = scope.kind() {
+ use rustc_middle::ty::DefIdTree;
+ let parent = self.parent(adt_def.did());
+ parent
+ } else {
+ // Is this always how we want to handle a non-ADT scope?
+ return false;
+ };
+
+ let def_id = match def {
+ Def::Adt(adt_def) => adt_def.did(),
+ Def::Variant(variant_def) => variant_def.def_id,
+ Def::Field(field_def) => field_def.did,
+ Def::Primitive => {
+ // primitives do not have a def_id, but they're always accessible
+ return true;
+ }
+ };
+
+ let ret = if self.visibility(def_id).is_accessible_from(parent, *self) {
+ true
+ } else {
+ false
+ };
+
+ tracing::trace!(?ret, "ret");
+ ret
+ }
+
+ fn min_align(&self, reference: Self::Ref) -> usize {
+ unimplemented!()
+ }
+ }
+}
--- /dev/null
+use super::query_context::test::{Def, UltraMinimal};
+use crate::maybe_transmutable::MaybeTransmutableQuery;
+use crate::{layout, Answer, Reason, Set};
+use itertools::Itertools;
+
+mod bool {
+ use super::*;
+
+ #[test]
+ fn should_permit_identity_transmutation_tree() {
+ println!("{:?}", layout::Tree::<!, !>::bool());
+ let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
+ layout::Tree::<Def, !>::bool(),
+ layout::Tree::<Def, !>::bool(),
+ (),
+ crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+ UltraMinimal,
+ )
+ .answer();
+ assert_eq!(answer, Answer::Yes);
+ }
+
+ #[test]
+ fn should_permit_identity_transmutation_dfa() {
+ let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
+ layout::Dfa::<!>::bool(),
+ layout::Dfa::<!>::bool(),
+ (),
+ crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+ UltraMinimal,
+ )
+ .answer();
+ assert_eq!(answer, Answer::Yes);
+ }
+
+ #[test]
+ fn should_permit_validity_expansion_and_reject_contraction() {
+ let un = layout::Tree::<Def, !>::uninhabited();
+ let b0 = layout::Tree::<Def, !>::from_bits(0);
+ let b1 = layout::Tree::<Def, !>::from_bits(1);
+ let b2 = layout::Tree::<Def, !>::from_bits(2);
+
+ let alts = [b0, b1, b2];
+
+ let into_layout = |alts: Vec<_>| {
+ alts.into_iter().fold(layout::Tree::<Def, !>::uninhabited(), layout::Tree::<Def, !>::or)
+ };
+
+ let into_set = |alts: Vec<_>| {
+ #[cfg(feature = "rustc")]
+ let mut set = Set::default();
+ #[cfg(not(feature = "rustc"))]
+ let mut set = Set::new();
+ set.extend(alts);
+ set
+ };
+
+ for src_alts in alts.clone().into_iter().powerset() {
+ let src_layout = into_layout(src_alts.clone());
+ let src_set = into_set(src_alts.clone());
+
+ for dst_alts in alts.clone().into_iter().powerset().filter(|alts| !alts.is_empty()) {
+ let dst_layout = into_layout(dst_alts.clone());
+ let dst_set = into_set(dst_alts.clone());
+
+ if src_set.is_subset(&dst_set) {
+ assert_eq!(
+ Answer::Yes,
+ MaybeTransmutableQuery::new(
+ src_layout.clone(),
+ dst_layout.clone(),
+ (),
+ crate::Assume { validity: false, ..crate::Assume::default() },
+ UltraMinimal,
+ )
+ .answer(),
+ "{:?} SHOULD be transmutable into {:?}",
+ src_layout,
+ dst_layout
+ );
+ } else if !src_set.is_disjoint(&dst_set) {
+ assert_eq!(
+ Answer::Yes,
+ MaybeTransmutableQuery::new(
+ src_layout.clone(),
+ dst_layout.clone(),
+ (),
+ crate::Assume { validity: true, ..crate::Assume::default() },
+ UltraMinimal,
+ )
+ .answer(),
+ "{:?} SHOULD be transmutable (assuming validity) into {:?}",
+ src_layout,
+ dst_layout
+ );
+ } else {
+ assert_eq!(
+ Answer::No(Reason::DstIsBitIncompatible),
+ MaybeTransmutableQuery::new(
+ src_layout.clone(),
+ dst_layout.clone(),
+ (),
+ crate::Assume { validity: false, ..crate::Assume::default() },
+ UltraMinimal,
+ )
+ .answer(),
+ "{:?} should NOT be transmutable into {:?}",
+ src_layout,
+ dst_layout
+ );
+ }
+ }
+ }
+ }
+}
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, TyCtxt};
pub fn provide(providers: &mut ty::query::Providers) {
associated_item_def_ids,
associated_items,
impl_item_implementor_ids,
- trait_of_item,
..*providers
};
}
.collect()
}
-/// If the given `DefId` describes an item belonging to a trait,
-/// returns the `DefId` of the trait that the trait item belongs to;
-/// otherwise, returns `None`.
-fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
- tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
- ty::TraitContainer(def_id) => Some(def_id),
- ty::ImplContainer(_) => None,
- })
-}
-
fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let parent_def_id = tcx.hir().get_parent_item(id);
if let Some(impl_item_ref) =
impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
{
- let assoc_item =
- associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
+ let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
debug_assert_eq!(assoc_item.def_id, def_id);
return assoc_item;
}
if let Some(trait_item_ref) =
trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
{
- let assoc_item =
- associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
+ let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
debug_assert_eq!(assoc_item.def_id, def_id);
return assoc_item;
}
)
}
-fn associated_item_from_trait_item_ref(
- tcx: TyCtxt<'_>,
- parent_def_id: LocalDefId,
- trait_item_ref: &hir::TraitItemRef,
-) -> ty::AssocItem {
+fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
let def_id = trait_item_ref.id.def_id;
let (kind, has_self) = match trait_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
ty::AssocItem {
name: trait_item_ref.ident.name,
kind,
- vis: tcx.visibility(def_id),
- defaultness: trait_item_ref.defaultness,
def_id: def_id.to_def_id(),
trait_item_def_id: Some(def_id.to_def_id()),
- container: ty::TraitContainer(parent_def_id.to_def_id()),
+ container: ty::TraitContainer,
fn_has_self_parameter: has_self,
}
}
-fn associated_item_from_impl_item_ref(
- tcx: TyCtxt<'_>,
- parent_def_id: LocalDefId,
- impl_item_ref: &hir::ImplItemRef,
-) -> ty::AssocItem {
+fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
let def_id = impl_item_ref.id.def_id;
let (kind, has_self) = match impl_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
ty::AssocItem {
name: impl_item_ref.ident.name,
kind,
- vis: tcx.visibility(def_id),
- defaultness: impl_item_ref.defaultness,
def_id: def_id.to_def_id(),
trait_item_def_id: impl_item_ref.trait_item_def_id,
- container: ty::ImplContainer(parent_def_id.to_def_id()),
+ container: ty::ImplContainer,
fn_has_self_parameter: has_self,
}
}
}
// If the item does not have a value, then we cannot return an instance.
- if !leaf_def.item.defaultness.has_value() {
+ if !leaf_def.item.defaultness(tcx).has_value() {
return Ok(None);
}
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{
- self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
-};
+use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
use rustc_trait_selection::traits;
fn sized_constraint_for_ty<'tcx>(
let adt_tys = adt.sized_constraint(tcx);
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
adt_tys
+ .0
.iter()
- .map(|ty| EarlyBinder(*ty).subst(tcx, substs))
+ .map(|ty| adt_tys.rebind(*ty).subst(tcx, substs))
.flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty))
.collect()
}
}
fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
- let item = tcx.hir().expect_item(def_id.expect_local());
- if let hir::ItemKind::Impl(impl_) = &item.kind {
- impl_.defaultness
- } else {
- bug!("`impl_defaultness` called on {:?}", item);
+ match tcx.hir().get_by_def_id(def_id.expect_local()) {
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.defaultness,
+ hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
+ | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness,
+ node => {
+ bug!("`impl_defaultness` called on {:?}", node);
+ }
}
}
rustc_lint = { path = "../rustc_lint" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_type_ir = { path = "../rustc_type_ir" }
+rustc_feature = { path = "../rustc_feature" }
trait_bound_spans.push(*span);
}
for assoc_item in items {
- let trait_def_id = assoc_item.container.id();
+ let trait_def_id = assoc_item.container_id(tcx);
names.push(format!(
"`{}` (from trait `{}`)",
assoc_item.name,
let mut dupes = false;
for item in assoc_items {
let prefix = if names[&item.name] > 1 {
- let trait_def_id = item.container.id();
+ let trait_def_id = item.container_id(tcx);
dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id))
} else {
let mut label = vec![];
for item in assoc_items {
let postfix = if names[&item.name] > 1 {
- let trait_def_id = item.container.id();
+ let trait_def_id = item.container_id(tcx);
format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
} else {
String::new()
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
- struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
+ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
+ MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
.or_else(|| find_item_of_kind(ty::AssocKind::Const))
.expect("missing associated type");
- if !assoc_item.vis.is_accessible_from(def_scope, tcx) {
+ if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
tcx.sess
.struct_span_err(
binding.span,
span: binding.span,
prev_span: *prev_span,
item_name: binding.item_name,
- def_path: tcx.def_path_str(assoc_item.container.id()),
+ def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
});
})
.or_insert(binding.span);
let ty = self.normalize_ty(span, ty);
let kind = DefKind::AssocTy;
- if !item.vis.is_accessible_from(def_scope, tcx) {
+ if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
let kind = kind.descr(item.def_id);
let msg = format!("{} `{}` is private", kind, assoc_ident);
tcx.sess
pub fn prohibit_generics<'a>(
&self,
segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
- extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
+ extend: impl Fn(&mut Diagnostic),
) -> bool {
let args = segments.clone().flat_map(|segment| segment.args().args);
}
/// Make sure that we are in the condition to suggest the blanket implementation.
- fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>(
- &self,
- self_ty: &hir::Ty<'_>,
- diag: &mut DiagnosticBuilder<'_, T>,
- ) {
+ fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
let tcx = self.tcx();
let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
if let hir::Node::Item(hir::Item {
sugg,
Applicability::MachineApplicable,
);
- self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag);
+ self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
diag.emit();
},
);
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
+use rustc_middle::ty::{self, ToPredicate, Ty};
use rustc_span::Span;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
all_arms_diverge &= self.diverges.get();
- let opt_suggest_box_span = self.opt_suggest_box_span(arm_ty, orig_expected);
+ let opt_suggest_box_span = prior_arm.and_then(|(_, prior_arm_ty, _)| {
+ self.opt_suggest_box_span(prior_arm_ty, arm_ty, orig_expected)
+ });
let (arm_block_id, arm_span) = if let hir::ExprKind::Block(blk, _) = arm.body.kind {
(Some(blk.hir_id), self.find_block_span(blk))
pub(crate) fn if_cause(
&self,
span: Span,
+ cond_span: Span,
then_expr: &'tcx hir::Expr<'tcx>,
else_expr: &'tcx hir::Expr<'tcx>,
then_ty: Ty<'tcx>,
// ```
if block.expr.is_none() && block.stmts.is_empty()
&& let Some(outer_span) = &mut outer_span
+ && let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span)
{
- *outer_span = self.tcx.sess.source_map().guess_head_span(*outer_span);
+ *outer_span = outer_span.with_hi(cond_span.hi())
}
(self.find_block_span(block), block.hir_id)
// provide a structured suggestion in that case.
pub(crate) fn opt_suggest_box_span(
&self,
- outer_ty: Ty<'tcx>,
+ first_ty: Ty<'tcx>,
+ second_ty: Ty<'tcx>,
orig_expected: Expectation<'tcx>,
) -> Option<Span> {
match orig_expected {
Expectation::ExpectHasType(expected)
if self.in_tail_expr
- && self.ret_coercion.as_ref()?.borrow().merged_ty().has_opaque_types()
- && self.can_coerce(outer_ty, expected) =>
+ && self.return_type_has_opaque
+ && self.can_coerce(first_ty, expected)
+ && self.can_coerce(second_ty, expected) =>
{
let obligations = self.fulfillment_cx.borrow().pending_obligations();
let mut suggest_box = !obligations.is_empty();
- for o in obligations {
- match o.predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(t) => {
- let pred =
- ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
- trait_ref: ty::TraitRef {
- def_id: t.def_id(),
- substs: self.tcx.mk_substs_trait(outer_ty, &[]),
+ 'outer: for o in obligations {
+ for outer_ty in &[first_ty, second_ty] {
+ match o.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(t) => {
+ let pred = ty::Binder::dummy(ty::PredicateKind::Trait(
+ ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: t.def_id(),
+ substs: self.tcx.mk_substs_trait(*outer_ty, &[]),
+ },
+ constness: t.constness,
+ polarity: t.polarity,
},
- constness: t.constness,
- polarity: t.polarity,
- }));
- let obl = Obligation::new(
- o.cause.clone(),
- self.param_env,
- pred.to_predicate(self.tcx),
- );
- suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
- if !suggest_box {
- // We've encountered some obligation that didn't hold, so the
- // return expression can't just be boxed. We don't need to
- // evaluate the rest of the obligations.
- break;
+ ));
+ let obl = Obligation::new(
+ o.cause.clone(),
+ self.param_env,
+ pred.to_predicate(self.tcx),
+ );
+ suggest_box &= self.predicate_must_hold_modulo_regions(&obl);
+ if !suggest_box {
+ // We've encountered some obligation that didn't hold, so the
+ // return expression can't just be boxed. We don't need to
+ // evaluate the rest of the obligations.
+ break 'outer;
+ }
}
+ _ => {}
}
- _ => {}
}
}
// If all the obligations hold (or there are no obligations) the tail expression
use crate::hir::def_id::DefId;
use crate::type_error_struct;
+use hir::def_id::LOCAL_CRATE;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::cast::{CastKind, CastTy};
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
use rustc_session::lint;
use rustc_session::Session;
use rustc_span::symbol::sym;
/// or "a length". If this argument is None, then the metadata is unknown, for example,
/// when we're typechecking a type parameter with a ?Sized bound.
IntToFatCast(Option<&'static str>),
+ ForeignNonExhaustiveAdt,
}
impl From<ErrorGuaranteed> for CastError {
}
err.emit();
}
+ CastError::ForeignNonExhaustiveAdt => {
+ make_invalid_casting_error(
+ fcx.tcx.sess,
+ self.span,
+ self.expr_ty,
+ self.cast_ty,
+ fcx,
+ )
+ .note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate")
+ .emit();
+ }
}
}
_ => return Err(CastError::NonScalar),
};
+ if let ty::Adt(adt_def, _) = *self.expr_ty.kind() {
+ if adt_def.did().krate != LOCAL_CRATE {
+ if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) {
+ return Err(CastError::ForeignNonExhaustiveAdt);
+ }
+ }
+ }
+
match (t_from, t_cast) {
// These types have invariants! can't cast into them.
(_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar),
use rustc_infer::traits::Obligation;
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::hir::nested_filter;
+use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_trait_selection::traits::{self, ObligationCtxt};
use rustc_ty_utils::representability::{self, Representability};
-use std::iter;
use std::ops::ControlFlow;
pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
let is_implemented = ancestors
.leaf_def(tcx, trait_item_id)
- .map_or(false, |node_item| node_item.item.defaultness.has_value());
+ .map_or(false, |node_item| node_item.item.defaultness(tcx).has_value());
if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
missing_items.push(tcx.associated_item(trait_item_id));
}
- if let Some(required_items) = &must_implement_one_of {
- // true if this item is specifically implemented in this impl
- let is_implemented_here = ancestors
- .leaf_def(tcx, trait_item_id)
- .map_or(false, |node_item| !node_item.defining_node.is_from_trait());
+ // true if this item is specifically implemented in this impl
+ let is_implemented_here = ancestors
+ .leaf_def(tcx, trait_item_id)
+ .map_or(false, |node_item| !node_item.defining_node.is_from_trait());
+
+ if !is_implemented_here {
+ match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
+ EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(
+ tcx,
+ full_impl_span,
+ trait_item_id,
+ feature,
+ reason,
+ issue,
+ ),
+ // Unmarked default bodies are considered stable (at least for now).
+ EvalResult::Allow | EvalResult::Unmarked => {}
+ }
+ }
+
+ if let Some(required_items) = &must_implement_one_of {
if is_implemented_here {
let trait_item = tcx.associated_item(trait_item_id);
if required_items.contains(&trait_item.ident(tcx)) {
}
}
- let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len());
- // This tracks the previous variant span (in the loop) incase we need it for diagnostics
- let mut prev_variant_span: Span = DUMMY_SP;
- for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) {
- // Check for duplicate discriminant values
- if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
- let variant_did = def.variant(VariantIdx::new(i)).def_id;
- let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local());
- let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
- let i_span = match variant_i.disr_expr {
- Some(ref expr) => tcx.hir().span(expr.hir_id),
- None => tcx.def_span(variant_did),
- };
- let span = match v.disr_expr {
- Some(ref expr) => tcx.hir().span(expr.hir_id),
- None => v.span,
- };
- let display_discr = format_discriminant_overflow(tcx, v, discr);
- let display_discr_i = format_discriminant_overflow(tcx, variant_i, disr_vals[i]);
- let no_disr = v.disr_expr.is_none();
- let mut err = struct_span_err!(
- tcx.sess,
- sp,
- E0081,
- "discriminant value `{}` assigned more than once",
- discr,
- );
-
- err.span_label(i_span, format!("first assignment of {display_discr_i}"));
- err.span_label(span, format!("second assignment of {display_discr}"));
-
- if no_disr {
- err.span_label(
- prev_variant_span,
- format!(
- "assigned discriminant for `{}` was incremented from this discriminant",
- v.ident
- ),
- );
- }
- err.emit();
- }
-
- disr_vals.push(discr);
- prev_variant_span = v.span;
- }
+ detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
check_representable(tcx, sp, def_id);
check_transparent(tcx, sp, def);
}
-/// In the case that a discriminant is both a duplicate and an overflowing literal,
-/// we insert both the assigned discriminant and the literal it overflowed from into the formatted
-/// output. Otherwise we format the discriminant normally.
-fn format_discriminant_overflow<'tcx>(
+/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
+fn detect_discriminant_duplicate<'tcx>(
tcx: TyCtxt<'tcx>,
- variant: &hir::Variant<'_>,
- dis: Discr<'tcx>,
-) -> String {
- if let Some(expr) = &variant.disr_expr {
- let body = &tcx.hir().body(expr.body).value;
- if let hir::ExprKind::Lit(lit) = &body.kind
- && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
- && dis.val != *lit_value
- {
- return format!("`{dis}` (overflowed from `{lit_value}`)");
+ mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
+ vs: &'tcx [hir::Variant<'tcx>],
+ self_span: Span,
+) {
+ // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
+ // Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
+ let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| {
+ let var = &vs[idx]; // HIR for the duplicate discriminant
+ let (span, display_discr) = match var.disr_expr {
+ Some(ref expr) => {
+ // In the case the discriminant is both a duplicate and overflowed, let the user know
+ if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
+ && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
+ && *lit_value != dis.val
+ {
+ (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
+ // Otherwise, format the value as-is
+ } else {
+ (tcx.hir().span(expr.hir_id), format!("`{dis}`"))
+ }
+ }
+ None => {
+ // At this point we know this discriminant is a duplicate, and was not explicitly
+ // assigned by the user. Here we iterate backwards to fetch the HIR for the last
+ // explictly assigned discriminant, and letting the user know that this was the
+ // increment startpoint, and how many steps from there leading to the duplicate
+ if let Some((n, hir::Variant { span, ident, .. })) =
+ vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
+ {
+ let ve_ident = var.ident;
+ let n = n + 1;
+ let sp = if n > 1 { "variants" } else { "variant" };
+
+ err.span_label(
+ *span,
+ format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
+ );
+ }
+
+ (vs[idx].span, format!("`{dis}`"))
+ }
+ };
+
+ err.span_label(span, format!("{display_discr} assigned here"));
+ };
+
+ // Here we loop through the discriminants, comparing each discriminant to another.
+ // When a duplicate is detected, we instatiate an error and point to both
+ // initial and duplicate value. The duplicate discriminant is then discarded by swapping
+ // it with the last element and decrementing the `vec.len` (which is why we have to evaluate
+ // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional
+ // style as we are mutating `discrs` on the fly).
+ let mut i = 0;
+ while i < discrs.len() {
+ let hir_var_i_idx = discrs[i].0.index();
+ let mut error: Option<DiagnosticBuilder<'_, _>> = None;
+
+ let mut o = i + 1;
+ while o < discrs.len() {
+ let hir_var_o_idx = discrs[o].0.index();
+
+ if discrs[i].1.val == discrs[o].1.val {
+ let err = error.get_or_insert_with(|| {
+ let mut ret = struct_span_err!(
+ tcx.sess,
+ self_span,
+ E0081,
+ "discriminant value `{}` assigned more than once",
+ discrs[i].1,
+ );
+
+ report(discrs[i].1, hir_var_i_idx, &mut ret);
+
+ ret
+ });
+
+ report(discrs[o].1, hir_var_o_idx, err);
+
+ // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
+ discrs[o] = *discrs.last().unwrap();
+ discrs.pop();
+ } else {
+ o += 1;
+ }
}
- }
- format!("`{dis}`")
+ if let Some(mut e) = error {
+ e.emit();
+ }
+
+ i += 1;
+ }
}
pub(super) fn check_type_params_are_used<'tcx>(
use crate::astconv::AstConv;
use crate::check::FnCtxt;
use rustc_errors::{
- struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::Expr;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
+struct CollectRetsVisitor<'tcx> {
+ ret_exprs: Vec<&'tcx hir::Expr<'tcx>>,
+}
+
+impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> {
+ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+ if let hir::ExprKind::Ret(_) = expr.kind {
+ self.ret_exprs.push(expr);
+ }
+ intravisit::walk_expr(self, expr);
+ }
+}
+
/// Coercing a mutable reference to an immutable works, while
/// coercing `&T` to `&mut T` should be forbidden.
fn coerce_mutbls<'tcx>(
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
{
- self.commit_unconditionally(|snapshot| {
+ self.commit_if_ok(|snapshot| {
let result = if let ty::FnPtr(fn_ty_b) = b.kind()
&& let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
(fn_ty_a.unsafety(), fn_ty_b.unsafety())
}
}
Err(coercion_error) => {
+ // Mark that we've failed to coerce the types here to suppress
+ // any superfluous errors we might encounter while trying to
+ // emit or provide suggestions on how to fix the initial error.
+ fcx.set_tainted_by_errors();
let (expected, found) = if label_expression_as_expected {
// In the case where this is a "forced unit", like
// `break`, we want to call the `()` "expected"
// type)
(self.final_ty.unwrap_or(self.expected_ty), expression_ty)
};
+ let (expected, found) = fcx.resolve_vars_if_possible((expected, found));
let mut err;
let mut unsized_return = false;
+ let mut visitor = CollectRetsVisitor { ret_exprs: vec![] };
match *cause.code() {
ObligationCauseCode::ReturnNoExpression => {
err = struct_span_err!(
if !fcx.tcx.features().unsized_locals {
unsized_return = self.is_return_ty_unsized(fcx, blk_id);
}
+ if let Some(expression) = expression
+ && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
+ intravisit::walk_block(& mut visitor, loop_blk);
+ }
}
ObligationCauseCode::ReturnValue(id) => {
err = self.report_return_mismatched_types(
);
}
+ if visitor.ret_exprs.len() > 0 && let Some(expr) = expression {
+ self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
+ }
err.emit_unless(unsized_return);
self.final_ty = Some(fcx.tcx.ty_error());
}
}
}
+ fn note_unreachable_loop_return(
+ &self,
+ err: &mut Diagnostic,
+ expr: &hir::Expr<'tcx>,
+ ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>,
+ ) {
+ let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;};
+ let mut span: MultiSpan = vec![loop_span].into();
+ span.push_span_label(loop_span, "this might have zero elements to iterate on");
+ for ret_expr in ret_exprs {
+ span.push_span_label(
+ ret_expr.span,
+ "if the loop doesn't execute, this value would never get returned",
+ );
+ }
+ err.span_note(
+ span,
+ "the function expects a value to always be returned, but loops might run zero times",
+ );
+ err.help(
+ "return a value for the case when the loop has zero elements to iterate on, or \
+ consider changing the return type to account for that possibility",
+ );
+ }
fn report_return_mismatched_types<'a>(
&self,
);
}
- if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
+ let ret_coercion_span = fcx.ret_coercion_span.get();
+
+ if let Some(sp) = ret_coercion_span
+ // If the closure has an explicit return type annotation, or if
+ // the closure's return type has been inferred from outside
+ // requirements (such as an Fn* trait bound), then a type error
+ // may occur at the first return expression we see in the closure
+ // (if it conflicts with the declared return type). Skip adding a
+ // note in this case, since it would be incorrect.
+ && !fcx.return_type_pre_known
+ {
+ err.span_note(
+ sp,
+ &format!(
+ "return type inferred to be `{}` here",
+ expected
+ ),
+ );
+ }
+
+ if let (Some(sp), Some(fn_output)) = (ret_coercion_span, fn_output) {
self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
}
+
err
}
// Create mapping from trait to placeholder.
let trait_to_placeholder_substs =
- impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
+ impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
let impl_m_generics = tcx.generics_of(impl_m.def_id);
let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+ // Next, add all inputs and output as well-formed tys. Importantly,
+ // we have to do this before normalization, since the normalized ty may
+ // not contain the input parameters. See issue #87748.
+ wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
- // Add the resulting inputs and output as well-formed.
+ // We also have to add the normalized trait signature
+ // as we don't normalize during implied bounds computation.
wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
let self_string = |method: &ty::AssocItem| {
let untransformed_self_ty = match method.container {
- ty::ImplContainer(_) => impl_trait_ref.self_ty(),
- ty::TraitContainer(_) => tcx.types.self_param,
+ ty::ImplContainer => impl_trait_ref.self_ty(),
+ ty::TraitContainer => tcx.types.self_param,
};
let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
let param_env = ty::ParamEnv::reveal_all();
) -> Result<(), ErrorGuaranteed> {
let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
let trait_to_impl_substs =
- impl_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+ impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
let impl_ty_generics = tcx.generics_of(impl_ty.def_id);
let trait_ty_generics = tcx.generics_of(trait_ty.def_id);
});
let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
let impl_ty_substs = tcx.intern_substs(&substs);
+ let container_id = impl_ty.container_id(tcx);
- let rebased_substs =
- impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+ let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
let impl_ty_value = tcx.type_of(impl_ty.def_id);
let param_env = tcx.param_env(impl_ty.def_id);
debug!(?normalize_param_env);
let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
- let rebased_substs =
- impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+ let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
tcx.infer_ctxt().enter(move |infcx| {
let ocx = ObligationCtxt::new(&infcx);
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
let implied_bounds = match impl_ty.container {
- ty::TraitContainer(_) => FxHashSet::default(),
- ty::ImplContainer(def_id) => {
- wfcheck::impl_implied_bounds(tcx, param_env, def_id.expect_local(), impl_ty_span)
- }
+ ty::TraitContainer => FxHashSet::default(),
+ ty::ImplContainer => wfcheck::impl_implied_bounds(
+ tcx,
+ param_env,
+ container_id.expect_local(),
+ impl_ty_span,
+ ),
};
let mut outlives_environment = OutlivesEnvironment::new(param_env);
outlives_environment.add_implied_bounds(&infcx, implied_bounds, impl_ty_hir_id);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
- self.report_closure_inferred_return_type(err, expected);
}
// Requires that the two types unify, and prints an error message if
};
let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]);
- let self_ty = format!("{:?}", self_ty);
let name = method_path.ident.name;
- let is_as_ref_able = (self_ty.starts_with("&std::option::Option")
- || self_ty.starts_with("&std::result::Result")
- || self_ty.starts_with("std::option::Option")
- || self_ty.starts_with("std::result::Result"))
- && (name == sym::map || name == sym::and_then);
+ let is_as_ref_able = match self_ty.peel_refs().kind() {
+ ty::Adt(def, _) => {
+ (self.tcx.is_diagnostic_item(sym::Option, def.did())
+ || self.tcx.is_diagnostic_item(sym::Result, def.did()))
+ && (name == sym::map || name == sym::and_then)
+ }
+ _ => false,
+ };
match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) {
(true, Ok(src)) => {
let suggestion = format!("as_ref().{}", src);
self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
|did| {
let ai = self.tcx.associated_item(did);
- ai.container == ty::TraitContainer(clone_trait)
+ ai.trait_container(self.tcx) == Some(clone_trait)
},
),
segment.ident.name,
_ if is_range_literal(expr) => true,
_ => false,
};
- let sugg_expr = if needs_parens { format!("({src})") } else { src };
if let Some(sugg) = self.can_use_as_ref(expr) {
return Some((
}
}
+ let sugg_expr = if needs_parens { format!("({src})") } else { src };
return Some(match mutability {
hir::Mutability::Mut => (
sp,
_ => false,
}
}
-
- // Report the type inferred by the return statement.
- fn report_closure_inferred_return_type(&self, err: &mut Diagnostic, expected: Ty<'tcx>) {
- if let Some(sp) = self.ret_coercion_span.get()
- // If the closure has an explicit return type annotation, or if
- // the closure's return type has been inferred from outside
- // requirements (such as an Fn* trait bound), then a type error
- // may occur at the first return expression we see in the closure
- // (if it conflicts with the declared return type). Skip adding a
- // note in this case, since it would be incorrect.
- && !self.return_type_pre_known
- {
- err.span_note(
- sp,
- &format!(
- "return type inferred to be `{}` here",
- self.resolve_vars_if_possible(expected)
- ),
- );
- }
- }
}
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
- EmissionGuarantee, ErrorGuaranteed,
+ ErrorGuaranteed,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Pos};
use rustc_target::spec::abi::Abi::RustIntrinsic;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCauseCode};
lhs: &'tcx hir::Expr<'tcx>,
err_code: &'static str,
op_span: Span,
- adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
+ adjust_err: impl FnOnce(&mut Diagnostic),
) {
if lhs.is_syntactic_place_expr() {
return;
let else_ty = self.check_expr_with_expectation(else_expr, expected);
let else_diverges = self.diverges.get();
- let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);
- let if_cause =
- self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span);
+ let opt_suggest_box_span = self.opt_suggest_box_span(then_ty, else_ty, orig_expected);
+ let if_cause = self.if_cause(
+ sp,
+ cond_expr.span,
+ then_expr,
+ else_expr,
+ then_ty,
+ else_ty,
+ opt_suggest_box_span,
+ );
coerce.coerce(self, &if_cause, else_expr, else_ty);
let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
- let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
- rhs_ty: Ty<'tcx>| {
+ let suggest_deref_binop = |err: &mut Diagnostic, rhs_ty: Ty<'tcx>| {
if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
// Can only assign if the type is sized, so if `DerefMut` yields a type that is
// unsized, do not suggest dereferencing it.
self.tcx().ty_error()
}
- fn check_call_constructor<G: EmissionGuarantee>(
+ fn check_call_constructor(
&self,
- err: &mut DiagnosticBuilder<'_, G>,
+ err: &mut Diagnostic,
base: &'tcx hir::Expr<'tcx>,
def_id: DefId,
) {
expr,
Some(span),
);
+ } else if let ty::RawPtr(ty_and_mut) = expr_t.kind()
+ && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind()
+ && let ExprKind::Field(base_expr, _) = expr.kind
+ && adt_def.variants().len() == 1
+ && adt_def
+ .variants()
+ .iter()
+ .next()
+ .unwrap()
+ .fields
+ .iter()
+ .any(|f| f.ident(self.tcx) == field)
+ {
+ err.multipart_suggestion(
+ "to access the field, dereference first",
+ vec![
+ (base_expr.span.shrink_to_lo(), "(*".to_string()),
+ (base_expr.span.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
} else {
- let mut found = false;
-
- if let ty::RawPtr(ty_and_mut) = expr_t.kind()
- && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind()
- {
- if adt_def.variants().len() == 1
- && adt_def
- .variants()
- .iter()
- .next()
- .unwrap()
- .fields
- .iter()
- .any(|f| f.ident(self.tcx) == field)
- {
- if let Some(dot_loc) = expr_snippet.rfind('.') {
- found = true;
- err.span_suggestion(
- expr.span.with_hi(expr.span.lo() + BytePos::from_usize(dot_loc)),
- "to access the field, dereference first",
- format!("(*{})", &expr_snippet[0..dot_loc]),
- Applicability::MaybeIncorrect,
- );
- }
- }
- }
-
- if !found {
- err.help("methods are immutable and cannot be assigned to");
- }
+ err.help("methods are immutable and cannot be assigned to");
}
err.emit();
);
// try to add a suggestion in case the field is a nested field of a field of the Adt
- if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
- for candidate_field in fields.iter() {
+ let mod_id = self.tcx.parent_module(id).to_def_id();
+ if let Some((fields, substs)) =
+ self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
+ {
+ for candidate_field in fields {
if let Some(mut field_path) = self.check_for_nested_field_satisfying(
span,
&|candidate_field, _| candidate_field.ident(self.tcx()) == field,
candidate_field,
substs,
vec![],
- self.tcx.parent_module(id).to_def_id(),
+ mod_id,
) {
// field_path includes `field` that we're looking for, so pop it.
field_path.pop();
err
}
- pub(crate) fn get_field_candidates(
+ pub(crate) fn get_field_candidates_considering_privacy(
&self,
span: Span,
- base_t: Ty<'tcx>,
- ) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> {
- debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
+ base_ty: Ty<'tcx>,
+ mod_id: DefId,
+ ) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, SubstsRef<'tcx>)> {
+ debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);
- for (base_t, _) in self.autoderef(span, base_t) {
+ for (base_t, _) in self.autoderef(span, base_ty) {
match base_t.kind() {
ty::Adt(base_def, substs) if !base_def.is_enum() => {
+ let tcx = self.tcx;
let fields = &base_def.non_enum_variant().fields;
- // For compile-time reasons put a limit on number of fields we search
- if fields.len() > 100 {
- return None;
+ // Some struct, e.g. some that impl `Deref`, have all private fields
+ // because you're expected to deref them to access the _real_ fields.
+ // This, for example, will help us suggest accessing a field through a `Box<T>`.
+ if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) {
+ continue;
}
- return Some((fields, substs));
+ return Some((
+ fields
+ .iter()
+ .filter(move |field| field.vis.is_accessible_from(mod_id, tcx))
+ // For compile-time reasons put a limit on number of fields we search
+ .take(100),
+ substs,
+ ));
}
_ => {}
}
candidate_field: &ty::FieldDef,
subst: SubstsRef<'tcx>,
mut field_path: Vec<Ident>,
- id: DefId,
+ mod_id: DefId,
) -> Option<Vec<Ident>> {
debug!(
"check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
// up to a depth of three
None
} else {
- // recursively search fields of `candidate_field` if it's a ty::Adt
field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
let field_ty = candidate_field.ty(self.tcx, subst);
- if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
- for field in nested_fields.iter() {
- if field.vis.is_accessible_from(id, self.tcx) {
- if matches(candidate_field, field_ty) {
- return Some(field_path);
- } else if let Some(field_path) = self.check_for_nested_field_satisfying(
- span,
- matches,
- field,
- subst,
- field_path.clone(),
- id,
- ) {
- return Some(field_path);
- }
+ if matches(candidate_field, field_ty) {
+ return Some(field_path);
+ } else if let Some((nested_fields, subst)) =
+ self.get_field_candidates_considering_privacy(span, field_ty, mod_id)
+ {
+ // recursively search fields of `candidate_field` if it's a ty::Adt
+ for field in nested_fields {
+ if let Some(field_path) = self.check_for_nested_field_satisfying(
+ span,
+ matches,
+ field,
+ subst,
+ field_path.clone(),
+ mod_id,
+ ) {
+ return Some(field_path);
}
}
}
is_alias_variant_ctor = true;
}
Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
- let container = tcx.associated_item(def_id).container;
- debug!(?def_id, ?container);
+ let assoc_item = tcx.associated_item(def_id);
+ let container = assoc_item.container;
+ let container_id = assoc_item.container_id(tcx);
+ debug!(?def_id, ?container, ?container_id);
match container {
- ty::TraitContainer(trait_did) => {
- callee::check_legal_trait_for_method_call(tcx, span, None, span, trait_did)
+ ty::TraitContainer => {
+ callee::check_legal_trait_for_method_call(tcx, span, None, span, container_id)
}
- ty::ImplContainer(impl_def_id) => {
+ ty::ImplContainer => {
if segments.len() == 1 {
// `<T>::assoc` will end up here, and so
// can `T::assoc`. It this came from an
// `T` for posterity (see `UserSelfTy` for
// details).
let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
- user_self_ty = Some(UserSelfTy { impl_def_id, self_ty });
+ user_self_ty = Some(UserSelfTy { impl_def_id: container_id, self_ty });
}
}
}
.filter_map(|seg| seg.args.as_ref())
.flat_map(|a| a.args.iter())
{
- if let hir::GenericArg::Type(hir_ty) = &arg {
- let ty = self.resolve_vars_if_possible(
- self.typeck_results.borrow().node_type(hir_ty.hir_id),
- );
- if ty == predicate.self_ty() {
- error.obligation.cause.span = hir_ty.span;
- }
+ if let hir::GenericArg::Type(hir_ty) = &arg
+ && let Some(ty) =
+ self.typeck_results.borrow().node_type_opt(hir_ty.hir_id)
+ && self.resolve_vars_if_possible(ty) == predicate.self_ty()
+ {
+ error.obligation.cause.span = hir_ty.span;
+ break;
}
}
}
fn label_fn_like(
&self,
- err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
+ err: &mut Diagnostic,
callable_def_id: Option<DefId>,
callee_ty: Option<Ty<'tcx>>,
) {
use std::cell::{Cell, RefCell};
use std::ops::Deref;
+/// The `FnCtxt` stores type-checking context needed to type-check bodies of
+/// functions, closures, and `const`s, including performing type inference
+/// with [`InferCtxt`].
+///
+/// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures*
+/// and thus does not perform type inference.
+///
+/// See [`ItemCtxt`]'s docs for more.
+///
+/// [`ItemCtxt`]: crate::collect::ItemCtxt
+/// [`InferCtxt`]: infer::InferCtxt
pub struct FnCtxt<'a, 'tcx> {
pub(super) body_id: hir::HirId,
&& results.type_dependent_def_id(expr.hir_id).map_or(
false,
|did| {
- self.tcx.associated_item(did).container
- == ty::AssocItemContainer::TraitContainer(clone_trait_did)
+ let assoc_item = self.tcx.associated_item(did);
+ assoc_item.container == ty::AssocItemContainer::TraitContainer
+ && assoc_item.container_id(self.tcx) == clone_trait_did
},
)
// If that clone call hasn't already dereferenced the self type (i.e. don't give this
) -> SubstsRef<'tcx> {
match pick.kind {
probe::InherentImplPick => {
- let impl_def_id = pick.item.container.id();
+ let impl_def_id = pick.item.container_id(self.tcx);
assert!(
self.tcx.impl_trait_ref(impl_def_id).is_none(),
"impl {:?} is not an inherent impl",
}
probe::ObjectPick => {
- let trait_def_id = pick.item.container.id();
+ let trait_def_id = pick.item.container_id(self.tcx);
self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
// The object data has no entry for the Self
// Type. For the purposes of this method call, we
}
probe::TraitPick => {
- let trait_def_id = pick.item.container.id();
+ let trait_def_id = pick.item.container_id(self.tcx);
// Make a trait reference `$0 : Trait<$1...$n>`
// consisting entirely of type variables. Later on in
fn enforce_illegal_method_limitations(&self, pick: &probe::Pick<'_>) {
// Disallow calls to the method `drop` defined in the `Drop` trait.
- match pick.item.container {
- ty::TraitContainer(trait_def_id) => callee::check_legal_trait_for_method_call(
+ if let Some(trait_def_id) = pick.item.trait_container(self.tcx) {
+ callee::check_legal_trait_for_method_call(
self.tcx,
self.span,
Some(self.self_expr.span),
self.call_expr.span,
trait_def_id,
- ),
- ty::ImplContainer(..) => {}
+ )
}
}
ProbeScope::AllTraits,
) {
// If we find a different result the caller probably forgot to import a trait.
- Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()],
+ Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container_id(self.tcx)],
Err(Ambiguity(ref sources)) => sources
.iter()
.filter_map(|source| {
let trait_name = self.trait_path_or_bare_name(
span,
call_expr.hir_id,
- pick.item.container.id(),
+ pick.item.container_id(self.tcx),
);
let mut lint = lint.build(&format!(
self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
// "type" refers to either a type or, more likely, a trait from which
// the associated function or method is from.
- let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
- let trait_generics = self.tcx.generics_of(pick.item.container.id());
+ let container_id = pick.item.container_id(self.tcx);
+ let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
+ let trait_generics = self.tcx.generics_of(container_id);
let trait_name =
if trait_generics.params.len() <= trait_generics.has_self as usize {
fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) {
let is_accessible = if let Some(name) = self.method_name {
let item = candidate.item;
- let def_scope =
- self.tcx.adjust_ident_and_get_scope(name, item.container.id(), self.body_id).1;
- item.vis.is_accessible_from(def_scope, self.tcx)
+ let def_scope = self
+ .tcx
+ .adjust_ident_and_get_scope(name, item.container_id(self.tcx), self.body_id)
+ .1;
+ item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx)
} else {
true
};
self.assemble_extension_candidates_for_all_traits();
let out_of_scope_traits = match self.pick_core() {
- Some(Ok(p)) => vec![p.item.container.id()],
+ Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
//Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
Some(Err(MethodError::Ambiguity(v))) => v
.into_iter()
self.tcx.def_path_str(stable_pick.item.def_id),
));
}
- (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer(def_id)) => {
+ (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
+ let def_id = stable_pick.item.container_id(self.tcx);
diag.span_suggestion(
self.span,
"use the fully qualified path to the associated const",
fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource {
match candidate.kind {
- InherentImplCandidate(..) => CandidateSource::Impl(candidate.item.container.id()),
+ InherentImplCandidate(..) => {
+ CandidateSource::Impl(candidate.item.container_id(self.tcx))
+ }
ObjectCandidate | WhereClauseCandidate(_) => {
- CandidateSource::Trait(candidate.item.container.id())
+ CandidateSource::Trait(candidate.item.container_id(self.tcx))
}
TraitCandidate(trait_ref) => self.probe(|_| {
let _ = self
// to that impl.
CandidateSource::Impl(impl_data.impl_def_id)
}
- _ => CandidateSource::Trait(candidate.item.container.id()),
+ _ => CandidateSource::Trait(candidate.item.container_id(self.tcx)),
}
}),
}
debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
// Check whether the impl imposes obligations we have to worry about.
- let impl_def_id = probe.item.container.id();
+ let impl_def_id = probe.item.container_id(self.tcx);
let impl_bounds = self.tcx.predicates_of(impl_def_id);
let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
probes: &[(&Candidate<'tcx>, ProbeResult)],
) -> Option<Pick<'tcx>> {
// Do all probes correspond to the same trait?
- let container = probes[0].0.item.container;
- if let ty::ImplContainer(_) = container {
- return None;
- }
- if probes[1..].iter().any(|&(p, _)| p.item.container != container) {
- return None;
+ let container = probes[0].0.item.trait_container(self.tcx)?;
+ for (p, _) in &probes[1..] {
+ let p_container = p.item.trait_container(self.tcx)?;
+ if p_container != container {
+ return None;
+ }
}
// FIXME: check the return type here somehow.
}
}
- let label_span_not_found = |err: &mut DiagnosticBuilder<'_, _>| {
+ let label_span_not_found = |err: &mut Diagnostic| {
if unsatisfied_predicates.is_empty() {
err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
let is_string_or_ref_str = match actual.kind() {
label_span_not_found(&mut err);
}
- self.check_for_field_method(&mut err, source, span, actual, item_name);
+ // Don't suggest (for example) `expr.field.method()` if `expr.method()`
+ // doesn't exist due to unsatisfied predicates.
+ if unsatisfied_predicates.is_empty() {
+ self.check_for_field_method(&mut err, source, span, actual, item_name);
+ }
self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
rcvr_ty: Ty<'tcx>,
expr: &hir::Expr<'_>,
item_name: Ident,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ err: &mut Diagnostic,
) -> bool {
let tcx = self.tcx;
let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
fn check_for_field_method(
&self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ err: &mut Diagnostic,
source: SelfSource<'tcx>,
span: Span,
actual: Ty<'tcx>,
item_name: Ident,
) {
if let SelfSource::MethodCall(expr) = source
- && let Some((fields, substs)) = self.get_field_candidates(span, actual)
+ && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
+ && let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id)
{
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
- for candidate_field in fields.iter() {
+ for candidate_field in fields {
if let Some(field_path) = self.check_for_nested_field_satisfying(
span,
&|_, field_ty| {
candidate_field,
substs,
vec![],
- self.tcx.parent_module(expr.hir_id).to_def_id(),
+ mod_id,
) {
let field_path_str = field_path
.iter()
fn check_for_unwrap_self(
&self,
- err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+ err: &mut Diagnostic,
source: SelfSource<'tcx>,
span: Span,
actual: Ty<'tcx>,
// We point at the method, but we just skip the rest of the check for arbitrary
// self types and rely on the suggestion to `use` the trait from
// `suggest_valid_traits`.
- let did = Some(pick.item.container.id());
+ let did = Some(pick.item.container_id(self.tcx));
let skip = skippable.contains(&did);
if pick.autoderefs == 0 && !skip {
err.span_label(
)
{
debug!("try_alt_rcvr: pick candidate {:?}", pick);
- let did = Some(pick.item.container.id());
+ let did = Some(pick.item.container_id(self.tcx));
// We don't want to suggest a container type when the missing
// method is `.clone()` or `.deref()` otherwise we'd suggest
// `Arc::new(foo).clone()`, which is far from what the user wants.
}
}
// We only want to suggest public or local traits (#45781).
- item.vis.is_public() || info.def_id.is_local()
+ item.visibility(self.tcx).is_public() || info.def_id.is_local()
})
.is_some()
})
use crate::check::gather_locals::GatherLocalsVisitor;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
- pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
+ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::Idx;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_session::Session;
use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident};
-use rustc_span::{self, BytePos, Span};
+use rustc_span::{self, BytePos, Span, Symbol};
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
use std::cell::RefCell;
+use std::num::NonZeroU32;
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
err.emit();
}
+fn default_body_is_unstable(
+ tcx: TyCtxt<'_>,
+ impl_span: Span,
+ item_did: DefId,
+ feature: Symbol,
+ reason: Option<Symbol>,
+ issue: Option<NonZeroU32>,
+) {
+ let missing_item_name = &tcx.associated_item(item_did).name;
+ let use_of_unstable_library_feature_note = match reason {
+ Some(r) => format!("use of unstable library feature '{feature}': {r}"),
+ None => format!("use of unstable library feature '{feature}'"),
+ };
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ impl_span,
+ E0046,
+ "not all trait items implemented, missing: `{missing_item_name}`",
+ );
+ err.note(format!("default implementation of `{missing_item_name}` is unstable"));
+ err.note(use_of_unstable_library_feature_note);
+ rustc_session::parse::add_feature_diagnostics_for_issue(
+ &mut err,
+ &tcx.sess.parse_sess,
+ feature,
+ rustc_feature::GateIssue::Library(issue),
+ );
+ err.emit();
+}
+
/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
fn bounds_from_generic_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
/// * `span` - The span of the snippet
/// * `params` - The number of parameters the constructor accepts
/// * `err` - A mutable diagnostic builder to add the suggestion to
-fn suggest_call_constructor<G: EmissionGuarantee>(
- span: Span,
- kind: CtorOf,
- params: usize,
- err: &mut DiagnosticBuilder<'_, G>,
-) {
+fn suggest_call_constructor(span: Span, kind: CtorOf, params: usize, err: &mut Diagnostic) {
// Note: tuple-structs don't have named fields, so just use placeholders
let args = vec!["_"; params].join(", ");
let applicable = if params > 0 {
{
// Suppress this error, since we already emitted
// a deref suggestion in check_overloaded_binop
- err.delay_as_bug();
+ err.downgrade_to_delayed_bug();
}
}
});
// If there are multiple arms, make sure they all agree on
// what the type of the binding `x` ought to be.
if var_id != pat.hir_id {
- self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti);
+ self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti);
}
if let Some(p) = sub {
local_ty
}
- fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
+ fn check_binding_alt_eq_ty(
+ &self,
+ ba: hir::BindingAnnotation,
+ span: Span,
+ var_id: HirId,
+ ty: Ty<'tcx>,
+ ti: TopInfo<'tcx>,
+ ) {
let var_ty = self.local_ty(span, var_id).decl_ty;
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
let hir = self.tcx.hir();
});
let pre = if in_match { "in the same arm, " } else { "" };
err.note(&format!("{}a binding must have the same type in all alternatives", pre));
- // FIXME: check if `var_ty` and `ty` can be made the same type by adding or removing
- // `ref` or `&` to the pattern.
+ self.suggest_adding_missing_ref_or_removing_ref(
+ &mut err,
+ span,
+ var_ty,
+ self.resolve_vars_with_obligations(ty),
+ ba,
+ );
err.emit();
}
}
+ fn suggest_adding_missing_ref_or_removing_ref(
+ &self,
+ err: &mut Diagnostic,
+ span: Span,
+ expected: Ty<'tcx>,
+ actual: Ty<'tcx>,
+ ba: hir::BindingAnnotation,
+ ) {
+ match (expected.kind(), actual.kind(), ba) {
+ (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::Unannotated)
+ if self.can_eq(self.param_env, *inner_ty, actual).is_ok() =>
+ {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ "consider adding `ref`",
+ "ref ",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::Ref)
+ if self.can_eq(self.param_env, expected, *inner_ty).is_ok() =>
+ {
+ err.span_suggestion_verbose(
+ span.with_hi(span.lo() + BytePos(4)),
+ "consider removing `ref`",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => (),
+ }
+ }
+
// Precondition: pat is a Ref(_) pattern
fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
let tcx = self.tcx;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
- self, AdtKind, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt,
- TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+ self, AdtKind, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
+ TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
let item = tcx.associated_item(item_id);
let (mut implied_bounds, self_ty) = match item.container {
- ty::TraitContainer(_) => (FxHashSet::default(), tcx.types.self_param),
- ty::ImplContainer(def_id) => (
- impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span),
- tcx.type_of(def_id),
- ),
+ ty::TraitContainer => (FxHashSet::default(), tcx.types.self_param),
+ ty::ImplContainer => {
+ let def_id = item.container_id(tcx);
+ (
+ impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span),
+ tcx.type_of(def_id),
+ )
+ }
};
match item.kind {
check_method_receiver(wfcx, hir_sig, item, self_ty);
}
ty::AssocKind::Type => {
- if let ty::AssocItemContainer::TraitContainer(_) = item.container {
+ if let ty::AssocItemContainer::TraitContainer = item.container {
check_associated_type_bounds(wfcx, item, span)
}
- if item.defaultness.has_value() {
+ if item.defaultness(tcx).has_value() {
let ty = tcx.type_of(item.def_id);
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
let infcx = wfcx.infcx;
let tcx = wfcx.tcx();
- let predicates = tcx.predicates_of(def_id);
+ let predicates = tcx.bound_predicates_of(def_id.to_def_id());
let generics = tcx.generics_of(def_id);
let is_our_default = |def: &ty::GenericParamDef| match def.kind {
// Now we build the substituted predicates.
let default_obligations = predicates
+ .0
.predicates
.iter()
.flat_map(|&(pred, sp)| {
}
let mut param_count = CountParams::default();
let has_region = pred.visit_with(&mut param_count).is_break();
- let substituted_pred = EarlyBinder(pred).subst(tcx, substs);
+ let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
// Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params.
if substituted_pred.has_param_types_or_consts()
|| has_region
{
None
- } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
+ } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
// Avoid duplication of predicates that contain no parameters, for example.
None
} else {
traits::Obligation::new(cause, wfcx.param_env, pred)
});
- let predicates = predicates.instantiate_identity(tcx);
+ let predicates = predicates.0.instantiate_identity(tcx);
let predicates = wfcx.normalize(span, None, predicates);
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
use rustc_trait_selection::traits::predicate_for_trait_def;
-use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_trait_selection::traits::{self, ObligationCause};
use std::collections::BTreeMap;
pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
// it is not immediately clear why Copy is not implemented for a field, since
// all we point at is the field itself.
tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
- let mut fulfill_cx = traits::FulfillmentContext::new();
- fulfill_cx.register_bound(
+ for error in traits::fully_solve_bound(
&infcx,
+ traits::ObligationCause::dummy_with_span(field_ty_span),
param_env,
ty,
tcx.lang_items().copy_trait().unwrap(),
- traits::ObligationCause::dummy_with_span(field_ty_span),
- );
- for error in fulfill_cx.select_all_or_error(&infcx) {
+ ) {
let error_predicate = error.obligation.predicate;
// Only note if it's not the root obligation, otherwise it's trivial and
// should be self-explanatory (i.e. a field literally doesn't implement Copy).
))
.emit();
} else {
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
- for field in coerced_fields {
- let predicate = predicate_for_trait_def(
- tcx,
- param_env,
- cause.clone(),
- dispatch_from_dyn_trait,
- 0,
- field.ty(tcx, substs_a),
- &[field.ty(tcx, substs_b).into()],
- );
-
- fulfill_cx.register_predicate_obligation(&infcx, predicate);
- }
-
- // Check that all transitive obligations are satisfied.
- let errors = fulfill_cx.select_all_or_error(&infcx);
+ let errors = traits::fully_solve_obligations(
+ &infcx,
+ coerced_fields.into_iter().map(|field| {
+ predicate_for_trait_def(
+ tcx,
+ param_env,
+ cause.clone(),
+ dispatch_from_dyn_trait,
+ 0,
+ field.ty(tcx, substs_a),
+ &[field.ty(tcx, substs_b).into()],
+ )
+ }),
+ );
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
}
};
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_hir_id);
let predicate = predicate_for_trait_def(
source,
&[target.into()],
);
- fulfill_cx.register_predicate_obligation(&infcx, predicate);
-
- // Check that all transitive obligations are satisfied.
- let errors = fulfill_cx.select_all_or_error(&infcx);
+ let errors = traits::fully_solve_obligation(&infcx, predicate);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
///////////////////////////////////////////////////////////////////////////
/// Context specific to some particular item. This is what implements
-/// `AstConv`. It has information about the predicates that are defined
+/// [`AstConv`].
+///
+/// # `ItemCtxt` vs `FnCtxt`
+///
+/// `ItemCtxt` is primarily used to type-check item signatures and lower them
+/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`].
+/// It's also used for the bodies of items like structs where the body (the fields)
+/// are just signatures.
+///
+/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of
+/// functions, closures, and `const`s -- anywhere that expressions and statements show up.
+///
+/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
+/// while `FnCtxt` does do inference.
+///
+/// [`FnCtxt`]: crate::check::FnCtxt
+/// [`InferCtxt`]: rustc_infer::infer::InferCtxt
+///
+/// # Trait predicates
+///
+/// `ItemCtxt` has information about the predicates that are defined
/// on the trait. Unfortunately, this predicate information is
/// available in various different forms at various points in the
/// process. So we can't just store a pointer to e.g., the AST or the
match item {
Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
- if !item.defaultness.has_value() {
+ if !tcx.impl_defaultness(item.id.def_id).has_value() {
tcx.sess
.struct_span_err(
item.span,
// supertrait).
if let ty::Projection(projection) = ty.kind() {
projection.substs == trait_identity_substs
- && tcx.associated_item(projection.item_def_id).container.id() == def_id
+ && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
} else {
false
}
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(impl_item) = tcx.opt_associated_item(def_id)
- && let ty::AssocItemContainer::ImplContainer(_) = impl_item.container
+ && let ty::AssocItemContainer::ImplContainer = impl_item.container
&& let Some(trait_item) = impl_item.trait_item_def_id
{
return tcx
use rustc_hir as hir;
use rustc_infer::traits::util;
use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_span::Span;
// Associated types are implicitly sized unless a `?Sized` bound is found
<dyn AstConv<'_>>::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_def_id = tcx.parent(assoc_item_def_id);
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
Some(mut err) => {
if !ty.references_error() {
+ // Only suggest adding `:` if it was missing (and suggested by parsing diagnostic)
+ let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" };
+
// 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.
// FIXME(eddyb) this looks like it should be functionality on `Diagnostic`.
err.span_suggestion(
span,
&format!("provide a type for the {item}", item = kind),
- format!("{}: {}", item_ident, sugg_ty),
+ format!("{colon} {sugg_ty}"),
Applicability::MachineApplicable,
);
} else {
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{ForeignItem, ForeignItemKind, HirId};
use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngine;
use rustc_infer::traits::{ObligationCause, WellFormedLoc};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder};
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
self.tcx.infer_ctxt().enter(|infcx| {
- let mut fulfill = traits::FulfillmentContext::new();
let tcx_ty =
self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
let cause = traits::ObligationCause::new(
self.hir_id,
traits::ObligationCauseCode::WellFormed(None),
);
- fulfill.register_predicate_obligation(
+ let errors = traits::fully_solve_obligation(
&infcx,
traits::Obligation::new(
cause,
.to_predicate(self.tcx),
),
);
-
- let errors = fulfill.select_all_or_error(&infcx);
if !errors.is_empty() {
debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors {
let item = tcx.associated_item(def_id);
match item.kind {
ty::AssocKind::Type => {
- if item.defaultness.has_value() {
+ if item.defaultness(tcx).has_value() {
cgp::parameters_for(&tcx.type_of(def_id), true)
} else {
Vec::new()
use rustc_hir::def_id::DefId;
use rustc_hir::{Node, CRATE_HIR_ID};
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
-use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::middle;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
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 _,
-};
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use std::iter;
) -> bool {
tcx.infer_ctxt().enter(|ref infcx| {
let param_env = ty::ParamEnv::empty();
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- match infcx.at(cause, param_env).eq(expected, actual) {
- Ok(InferOk { obligations, .. }) => {
- fulfill_cx.register_predicate_obligations(infcx, obligations);
- }
+ let errors = match infcx.at(cause, param_env).eq(expected, actual) {
+ Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
Err(err) => {
infcx.report_mismatched_types(cause, expected, actual, err).emit();
return false;
}
- }
+ };
- match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ match &errors[..] {
[] => true,
errors => {
infcx.report_fulfillment_errors(errors, None, false);
}
let expected_return_type;
- if let Some(term_id) = tcx.lang_items().termination() {
+ if let Some(term_did) = tcx.lang_items().termination() {
let return_ty = main_fnsig.output();
let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
if !return_ty.bound_vars().is_empty() {
}
let return_ty = return_ty.skip_binder();
tcx.infer_ctxt().enter(|infcx| {
+ // Main should have no WC, so empty param env is OK here.
+ let param_env = ty::ParamEnv::empty();
let cause = traits::ObligationCause::new(
return_ty_span,
main_diagnostics_hir_id,
ObligationCauseCode::MainFunctionType,
);
- let mut fulfillment_cx = traits::FulfillmentContext::new();
- // 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,
- );
- let errors = fulfillment_cx.select_all_or_error(&infcx);
+ let ocx = traits::ObligationCtxt::new(&infcx);
+ let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
+ ocx.register_bound(cause, param_env, norm_return_ty, term_did);
+ let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
error = true;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
use rustc_span::Span;
use super::explicit::ExplicitPredicatesMap;
debug!("Projection");
check_explicit_predicates(
tcx,
- tcx.associated_item(obj.item_def_id).container.id(),
+ tcx.parent(obj.item_def_id),
obj.substs,
required_predicates,
explicit_map,
use rustc_trait_selection::infer::InferCtxt;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
use rustc_trait_selection::traits::query::NoSolution;
-use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine};
+use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt};
pub use rustc_middle::traits::query::OutlivesBound;
if let Some(constraints) = constraints {
// Instantiation may have produced new inference variables and constraints on those
// variables. Process these constraints.
- let mut fulfill_cx = FulfillmentContext::new();
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx);
let cause = ObligationCause::misc(span, body_id);
for &constraint in &constraints.outlives {
let obligation = self.query_outlives_constraint_to_obligation(
# probably don't want to use this.
#qemu-rootfs = <none> (path)
+# Skip building the `std` library for this target. Enabled by default for
+# target triples containing `-none`, `nvptx`, `switch`, or `-uefi`.
+#no-std = <platform-specific> (bool)
+
# =============================================================================
# Distribution options
#
for n in 0..(<$t>::BITS / 8) {
for i in 1..=(100 as $t) {
let x = black_box(i << (n * 8));
- black_box(x.log10());
+ black_box(x.ilog10());
}
}
});
.collect();
bench.iter(|| {
for x in &numbers {
- black_box(black_box(x).log10());
+ black_box(black_box(x).ilog10());
}
});
}
.collect();
bench.iter(|| {
for x in &numbers {
- black_box(black_box(x).log10());
+ black_box(black_box(x).ilog10());
}
});
}
Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) })
}
- /// Internal helper constructor to skip revalidating alignment validity.
- #[inline]
- const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> {
+ #[inline(always)]
+ const fn max_size_for_align(align: ValidAlign) -> usize {
// (power-of-two implies align != 0.)
// Rounded up size is:
//
// Above implies that checking for summation overflow is both
// necessary and sufficient.
- if size > isize::MAX as usize - (align.as_nonzero().get() - 1) {
+ isize::MAX as usize - (align.as_usize() - 1)
+ }
+
+ /// Internal helper constructor to skip revalidating alignment validity.
+ #[inline]
+ const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> {
+ if size > Self::max_size_for_align(align) {
return Err(LayoutError);
}
without modifying the layout"]
#[inline]
pub const fn align(&self) -> usize {
- self.align.as_nonzero().get()
+ self.align.as_usize()
}
/// Constructs a `Layout` suitable for holding a value of type `T`.
/// Creates a layout describing the record for a `[T; n]`.
///
- /// On arithmetic overflow, returns `LayoutError`.
+ /// On arithmetic overflow or when the total size would exceed
+ /// `isize::MAX`, returns `LayoutError`.
#[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
#[inline]
pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
- let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
- // The safe constructor is called here to enforce the isize size limit.
- Layout::from_size_valid_align(array_size, ValidAlign::of::<T>())
+ // Reduce the amount of code we need to monomorphize per `T`.
+ return inner(mem::size_of::<T>(), ValidAlign::of::<T>(), n);
+
+ #[inline]
+ fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result<Layout, LayoutError> {
+ // We need to check two things about the size:
+ // - That the total size won't overflow a `usize`, and
+ // - That the total size still fits in an `isize`.
+ // By using division we can check them both with a single threshold.
+ // That'd usually be a bad idea, but thankfully here the element size
+ // and alignment are constants, so the compiler will fold all of it.
+ if element_size != 0 && n > Layout::max_size_for_align(align) / element_size {
+ return Err(LayoutError);
+ }
+
+ let array_size = element_size * n;
+
+ // SAFETY: We just checked above that the `array_size` will not
+ // exceed `isize::MAX` even when rounded up to the alignment.
+ // And `ValidAlign` guarantees it's a power of two.
+ unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
+ }
}
}
)+};
}
-// SAFETY: All the ordinary integer types allow all bit patterns as distinct values
+// SAFETY: All the ordinary integer types have no padding, and are not pointers.
is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
-// SAFETY: bool and char have *niches*, but no *padding*, so this is sound
+// SAFETY: bool and char have *niches*, but no *padding* (and these are not pointer types), so this
+// is sound
is_raw_eq_comparable!(bool, char);
-// SAFETY: Similarly, the non-zero types have a niche, but no undef,
+// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers,
// and they compare like their underlying numeric type.
is_raw_eq_comparable!(
NonZeroU8,
///
/// The general categories for numbers (`Nd` for decimal digits, `Nl` for letter-like numeric
/// characters, and `No` for other numeric characters) are specified in the [Unicode Character
- /// Database][ucd] [`UnicodeData.txt`]. Note that this means ideographic numbers like '三'
- /// are considered alphabetic, not numeric. Please consider to use `is_ascii_digit` or `is_digit`.
+ /// Database][ucd] [`UnicodeData.txt`].
///
/// This method doesn't cover everything that could be considered a number, e.g. ideographic numbers like '三'.
/// If you want everything including characters with overlapping purposes then you might want to use
use crate::cmp::Ordering;
use crate::ffi::c_char;
use crate::fmt::{self, Write};
+use crate::intrinsics;
use crate::ops;
use crate::slice;
use crate::slice::memchr;
#[must_use]
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
#[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
+ #[rustc_allow_const_fn_unstable(const_eval_select)]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
- // We're in a const fn, so this is the best we can do
- debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
- // SAFETY: Calling an inner function with the same prerequisites.
- unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }
- }
+ #[inline]
+ fn rt_impl(bytes: &[u8]) -> &CStr {
+ // Chance at catching some UB at runtime with debug builds.
+ debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
- #[inline]
- const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
- // SAFETY: Casting to CStr is safe because its internal representation
- // is a [u8] too (safe only inside std).
- // Dereferencing the obtained pointer is safe because it comes from a
- // reference. Making a reference is then safe because its lifetime
- // is bound by the lifetime of the given `bytes`.
- unsafe { &*(bytes as *const [u8] as *const CStr) }
+ // SAFETY: Casting to CStr is safe because its internal representation
+ // is a [u8] too (safe only inside std).
+ // Dereferencing the obtained pointer is safe because it comes from a
+ // reference. Making a reference is then safe because its lifetime
+ // is bound by the lifetime of the given `bytes`.
+ unsafe { &*(bytes as *const [u8] as *const CStr) }
+ }
+
+ const fn const_impl(bytes: &[u8]) -> &CStr {
+ // Saturating so that an empty slice panics in the assert with a good
+ // message, not here due to underflow.
+ let mut i = bytes.len().saturating_sub(1);
+ assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated");
+
+ // Ending null byte exists, skip to the rest.
+ while i != 0 {
+ i -= 1;
+ let byte = bytes[i];
+ assert!(byte != 0, "input contained interior nul");
+ }
+
+ // SAFETY: See `rt_impl` cast.
+ unsafe { &*(bytes as *const [u8] as *const CStr) }
+ }
+
+ // SAFETY: The const and runtime versions have identical behavior
+ // unless the safety contract of `from_bytes_with_nul_unchecked` is
+ // violated, which is UB.
+ unsafe { intrinsics::const_eval_select((bytes,), const_impl, rt_impl) }
}
/// Returns the inner pointer to this C string.
/// Reinterprets the bits of a value of one type as another type.
///
- /// Both types must have the same size. Neither the original, nor the result,
- /// may be an [invalid value](../../nomicon/what-unsafe-does.html).
+ /// Both types must have the same size. Compilation will fail if this is not guaranteed.
///
/// `transmute` is semantically equivalent to a bitwise move of one type
/// into another. It copies the bits from the source value into the
- /// destination value, then forgets the original. It's equivalent to C's
- /// `memcpy` under the hood, just like `transmute_copy`.
+ /// destination value, then forgets the original. Note that source and destination
+ /// are passed by-value, which means if `T` or `U` contain padding, that padding
+ /// is *not* guaranteed to be preserved by `transmute`.
+ ///
+ /// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at
+ /// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler
+ /// will generate code *assuming that you, the programmer, ensure that there will never be
+ /// undefined behavior*. It is therefore your responsibility to guarantee that every value
+ /// passed to `transmute` is valid at both types `T` and `U`. Failing to uphold this condition
+ /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly
+ /// unsafe**. `transmute` should be the absolute last resort.
+ ///
+ /// Transmuting pointers to integers in a `const` context is [undefined behavior][ub].
+ /// Any attempt to use the resulting value for integer operations will abort const-evaluation.
+ /// (And even outside `const`, such transmutation is touching on many unspecified aspects of the
+ /// Rust memory model and should be avoided. See below for alternatives.)
///
/// Because `transmute` is a by-value operation, alignment of the *transmuted values
/// themselves* is not a concern. As with any other function, the compiler already ensures
/// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper
/// alignment of the pointed-to values.
///
- /// `transmute` is **incredibly** unsafe. There are a vast number of ways to
- /// cause [undefined behavior][ub] with this function. `transmute` should be
- /// the absolute last resort.
- ///
- /// Transmuting pointers to integers in a `const` context is [undefined behavior][ub].
- /// Any attempt to use the resulting value for integer operations will abort const-evaluation.
- ///
- /// The [nomicon](../../nomicon/transmutes.html) has additional
- /// documentation.
+ /// The [nomicon](../../nomicon/transmutes.html) has additional documentation.
///
/// [ub]: ../../reference/behavior-considered-undefined.html
///
///
/// # Safety
///
- /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized.
+ /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized or carry a
+ /// pointer value.
/// Note that this is a stricter criterion than just the *values* being
/// fully-initialized: if `T` has padding, it's UB to call this intrinsic.
///
// alignment as a parameter, such as `Layout::padding_needed_for`.
pub(crate) use valid_align::ValidAlign;
+mod transmutability;
+#[unstable(feature = "transmutability", issue = "99571")]
+pub use transmutability::{Assume, BikeshedIntrinsicFrom};
+
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(inline)]
pub use crate::intrinsics::transmute;
--- /dev/null
+/// Are values of a type transmutable into values of another type?
+///
+/// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of
+/// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`,
+/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
+#[unstable(feature = "transmutability", issue = "99571")]
+#[cfg_attr(not(bootstrap), lang = "transmute_trait")]
+#[rustc_on_unimplemented(
+ message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.",
+ label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`."
+)]
+pub unsafe trait BikeshedIntrinsicFrom<
+ Src,
+ Context,
+ const ASSUME_ALIGNMENT: bool,
+ const ASSUME_LIFETIMES: bool,
+ const ASSUME_VALIDITY: bool,
+ const ASSUME_VISIBILITY: bool,
+> where
+ Src: ?Sized,
+{
+}
+
+/// What transmutation safety conditions shall the compiler assume that *you* are checking?
+#[unstable(feature = "transmutability", issue = "99571")]
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct Assume {
+ /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that
+ /// destination referents do not have stricter alignment requirements than source referents.
+ pub alignment: bool,
+
+ /// When `true`, the compiler assume that *you* are ensuring that lifetimes are not extended in a manner
+ /// that violates Rust's memory model.
+ pub lifetimes: bool,
+
+ /// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid
+ /// instance of the destination type.
+ pub validity: bool,
+
+ /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the
+ /// type and field privacy of the destination type (and sometimes of the source type, too).
+ pub visibility: bool,
+}
unsafe { mem::transmute::<usize, ValidAlign>(align) }
}
+ #[inline]
+ pub(crate) const fn as_usize(self) -> usize {
+ self.0 as usize
+ }
+
#[inline]
pub(crate) const fn as_nonzero(self) -> NonZeroUsize {
// SAFETY: All the discriminants are non-zero.
- unsafe { NonZeroUsize::new_unchecked(self.0 as usize) }
+ unsafe { NonZeroUsize::new_unchecked(self.as_usize()) }
}
/// Returns the base 2 logarithm of the alignment.
// Find the most significant non-zero digit.
let msd = digits.iter().rposition(|&x| x != 0);
match msd {
- Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1,
+ Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1,
// There are no non-zero digits, i.e., the number is zero.
_ => 0,
}
/// rounded down.
///
/// This method might not be optimized owing to implementation details;
- /// `log2` can produce results more efficiently for base 2, and `log10`
+ /// `ilog2` can produce results more efficiently for base 2, and `ilog10`
/// can produce results more efficiently for base 10.
///
/// # Panics
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log(self, base: Self) -> u32 {
- match self.checked_log(base) {
+ pub const fn ilog(self, base: Self) -> u32 {
+ match self.checked_ilog(base) {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log2(self) -> u32 {
- match self.checked_log2() {
+ pub const fn ilog2(self) -> u32 {
+ match self.checked_ilog2() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log10(self) -> u32 {
- match self.checked_log10() {
+ pub const fn ilog10(self) -> u32 {
+ match self.checked_ilog10() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
/// Returns `None` if the number is negative or zero, or if the base is not at least 2.
///
/// This method might not be optimized owing to implementation details;
- /// `checked_log2` can produce results more efficiently for base 2, and
- /// `checked_log10` can produce results more efficiently for base 10.
+ /// `checked_ilog2` can produce results more efficiently for base 2, and
+ /// `checked_ilog10` can produce results more efficiently for base 10.
///
/// # Examples
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log(self, base: Self) -> Option<u32> {
+ pub const fn checked_ilog(self, base: Self) -> Option<u32> {
if self <= 0 || base <= 1 {
None
} else {
// Optimization for 128 bit wide integers.
if Self::BITS == 128 {
- let b = Self::log2(self) / (Self::log2(base) + 1);
+ let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
n += b;
r /= base.pow(b as u32);
}
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log2(self) -> Option<u32> {
+ pub const fn checked_ilog2(self) -> Option<u32> {
if self <= 0 {
None
} else {
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log10(self) -> Option<u32> {
+ pub const fn checked_ilog10(self) -> Option<u32> {
if self > 0 {
Some(int_log10::$ActualT(self as $ActualT))
} else {
/// Returns the base 2 logarithm of the number, rounded down.
///
/// This is the same operation as
- #[doc = concat!("[`", stringify!($Int), "::log2`],")]
+ #[doc = concat!("[`", stringify!($Int), "::ilog2`],")]
/// except that it has no failure cases to worry about
/// since this value can never be zero.
///
/// #![feature(int_log)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")]
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")]
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn log2(self) -> u32 {
+ pub const fn ilog2(self) -> u32 {
Self::BITS - 1 - self.leading_zeros()
}
/// Returns the base 10 logarithm of the number, rounded down.
///
/// This is the same operation as
- #[doc = concat!("[`", stringify!($Int), "::log10`],")]
+ #[doc = concat!("[`", stringify!($Int), "::ilog10`],")]
/// except that it has no failure cases to worry about
/// since this value can never be zero.
///
/// #![feature(int_log)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")]
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")]
- #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
+ #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn log10(self) -> u32 {
+ pub const fn ilog10(self) -> u32 {
super::int_log10::$Int(self.0)
}
}
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log(self, base: Self) -> u32 {
- match self.checked_log(base) {
+ pub const fn ilog(self, base: Self) -> u32 {
+ match self.checked_ilog(base) {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log2(self) -> u32 {
- match self.checked_log2() {
+ pub const fn ilog2(self) -> u32 {
+ match self.checked_ilog2() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
#[track_caller]
#[rustc_inherit_overflow_checks]
#[allow(arithmetic_overflow)]
- pub const fn log10(self) -> u32 {
- match self.checked_log10() {
+ pub const fn ilog10(self) -> u32 {
+ match self.checked_ilog10() {
Some(n) => n,
None => {
// In debug builds, trigger a panic on None.
/// Returns `None` if the number is zero, or if the base is not at least 2.
///
/// This method might not be optimized owing to implementation details;
- /// `checked_log2` can produce results more efficiently for base 2, and
- /// `checked_log10` can produce results more efficiently for base 10.
+ /// `checked_ilog2` can produce results more efficiently for base 2, and
+ /// `checked_ilog10` can produce results more efficiently for base 10.
///
/// # Examples
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
+ #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log(self, base: Self) -> Option<u32> {
+ pub const fn checked_ilog(self, base: Self) -> Option<u32> {
if self <= 0 || base <= 1 {
None
} else {
// Optimization for 128 bit wide integers.
if Self::BITS == 128 {
- let b = Self::log2(self) / (Self::log2(base) + 1);
+ let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
n += b;
r /= base.pow(b as u32);
}
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
+ #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log2(self) -> Option<u32> {
+ pub const fn checked_ilog2(self) -> Option<u32> {
if let Some(x) = <$NonZeroT>::new(self) {
- Some(x.log2())
+ Some(x.ilog2())
} else {
None
}
///
/// ```
/// #![feature(int_log)]
- #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
+ #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ```
#[unstable(feature = "int_log", issue = "70887")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
- pub const fn checked_log10(self) -> Option<u32> {
+ pub const fn checked_ilog10(self) -> Option<u32> {
if let Some(x) = <$NonZeroT>::new(self) {
- Some(x.log10())
+ Some(x.ilog10())
} else {
None
}
///
/// This is a bit safer than `as` because it wouldn't silently change the type if the code is
/// refactored.
- #[unstable(feature = "ptr_const_cast", issue = "92675")]
- #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+ #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+ #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
pub const fn cast_mut(self) -> *mut T {
self as _
}
panic!("is_aligned_to: align is not a power-of-two");
}
- // SAFETY: `is_power_of_two()` will return `false` for zero.
- unsafe { core::intrinsics::assume(align != 0) };
-
// Cast is needed for `T: !Sized`
- self.cast::<u8>().addr() % align == 0
+ self.cast::<u8>().addr() & align - 1 == 0
}
}
/// coercion.
///
/// [`cast_mut`]: #method.cast_mut
- #[unstable(feature = "ptr_const_cast", issue = "92675")]
- #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+ #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+ #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
pub const fn cast_const(self) -> *const T {
self as _
}
panic!("is_aligned_to: align is not a power-of-two");
}
- // SAFETY: `is_power_of_two()` will return `false` for zero.
- unsafe { core::intrinsics::assume(align != 0) };
-
// Cast is needed for `T: !Sized`
- self.cast::<u8>().addr() % align == 0
+ self.cast::<u8>().addr() & align - 1 == 0
}
}
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T> Send for ChunksMut<'_, T> where T: Send {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T> Sync for ChunksMut<'_, T> where T: Sync {}
+
/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
/// time), starting at the beginning of the slice.
///
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+unsafe impl<T> Send for ChunksExactMut<'_, T> where T: Send {}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+unsafe impl<T> Sync for ChunksExactMut<'_, T> where T: Sync {}
+
/// A windowed iterator over a slice in overlapping chunks (`N` elements at a
/// time), starting at the beginning of the slice
///
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Send for RChunksMut<'_, T> where T: Send {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Sync for RChunksMut<'_, T> where T: Sync {}
+
/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
/// time), starting at the end of the slice.
///
const MAY_HAVE_SIDE_EFFECT: bool = false;
}
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Send for RChunksExactMut<'_, T> where T: Send {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Sync for RChunksExactMut<'_, T> where T: Sync {}
+
#[doc(hidden)]
#[unstable(feature = "trusted_random_access", issue = "none")]
unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {}
#[inline]
pub fn is_ascii(&self) -> bool {
// We can treat each byte as character here: all multibyte characters
- // start with a byte that is not in the ascii range, so we will stop
+ // start with a byte that is not in the ASCII range, so we will stop
// there already.
self.as_bytes().is_ascii()
}
/// assert_eq!(duration.as_secs(), 5);
/// ```
///
- /// To determine the total number of seconds represented by the `Duration`,
- /// use `as_secs` in combination with [`subsec_nanos`]:
- ///
- /// ```
- /// use std::time::Duration;
- ///
- /// let duration = Duration::new(5, 730023852);
- ///
- /// assert_eq!(5.730023852,
- /// duration.as_secs() as f64
- /// + duration.subsec_nanos() as f64 * 1e-9);
- /// ```
+ /// To determine the total number of seconds represented by the `Duration`
+ /// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`]
///
+ /// [`as_secs_f64`]: Duration::as_secs_f64
+ /// [`as_secs_f32`]: Duration::as_secs_f32
/// [`subsec_nanos`]: Duration::subsec_nanos
#[stable(feature = "duration", since = "1.3.0")]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
// 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() {
+ if let Some(log) = integer_part.checked_ilog10() {
// integer_part is > 0, so has length log10(x)+1
actual_w += 1 + log as usize;
} else {
use core::alloc::Layout;
+use core::mem::size_of;
use core::ptr::{self, NonNull};
#[test]
assert_eq!(Some(DANGLING), NonNull::new(ptr::invalid_mut(ALIGN)));
}
+#[test]
+fn layout_round_up_to_align_edge_cases() {
+ const MAX_SIZE: usize = isize::MAX as usize;
+
+ for shift in 0..usize::BITS {
+ let align = 1_usize << shift;
+ let edge = (MAX_SIZE + 1) - align;
+ let low = edge.saturating_sub(10);
+ let high = edge.saturating_add(10);
+ assert!(Layout::from_size_align(low, align).is_ok());
+ assert!(Layout::from_size_align(high, align).is_err());
+ for size in low..=high {
+ assert_eq!(
+ Layout::from_size_align(size, align).is_ok(),
+ size.next_multiple_of(align) <= MAX_SIZE,
+ );
+ }
+ }
+}
+
+#[test]
+fn layout_array_edge_cases() {
+ for_type::<i64>();
+ for_type::<[i32; 0b10101]>();
+ for_type::<[u8; 0b1010101]>();
+
+ // Make sure ZSTs don't lead to divide-by-zero
+ assert_eq!(Layout::array::<()>(usize::MAX).unwrap(), Layout::from_size_align(0, 1).unwrap());
+
+ fn for_type<T>() {
+ const MAX_SIZE: usize = isize::MAX as usize;
+
+ let edge = (MAX_SIZE + 1) / size_of::<T>();
+ let low = edge.saturating_sub(10);
+ let high = edge.saturating_add(10);
+ assert!(Layout::array::<T>(low).is_ok());
+ assert!(Layout::array::<T>(high).is_err());
+ for n in low..=high {
+ assert_eq!(Layout::array::<T>(n).is_ok(), n * size_of::<T>() <= MAX_SIZE);
+ }
+ }
+}
+
#[test]
fn layout_debug_shows_log2_of_alignment() {
// `Debug` is not stable, but here's what it does right now
-//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a
+//! This tests the `Integer::{ilog,log2,log10}` methods. These tests are in a
//! separate file because there's both a large number of them, and not all tests
-//! can be run on Android. This is because in Android `log2` uses an imprecise
+//! can be run on Android. This is because in Android `ilog2` uses an imprecise
//! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53
#[test]
-fn checked_log() {
- assert_eq!(999u32.checked_log(10), Some(2));
- assert_eq!(1000u32.checked_log(10), Some(3));
- assert_eq!(555u32.checked_log(13), Some(2));
- assert_eq!(63u32.checked_log(4), Some(2));
- assert_eq!(64u32.checked_log(4), Some(3));
- assert_eq!(10460353203u64.checked_log(3), Some(21));
- assert_eq!(10460353202u64.checked_log(3), Some(20));
- assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80));
- assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79));
- assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8));
- assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7));
-
- assert_eq!(0u8.checked_log(4), None);
- assert_eq!(0u16.checked_log(4), None);
- assert_eq!(0i8.checked_log(4), None);
- assert_eq!(0i16.checked_log(4), None);
+fn checked_ilog() {
+ assert_eq!(999u32.checked_ilog(10), Some(2));
+ assert_eq!(1000u32.checked_ilog(10), Some(3));
+ assert_eq!(555u32.checked_ilog(13), Some(2));
+ assert_eq!(63u32.checked_ilog(4), Some(2));
+ assert_eq!(64u32.checked_ilog(4), Some(3));
+ assert_eq!(10460353203u64.checked_ilog(3), Some(21));
+ assert_eq!(10460353202u64.checked_ilog(3), Some(20));
+ assert_eq!(147808829414345923316083210206383297601u128.checked_ilog(3), Some(80));
+ assert_eq!(147808829414345923316083210206383297600u128.checked_ilog(3), Some(79));
+ assert_eq!(22528399544939174411840147874772641u128.checked_ilog(19683), Some(8));
+ assert_eq!(22528399544939174411840147874772631i128.checked_ilog(19683), Some(7));
+
+ assert_eq!(0u8.checked_ilog(4), None);
+ assert_eq!(0u16.checked_ilog(4), None);
+ assert_eq!(0i8.checked_ilog(4), None);
+ assert_eq!(0i16.checked_ilog(4), None);
#[cfg(not(miri))] // Miri is too slow
for i in i16::MIN..=0 {
- assert_eq!(i.checked_log(4), None);
+ assert_eq!(i.checked_ilog(4), None);
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=i16::MAX {
- assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+ assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=u16::MAX {
- assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+ assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32));
}
}
#[test]
-fn checked_log2() {
- assert_eq!(5u32.checked_log2(), Some(2));
- assert_eq!(0u64.checked_log2(), None);
- assert_eq!(128i32.checked_log2(), Some(7));
- assert_eq!((-55i16).checked_log2(), None);
+fn checked_ilog2() {
+ assert_eq!(5u32.checked_ilog2(), Some(2));
+ assert_eq!(0u64.checked_ilog2(), None);
+ assert_eq!(128i32.checked_ilog2(), Some(7));
+ assert_eq!((-55i16).checked_ilog2(), None);
- assert_eq!(0u8.checked_log2(), None);
- assert_eq!(0u16.checked_log2(), None);
- assert_eq!(0i8.checked_log2(), None);
- assert_eq!(0i16.checked_log2(), None);
+ assert_eq!(0u8.checked_ilog2(), None);
+ assert_eq!(0u16.checked_ilog2(), None);
+ assert_eq!(0i8.checked_ilog2(), None);
+ assert_eq!(0i16.checked_ilog2(), None);
for i in 1..=u8::MAX {
- assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=u16::MAX {
- // Guard against Android's imprecise f32::log2 implementation.
+ // Guard against Android's imprecise f32::ilog2 implementation.
if i != 8192 && i != 32768 {
- assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
}
}
for i in i8::MIN..=0 {
- assert_eq!(i.checked_log2(), None);
+ assert_eq!(i.checked_ilog2(), None);
}
for i in 1..=i8::MAX {
- assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in i16::MIN..=0 {
- assert_eq!(i.checked_log2(), None);
+ assert_eq!(i.checked_ilog2(), None);
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=i16::MAX {
- // Guard against Android's imprecise f32::log2 implementation.
+ // Guard against Android's imprecise f32::ilog2 implementation.
if i != 8192 {
- assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+ assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
}
}
}
-// Validate cases that fail on Android's imprecise float log2 implementation.
+// Validate cases that fail on Android's imprecise float ilog2 implementation.
#[test]
#[cfg(not(target_os = "android"))]
-fn checked_log2_not_android() {
- assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u32));
- assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u32));
- assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as u32));
+fn checked_ilog2_not_android() {
+ assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32));
+ assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32));
+ assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32));
}
#[test]
-fn checked_log10() {
- assert_eq!(0u8.checked_log10(), None);
- assert_eq!(0u16.checked_log10(), None);
- assert_eq!(0i8.checked_log10(), None);
- assert_eq!(0i16.checked_log10(), None);
+fn checked_ilog10() {
+ assert_eq!(0u8.checked_ilog10(), None);
+ assert_eq!(0u16.checked_ilog10(), None);
+ assert_eq!(0i8.checked_ilog10(), None);
+ assert_eq!(0i16.checked_ilog10(), None);
#[cfg(not(miri))] // Miri is too slow
for i in i16::MIN..=0 {
- assert_eq!(i.checked_log10(), None);
+ assert_eq!(i.checked_ilog10(), None);
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=i16::MAX {
- assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+ assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=u16::MAX {
- assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+ assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
}
#[cfg(not(miri))] // Miri is too slow
for i in 1..=100_000u32 {
- assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+ assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
}
}
-macro_rules! log10_loop {
- ($T:ty, $log10_max:expr) => {
- assert_eq!(<$T>::MAX.log10(), $log10_max);
- for i in 0..=$log10_max {
+macro_rules! ilog10_loop {
+ ($T:ty, $ilog10_max:expr) => {
+ assert_eq!(<$T>::MAX.ilog10(), $ilog10_max);
+ for i in 0..=$ilog10_max {
let p = (10 as $T).pow(i as u32);
if p >= 10 {
- assert_eq!((p - 9).log10(), i - 1);
- assert_eq!((p - 1).log10(), i - 1);
+ assert_eq!((p - 9).ilog10(), i - 1);
+ assert_eq!((p - 1).ilog10(), i - 1);
}
- assert_eq!(p.log10(), i);
- assert_eq!((p + 1).log10(), i);
+ assert_eq!(p.ilog10(), i);
+ assert_eq!((p + 1).ilog10(), i);
if p >= 10 {
- assert_eq!((p + 9).log10(), i);
+ assert_eq!((p + 9).ilog10(), i);
}
- // also check `x.log(10)`
+ // also check `x.ilog(10)`
if p >= 10 {
- assert_eq!((p - 9).log(10), i - 1);
- assert_eq!((p - 1).log(10), i - 1);
+ assert_eq!((p - 9).ilog(10), i - 1);
+ assert_eq!((p - 1).ilog(10), i - 1);
}
- assert_eq!(p.log(10), i);
- assert_eq!((p + 1).log(10), i);
+ assert_eq!(p.ilog(10), i);
+ assert_eq!((p + 1).ilog(10), i);
if p >= 10 {
- assert_eq!((p + 9).log(10), i);
+ assert_eq!((p + 9).ilog(10), i);
}
}
};
}
#[test]
-fn log10_u8() {
- log10_loop! { u8, 2 }
+fn ilog10_u8() {
+ ilog10_loop! { u8, 2 }
}
#[test]
-fn log10_u16() {
- log10_loop! { u16, 4 }
+fn ilog10_u16() {
+ ilog10_loop! { u16, 4 }
}
#[test]
-fn log10_u32() {
- log10_loop! { u32, 9 }
+fn ilog10_u32() {
+ ilog10_loop! { u32, 9 }
}
#[test]
-fn log10_u64() {
- log10_loop! { u64, 19 }
+fn ilog10_u64() {
+ ilog10_loop! { u64, 19 }
}
#[test]
-fn log10_u128() {
- log10_loop! { u128, 38 }
+fn ilog10_u128() {
+ ilog10_loop! { u128, 38 }
}
assert_eq!(v1, [0, 16, 17, 22, 23]);
}
+#[test]
+fn chunks_mut_are_send_and_sync() {
+ use std::cell::Cell;
+ use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut};
+ use std::sync::MutexGuard;
+
+ fn assert_send_and_sync()
+ where
+ ChunksMut<'static, Cell<i32>>: Send,
+ ChunksMut<'static, MutexGuard<'static, u32>>: Sync,
+ ChunksExactMut<'static, Cell<i32>>: Send,
+ ChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
+ RChunksMut<'static, Cell<i32>>: Send,
+ RChunksMut<'static, MutexGuard<'static, u32>>: Sync,
+ RChunksExactMut<'static, Cell<i32>>: Send,
+ RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
+ {
+ }
+
+ assert_send_and_sync();
+}
+
#[test]
fn test_windows_count() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
//! implementing `std::error::Error`) to get a causal chain of where an error
//! was generated.
//!
-//! > **Note**: this module is unstable and is designed in [RFC 2504], and you
-//! > can learn more about its status in the [tracking issue].
-//!
-//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
-//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487
-//!
//! ## Accuracy
//!
//! Backtraces are attempted to be as accurate as possible, but no guarantees
//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change
//! how backtraces are captured.
-#![unstable(feature = "backtrace", issue = "53487")]
+#![stable(feature = "backtrace", since = "1.65.0")]
#[cfg(test)]
mod tests;
/// previous point in time. In some instances the `Backtrace` type may
/// internally be empty due to configuration. For more information see
/// `Backtrace::capture`.
+#[stable(feature = "backtrace", since = "1.65.0")]
#[must_use]
pub struct Backtrace {
inner: Inner,
/// The current status of a backtrace, indicating whether it was captured or
/// whether it is empty for some other reason.
+#[stable(feature = "backtrace", since = "1.65.0")]
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
pub enum BacktraceStatus {
/// Capturing a backtrace is not supported, likely because it's not
/// implemented for the current platform.
+ #[stable(feature = "backtrace", since = "1.65.0")]
Unsupported,
/// Capturing a backtrace has been disabled through either the
/// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
+ #[stable(feature = "backtrace", since = "1.65.0")]
Disabled,
/// A backtrace has been captured and the `Backtrace` should print
/// reasonable information when rendered.
+ #[stable(feature = "backtrace", since = "1.65.0")]
Captured,
}
Wide(Vec<u16>),
}
+#[stable(feature = "backtrace", since = "1.65.0")]
impl fmt::Debug for Backtrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let capture = match &self.inner {
}
}
+#[unstable(feature = "backtrace_frames", issue = "79676")]
impl fmt::Debug for BacktraceFrame {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut dbg = fmt.debug_list();
///
/// To forcibly capture a backtrace regardless of environment variables, use
/// the `Backtrace::force_capture` function.
+ #[stable(feature = "backtrace", since = "1.65.0")]
#[inline(never)] // want to make sure there's a frame here to remove
pub fn capture() -> Backtrace {
if !Backtrace::enabled() {
/// Note that capturing a backtrace can be an expensive operation on some
/// platforms, so this should be used with caution in performance-sensitive
/// parts of code.
+ #[stable(feature = "backtrace", since = "1.65.0")]
#[inline(never)] // want to make sure there's a frame here to remove
pub fn force_capture() -> Backtrace {
Backtrace::create(Backtrace::force_capture as usize)
/// Forcibly captures a disabled backtrace, regardless of environment
/// variable configuration.
+ #[stable(feature = "backtrace", since = "1.65.0")]
+ #[rustc_const_stable(feature = "backtrace", since = "1.65.0")]
pub const fn disabled() -> Backtrace {
Backtrace { inner: Inner::Disabled }
}
/// Returns the status of this backtrace, indicating whether this backtrace
/// request was unsupported, disabled, or a stack trace was actually
/// captured.
+ #[stable(feature = "backtrace", since = "1.65.0")]
#[must_use]
pub fn status(&self) -> BacktraceStatus {
match self.inner {
}
}
+#[stable(feature = "backtrace", since = "1.65.0")]
impl fmt::Display for Backtrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let capture = match &self.inner {
TypeId::of::<Self>()
}
- /// Returns a stack backtrace, if available, of where this error occurred.
- ///
- /// This function allows inspecting the location, in code, of where an error
- /// happened. The returned `Backtrace` contains information about the stack
- /// trace of the OS thread of execution of where the error originated from.
- ///
- /// Note that not all errors contain a `Backtrace`. Also note that a
- /// `Backtrace` may actually be empty. For more information consult the
- /// `Backtrace` type itself.
- #[unstable(feature = "backtrace", issue = "53487")]
- fn backtrace(&self) -> Option<&Backtrace> {
- None
- }
-
/// ```
/// if let Err(e) = "xc".parse::<u32>() {
/// // Print `e` itself, no need for description().
}
#[unstable(feature = "error_generic_member_access", issue = "99301")]
-impl Provider for dyn Error + 'static {
+impl<'b> Provider for dyn Error + 'b {
fn provide<'a>(&'a self, req: &mut Demand<'a>) {
self.provide(req)
}
Error::source(&**self)
}
- fn backtrace(&self) -> Option<&Backtrace> {
- Error::backtrace(&**self)
+ fn provide<'b>(&'b self, req: &mut Demand<'b>) {
+ Error::provide(&**self, req);
}
}
Error::source(&**self)
}
- fn backtrace(&self) -> Option<&Backtrace> {
- Error::backtrace(&**self)
+ fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+ Error::provide(&**self, req);
}
}
}
}
+impl<'a> dyn Error + 'a {
+ /// Request a reference of type `T` as context about this error.
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ pub fn request_ref<T: ?Sized + 'static>(&'a self) -> Option<&'a T> {
+ core::any::request_ref(self)
+ }
+
+ /// Request a value of type `T` as context about this error.
+ #[unstable(feature = "error_generic_member_access", issue = "99301")]
+ pub fn request_value<T: 'static>(&'a self) -> Option<T> {
+ core::any::request_value(self)
+ }
+}
+
// Copied from `any.rs`.
impl dyn Error + 'static {
/// Returns `true` if the inner type is the same as `T`.
None
}
}
-
- /// Request a reference of type `T` as context about this error.
- #[unstable(feature = "error_generic_member_access", issue = "99301")]
- pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
- core::any::request_ref(self)
- }
-
- /// Request a value of type `T` as context about this error.
- #[unstable(feature = "error_generic_member_access", issue = "99301")]
- pub fn request_value<T: 'static>(&self) -> Option<T> {
- core::any::request_value(self)
- }
}
impl dyn Error + 'static + Send {
/// Request a reference of type `T` as context about this error.
#[unstable(feature = "error_generic_member_access", issue = "99301")]
pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
- <dyn Error + 'static>::request_ref(self)
+ <dyn Error>::request_ref(self)
}
/// Request a value of type `T` as context about this error.
#[unstable(feature = "error_generic_member_access", issue = "99301")]
pub fn request_value<T: 'static>(&self) -> Option<T> {
- <dyn Error + 'static>::request_value(self)
+ <dyn Error>::request_value(self)
}
}
/// Request a reference of type `T` as context about this error.
#[unstable(feature = "error_generic_member_access", issue = "99301")]
pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
- <dyn Error + 'static>::request_ref(self)
+ <dyn Error>::request_ref(self)
}
/// Request a value of type `T` as context about this error.
#[unstable(feature = "error_generic_member_access", issue = "99301")]
pub fn request_value<T: 'static>(&self) -> Option<T> {
- <dyn Error + 'static>::request_value(self)
+ <dyn Error>::request_value(self)
}
}
///
/// ```rust
/// #![feature(error_reporter)]
- /// #![feature(backtrace)]
+ /// #![feature(provide_any)]
+ /// #![feature(error_generic_member_access)]
/// # use std::error::Error;
/// # use std::fmt;
+ /// use std::any::Demand;
/// use std::error::Report;
/// use std::backtrace::Backtrace;
///
/// }
///
/// impl Error for SuperErrorSideKick {
- /// fn backtrace(&self) -> Option<&Backtrace> {
- /// Some(&self.backtrace)
+ /// fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+ /// req
+ /// .provide_ref::<Backtrace>(&self.backtrace);
/// }
/// }
///
fn backtrace(&self) -> Option<&Backtrace> {
// have to grab the backtrace on the first error directly since that error may not be
// 'static
- let backtrace = self.error.backtrace();
+ let backtrace = (&self.error as &dyn Error).request_ref();
let backtrace = backtrace.or_else(|| {
self.error
.source()
- .map(|source| source.chain().find_map(|source| source.backtrace()))
+ .map(|source| source.chain().find_map(|source| source.request_ref()))
.flatten()
});
backtrace
fn backtrace(&self) -> Option<&Backtrace> {
// have to grab the backtrace on the first error directly since that error may not be
// 'static
- let backtrace = self.error.backtrace();
+ let backtrace = self.error.request_ref();
let backtrace = backtrace.or_else(|| {
self.error
.source()
- .map(|source| source.chain().find_map(|source| source.backtrace()))
+ .map(|source| source.chain().find_map(|source| source.request_ref()))
.flatten()
});
backtrace
use super::Error;
use crate::fmt;
+use core::any::Demand;
#[derive(Debug, PartialEq)]
struct A;
self.source.as_deref()
}
- fn backtrace(&self) -> Option<&Backtrace> {
- self.backtrace.as_ref()
+ fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+ self.backtrace.as_ref().map(|bt| req.provide_ref::<Backtrace>(bt));
}
}
#![cfg_attr(bootstrap, feature(let_chains))]
#![feature(let_else)]
#![feature(linkage)]
+#![feature(link_cfg)]
#![feature(min_specialization)]
#![feature(must_not_suspend)]
#![feature(needs_panic_runtime)]
custom_flags: i32,
}
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {}
+
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FilePermissions(c_short);
}
}
+impl FileTimes {
+ pub fn set_accessed(&mut self, _t: SystemTime) {}
+ pub fn set_modified(&mut self, _t: SystemTime) {}
+}
+
impl FileType {
pub fn is_dir(&self) -> bool {
self.is(abi::S_IFDIR)
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
unsupported()
}
+
+ pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+ unsupported()
+ }
}
impl Drop for File {
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))
+ let (addr, len) = addr.into_inner();
+ cvt(netc::connect(self.0.raw(), addr.as_ptr(), len))
};
self.set_nonblocking(false)?;
fn default() -> Self {
// Redox doesn't appear to support `UTIME_OMIT`, so we stub it out here, and always return
// an error in `set_times`.
- #[cfg(target_os = "redox")]
+ // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore
+ // the same as for Redox.
+ #[cfg(any(target_os = "redox", target_os = "espidf"))]
let omit = libc::timespec { tv_sec: 0, tv_nsec: 0 };
- #[cfg(not(target_os = "redox"))]
+ #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
let omit = libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ };
Self([omit; 2])
}
impl Drop for Dir {
fn drop(&mut self) {
let r = unsafe { libc::closedir(self.0) };
- debug_assert_eq!(r, 0);
+ assert!(
+ r == 0 || crate::io::Error::last_os_error().kind() == crate::io::ErrorKind::Interrupted,
+ "unexpected error during closedir: {:?}",
+ crate::io::Error::last_os_error()
+ );
}
}
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
cfg_if::cfg_if! {
- if #[cfg(target_os = "redox")] {
+ if #[cfg(any(target_os = "redox", target_os = "espidf"))] {
// Redox doesn't appear to support `UTIME_OMIT`.
+ // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore
+ // the same as for Redox.
drop(times);
Err(io::const_io_error!(
io::ErrorKind::Unsupported,
let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
let stable_now = Instant::now();
let r = libc::gettimeofday(&mut sys_now, ptr::null_mut());
- debug_assert_eq!(r, 0);
+ assert_eq!(r, 0, "unexpected error: {:?}", crate::io::Error::last_os_error());
let nsec = dur.subsec_nanos() as libc::c_long + (sys_now.tv_usec * 1000) as libc::c_long;
let extra = (nsec / 1_000_000_000) as libc::time_t;
cfg_if::cfg_if! {
if #[cfg(target_os = "android")] {
- #[link(name = "dl")]
- #[link(name = "log")]
+ #[link(name = "dl", kind = "static", modifiers = "-bundle",
+ cfg(target_feature = "crt-static"))]
+ #[link(name = "dl", cfg(not(target_feature = "crt-static")))]
+ #[link(name = "log", cfg(not(target_feature = "crt-static")))]
extern "C" {}
} else if #[cfg(target_os = "freebsd")] {
#[link(name = "execinfo")]
-use crate::mem;
-use crate::slice;
-
pub fn hashmap_random_keys() -> (u64, u64) {
- let mut v = (0, 0);
- unsafe {
- let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, mem::size_of_val(&v));
- imp::fill_bytes(view);
- }
- v
+ const KEY_LEN: usize = core::mem::size_of::<u64>();
+
+ let mut v = [0u8; KEY_LEN * 2];
+ imp::fill_bytes(&mut v);
+
+ let key1 = v[0..KEY_LEN].try_into().unwrap();
+ let key2 = v[KEY_LEN..].try_into().unwrap();
+
+ (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
}
#[cfg(all(
debug_assert_eq!(ret, 0);
}
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(target_os = "android")]
pub fn set_name(name: &CStr) {
const PR_SET_NAME: libc::c_int = 15;
- // pthread wrapper only appeared in glibc 2.12, so we use syscall
- // directly.
unsafe {
libc::prctl(
PR_SET_NAME,
}
}
+ #[cfg(target_os = "linux")]
+ pub fn set_name(name: &CStr) {
+ unsafe {
+ // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20.
+ libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
+ }
+ }
+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
pub fn set_name(name: &CStr) {
unsafe {
fn next(&mut self) -> Option<&'a OsStr> {
None
}
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, Some(0))
+ }
}
impl<'a> ExactSizeIterator for CommandArgs<'a> {}
#[path = "../unix/locks"]
pub mod locks {
#![allow(unsafe_op_in_unsafe_fn)]
- mod futex;
+ mod futex_condvar;
+ mod futex_mutex;
mod futex_rwlock;
- pub(crate) use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
+ pub(crate) use futex_condvar::{Condvar, MovableCondvar};
+ pub(crate) use futex_mutex::{Mutex, MovableMutex};
pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
}
#[path = "atomics/futex.rs"]
}
}
-compat_fn_optional! {
+compat_fn_with_fallback! {
pub static SYNCH_API: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0");
-
- // >= Windows 8 / Server 2012
- // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress
- pub fn WaitOnAddress(
- Address: LPVOID,
- CompareAddress: LPVOID,
- AddressSize: SIZE_T,
- dwMilliseconds: DWORD
- ) -> BOOL;
- pub fn WakeByAddressSingle(Address: LPVOID) -> ();
+ #[allow(unused)]
+ fn WakeByAddressSingle(Address: LPVOID) -> () {
+ // This fallback is currently tightly coupled to its use in Parker::unpark.
+ //
+ // FIXME: If `WakeByAddressSingle` needs to be used anywhere other than
+ // Parker::unpark then this fallback will be wrong and will need to be decoupled.
+ crate::sys::windows::thread_parker::unpark_keyed_event(Address)
+ }
}
+pub use crate::sys::compat::WaitOnAddress;
+// Change exported name of `WakeByAddressSingle` to make the strange fallback
+// behaviour clear.
+pub use WakeByAddressSingle::call as wake_by_address_single_or_unpark_keyed_event;
compat_fn_with_fallback! {
pub static NTDLL: &CStr = ansi_str!("ntdll");
//! `GetModuleHandle` and `GetProcAddress` to look up DLL entry points at
//! runtime.
//!
-//! This implementation uses a static initializer to look up the DLL entry
-//! points. The CRT (C runtime) executes static initializers before `main`
-//! is called (for binaries) and before `DllMain` is called (for DLLs).
-//! This is the ideal time to look up DLL imports, because we are guaranteed
-//! that no other threads will attempt to call these entry points. Thus,
-//! we can look up the imports and store them in `static mut` fields
-//! without any synchronization.
+//! This is implemented simply by storing a function pointer in an atomic.
+//! Loading and calling this function will have little or no overhead
+//! compared with calling any other dynamically imported function.
//!
-//! This has an additional advantage: Because the DLL import lookup happens
-//! at module initialization, the cost of these lookups is deterministic,
-//! and is removed from the code paths that actually call the DLL imports.
-//! That is, there is no unpredictable "cache miss" that occurs when calling
-//! a DLL import. For applications that benefit from predictable delays,
-//! this is a benefit. This also eliminates the comparison-and-branch
-//! from the hot path.
-//!
-//! Currently, the standard library uses only a small number of dynamic
-//! DLL imports. If this number grows substantially, then the cost of
-//! performing all of the lookups at initialization time might become
-//! substantial.
-//!
-//! The mechanism of registering a static initializer with the CRT is
-//! documented in
-//! [CRT Initialization](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-160).
-//! It works by contributing a global symbol to the `.CRT$XCU` section.
-//! The linker builds a table of all static initializer functions.
-//! The CRT startup code then iterates that table, calling each
-//! initializer function.
-//!
-//! # **WARNING!!*
-//! The environment that a static initializer function runs in is highly
-//! constrained. There are **many** restrictions on what static initializers
-//! can safely do. Static initializer functions **MUST NOT** do any of the
-//! following (this list is not comprehensive):
-//! * touch any other static field that is used by a different static
-//! initializer, because the order that static initializers run in
-//! is not defined.
-//! * call `LoadLibrary` or any other function that acquires the DLL
-//! loader lock.
-//! * call any Rust function or CRT function that touches any static
-//! (global) state.
+//! The stored function pointer starts out as an importer function which will
+//! swap itself with the real function when it's called for the first time. If
+//! the real function can't be imported then a fallback function is used in its
+//! place. While this is low cost for the happy path (where the function is
+//! already loaded) it does mean there's some overhead the first time the
+//! function is called. In the worst case, multiple threads may all end up
+//! importing the same function unnecessarily.
use crate::ffi::{c_void, CStr};
use crate::ptr::NonNull;
unsafe { crate::ffi::CStr::from_bytes_with_nul_unchecked(bytes) }
}
-#[used]
-#[link_section = ".CRT$XCU"]
-static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init;
-
-/// This is where the magic preloading of symbols happens.
-///
-/// Note that any functions included here will be unconditionally included in
-/// the final binary, regardless of whether or not they're actually used.
-///
-/// Therefore, this is limited to `compat_fn_optional` functions which must be
-/// preloaded and any functions which may be more time sensitive, even for the first call.
-unsafe extern "C" fn init() {
- // There is no locking here. This code is executed before main() is entered, and
- // is guaranteed to be single-threaded.
- //
- // DO NOT do anything interesting or complicated in this function! DO NOT call
- // any Rust functions or CRT functions if those functions touch any global state,
- // because this function runs during global initialization. For example, DO NOT
- // do any dynamic allocation, don't call LoadLibrary, etc.
-
- if let Some(synch) = Module::new(c::SYNCH_API) {
- // These are optional and so we must manually attempt to load them
- // before they can be used.
- c::WaitOnAddress::preload(synch);
- c::WakeByAddressSingle::preload(synch);
- }
-
- if let Some(kernel32) = Module::new(c::KERNEL32) {
- // Preloading this means getting a precise time will be as fast as possible.
- c::GetSystemTimePreciseAsFileTime::preload(kernel32);
- }
-}
-
/// Represents a loaded module.
///
/// Note that the modules std depends on must not be unloaded.
macro_rules! compat_fn_with_fallback {
(pub static $module:ident: &CStr = $name:expr; $(
$(#[$meta:meta])*
- pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block
+ $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block
)*) => (
pub static $module: &CStr = $name;
$(
$fallback_body
}
- #[allow(unused)]
- pub(in crate::sys) fn preload(module: Module) {
- load_from_module(Some(module));
- }
-
#[inline(always)]
pub unsafe fn call($($argname: $argtype),*) -> $rettype {
let func: F = mem::transmute(PTR.load(Ordering::Relaxed));
}
}
$(#[$meta])*
- pub use $symbol::call as $symbol;
+ $vis use $symbol::call as $symbol;
)*)
}
-/// A function that either exists or doesn't.
+/// Optionally load `WaitOnAddress`.
+/// Unlike the dynamic loading described above, this does not have a fallback.
///
-/// NOTE: Optional functions must be preloaded in the `init` function above, or they will always be None.
-macro_rules! compat_fn_optional {
- (pub static $module:ident: &CStr = $name:expr; $(
- $(#[$meta:meta])*
- pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty;
- )*) => (
- pub static $module: &CStr = $name;
- $(
- $(#[$meta])*
- pub mod $symbol {
- #[allow(unused_imports)]
- use super::*;
- use crate::mem;
- use crate::sync::atomic::{AtomicPtr, Ordering};
- use crate::sys::compat::Module;
- use crate::ptr::{self, NonNull};
-
- type F = unsafe extern "system" fn($($argtype),*) -> $rettype;
-
- /// `PTR` will either be `null()` or set to the loaded function.
- static PTR: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
-
- /// Only allow access to the function if it has loaded successfully.
- #[inline(always)]
- #[cfg(not(miri))]
- pub fn option() -> Option<F> {
- unsafe {
- NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| mem::transmute(f))
- }
- }
-
- // Miri does not understand the way we do preloading
- // therefore load the function here instead.
- #[cfg(miri)]
- pub fn option() -> Option<F> {
- let mut func = NonNull::new(PTR.load(Ordering::Relaxed));
- if func.is_none() {
- unsafe { Module::new($module).map(preload) };
- func = NonNull::new(PTR.load(Ordering::Relaxed));
- }
- unsafe {
- func.map(|f| mem::transmute(f))
- }
- }
+/// This is rexported from sys::c. You should prefer to import
+/// from there in case this changes again in the future.
+pub mod WaitOnAddress {
+ use super::*;
+ use crate::mem;
+ use crate::ptr;
+ use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
+ use crate::sys::c;
+
+ static MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0");
+ static SYMBOL_NAME: &CStr = ansi_str!("WaitOnAddress");
+
+ // WaitOnAddress function signature.
+ type F = unsafe extern "system" fn(
+ Address: c::LPVOID,
+ CompareAddress: c::LPVOID,
+ AddressSize: c::SIZE_T,
+ dwMilliseconds: c::DWORD,
+ );
+
+ // A place to store the loaded function atomically.
+ static WAIT_ON_ADDRESS: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
+
+ // We can skip trying to load again if we already tried.
+ static LOAD_MODULE: AtomicBool = AtomicBool::new(true);
+
+ #[inline(always)]
+ pub fn option() -> Option<F> {
+ let f = WAIT_ON_ADDRESS.load(Ordering::Acquire);
+ if !f.is_null() { Some(unsafe { mem::transmute(f) }) } else { try_load() }
+ }
- #[allow(unused)]
- pub(in crate::sys) fn preload(module: Module) {
- unsafe {
- static SYMBOL_NAME: &CStr = ansi_str!(sym $symbol);
- if let Some(f) = module.proc_address(SYMBOL_NAME) {
- PTR.store(f.as_ptr(), Ordering::Relaxed);
- }
- }
+ #[cold]
+ fn try_load() -> Option<F> {
+ if LOAD_MODULE.load(Ordering::Acquire) {
+ // load the module
+ let mut wait_on_address = None;
+ if let Some(func) = try_load_inner() {
+ WAIT_ON_ADDRESS.store(func.as_ptr(), Ordering::Release);
+ wait_on_address = Some(unsafe { mem::transmute(func) });
}
+ // Don't try to load the module again even if loading failed.
+ LOAD_MODULE.store(false, Ordering::Release);
+ wait_on_address
+ } else {
+ None
}
- )*)
+ }
+
+ // In the future this could be a `try` block but until then I think it's a
+ // little bit cleaner as a separate function.
+ fn try_load_inner() -> Option<NonNull<c_void>> {
+ unsafe { Module::new(MODULE_NAME)?.proc_address(SYMBOL_NAME) }
+ }
}
use crate::io;
use crate::mem;
-use crate::sync;
+use crate::ptr;
use crate::sys::c;
-/// The kinds of HashMap RNG that may be available
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum HashMapRng {
- Preferred,
- Fallback,
-}
-
pub fn hashmap_random_keys() -> (u64, u64) {
- match get_hashmap_rng() {
- HashMapRng::Preferred => {
- preferred_rng().expect("couldn't generate random bytes with preferred RNG")
- }
- HashMapRng::Fallback => {
- fallback_rng().expect("couldn't generate random bytes with fallback RNG")
- }
- }
-}
-
-/// Returns the HashMap RNG that should be used
-///
-/// Panics if they are both broken
-fn get_hashmap_rng() -> HashMapRng {
- // Assume that if the preferred RNG is broken the first time we use it, it likely means
- // that: the DLL has failed to load, there is no point to calling it over-and-over again,
- // and we should cache the result
- static VALUE: sync::OnceLock<HashMapRng> = sync::OnceLock::new();
- *VALUE.get_or_init(choose_hashmap_rng)
-}
-
-/// Test whether we should use the preferred or fallback RNG
-///
-/// If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
-/// we choose that
-///
-/// Panics if both the preferred and the fallback RNG are both non-functional
-fn choose_hashmap_rng() -> HashMapRng {
- let preferred_error = match preferred_rng() {
- Ok(_) => return HashMapRng::Preferred,
- Err(e) => e,
- };
-
- match fallback_rng() {
- Ok(_) => return HashMapRng::Fallback,
- Err(fallback_error) => panic!(
- "preferred RNG broken: `{}`, fallback RNG broken: `{}`",
- preferred_error, fallback_error
- ),
- }
-}
-
-/// Generate random numbers using the preferred RNG function (BCryptGenRandom)
-fn preferred_rng() -> Result<(u64, u64), io::Error> {
- use crate::ptr;
-
let mut v = (0, 0);
let ret = unsafe {
c::BCryptGenRandom(
c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
)
};
-
- if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+ if ret != 0 { fallback_rng() } else { v }
}
/// Generate random numbers using the fallback RNG function (RtlGenRandom)
#[cfg(not(target_vendor = "uwp"))]
-fn fallback_rng() -> Result<(u64, u64), io::Error> {
+#[inline(never)]
+fn fallback_rng() -> (u64, u64) {
let mut v = (0, 0);
let ret =
unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };
- if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+ if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) }
}
/// We can't use RtlGenRandom with UWP, so there is no fallback
#[cfg(target_vendor = "uwp")]
-fn fallback_rng() -> Result<(u64, u64), io::Error> {
- Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP"))
+#[inline(never)]
+fn fallback_rng() -> (u64, u64) {
+ panic!("fallback RNG broken: RtlGenRandom() not supported on UWP");
}
// purpose, to make sure every unpark() has a release-acquire ordering
// with park().
if self.state.swap(NOTIFIED, Release) == PARKED {
- if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() {
- unsafe {
- wake_by_address_single(self.ptr());
- }
- } else {
- // If we run NtReleaseKeyedEvent before the waiting thread runs
- // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
- // If the waiting thread wakes up before we run NtReleaseKeyedEvent
- // (e.g. due to a timeout), this blocks until we do wake up a thread.
- // To prevent this thread from blocking indefinitely in that case,
- // park_impl() will, after seeing the state set to NOTIFIED after
- // waking up, call NtWaitForKeyedEvent again to unblock us.
- unsafe {
- c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
- }
+ unsafe {
+ // This calls either WakeByAddressSingle or unpark_keyed_event (see below).
+ c::wake_by_address_single_or_unpark_keyed_event(self.ptr());
}
}
}
}
}
+// This function signature makes it compatible with c::WakeByAddressSingle
+// so that it can be used as a fallback for that function.
+pub unsafe extern "C" fn unpark_keyed_event(address: c::LPVOID) {
+ // If we run NtReleaseKeyedEvent before the waiting thread runs
+ // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
+ // If the waiting thread wakes up before we run NtReleaseKeyedEvent
+ // (e.g. due to a timeout), this blocks until we do wake up a thread.
+ // To prevent this thread from blocking indefinitely in that case,
+ // park_impl() will, after seeing the state set to NOTIFIED after
+ // waking up, call NtWaitForKeyedEvent again to unblock us.
+ c::NtReleaseKeyedEvent(keyed_event_handle(), address, 0, ptr::null_mut());
+}
+
fn keyed_event_handle() -> c::HANDLE {
const INVALID: c::HANDLE = ptr::invalid_mut(!0);
static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
use crate::str;
use crate::sync::Arc;
use crate::sys::thread as imp;
-use crate::sys_common::mutex;
use crate::sys_common::thread;
use crate::sys_common::thread_info;
use crate::sys_common::thread_parker::Parker;
impl ThreadId {
// Generate a new unique thread ID.
fn new() -> ThreadId {
- // It is UB to attempt to acquire this mutex reentrantly!
- static GUARD: mutex::StaticMutex = mutex::StaticMutex::new();
- static mut COUNTER: u64 = 1;
-
- unsafe {
- let guard = GUARD.lock();
-
- // If we somehow use up all our bits, panic so that we're not
- // covering up subtle bugs of IDs being reused.
- if COUNTER == u64::MAX {
- drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
- panic!("failed to generate unique thread ID: bitspace exhausted");
- }
-
- let id = COUNTER;
- COUNTER += 1;
+ #[cold]
+ fn exhausted() -> ! {
+ panic!("failed to generate unique thread ID: bitspace exhausted")
+ }
- ThreadId(NonZeroU64::new(id).unwrap())
+ cfg_if::cfg_if! {
+ if #[cfg(target_has_atomic = "64")] {
+ use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
+
+ static COUNTER: AtomicU64 = AtomicU64::new(0);
+
+ let mut last = COUNTER.load(Relaxed);
+ loop {
+ let Some(id) = last.checked_add(1) else {
+ exhausted();
+ };
+
+ match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
+ Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()),
+ Err(id) => last = id,
+ }
+ }
+ } else {
+ use crate::sys_common::mutex::StaticMutex;
+
+ // It is UB to attempt to acquire this mutex reentrantly!
+ static GUARD: StaticMutex = StaticMutex::new();
+ static mut COUNTER: u64 = 0;
+
+ unsafe {
+ let guard = GUARD.lock();
+
+ let Some(id) = COUNTER.checked_add(1) else {
+ drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
+ exhausted();
+ };
+
+ COUNTER = id;
+ drop(guard);
+ ThreadId(NonZeroU64::new(id).unwrap())
+ }
+ }
}
}
/// Creates a TermInfo for the named terminal.
pub(crate) fn from_name(name: &str) -> Result<TermInfo, Error> {
+ if cfg!(miri) {
+ // Avoid all the work of parsing the terminfo (it's pretty slow under Miri), and just
+ // assume that the standard color codes work (like e.g. the 'colored' crate).
+ return Ok(TermInfo {
+ names: Default::default(),
+ bools: Default::default(),
+ numbers: Default::default(),
+ strings: Default::default(),
+ });
+ }
+
get_dbpath_for_term(name)
.ok_or_else(|| {
Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found"))
impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
fn fg(&mut self, color: color::Color) -> io::Result<bool> {
let color = self.dim_if_necessary(color);
+ if cfg!(miri) && color < 8 {
+ // The Miri logic for this only works for the most basic 8 colors, which we just assume
+ // the terminal will support. (`num_colors` is always 0 in Miri, so higher colors will
+ // just fail. But libtest doesn't use any higher colors anyway.)
+ return write!(self.out, "\x1B[3{color}m").and(Ok(true));
+ }
if self.num_colors > color {
return self.apply_cap("setaf", &[Param::Number(color as i32)]);
}
}
fn reset(&mut self) -> io::Result<bool> {
+ if cfg!(miri) {
+ return write!(self.out, "\x1B[0m").and(Ok(true));
+ }
// are there any terminals that have color/attrs and not sgr0?
// Try falling back to sgr, then op
let cmd = match ["sgr0", "sgr", "op"].iter().find_map(|cap| self.ti.strings.get(*cap)) {
let has_unwind = build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
if has_unwind {
- println!("cargo:rustc-link-lib=unwind");
- } else {
- println!("cargo:rustc-link-lib=gcc");
+ println!("cargo:rustc-cfg=feature=\"system-llvm-libunwind\"");
}
-
- // Android's unwinding library depends on dl_iterate_phdr in `libdl`.
- println!("cargo:rustc-link-lib=dl");
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("netbsd") {
}
}
+#[cfg(target_os = "android")]
+cfg_if::cfg_if! {
+ if #[cfg(feature = "llvm-libunwind")] {
+ compile_error!("`llvm-libunwind` is not supported for Android targets");
+ } else if #[cfg(feature = "system-llvm-libunwind")] {
+ #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+ #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
+ extern "C" {}
+ } else {
+ #[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+ #[link(name = "gcc", cfg(not(target_feature = "crt-static")))]
+ extern "C" {}
+ }
+}
+// Android's unwinding library depends on dl_iterate_phdr in `libdl`.
+#[cfg(target_os = "android")]
+#[link(name = "dl", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+#[link(name = "dl", cfg(not(target_feature = "crt-static")))]
+extern "C" {}
+
// When building with crt-static, we get `gcc_eh` from the `libc` crate, since
// glibc needs it, and needs it listed later on the linker command line. We
// don't want to duplicate it here.
config.stage = 0;
config.cmd = Subcommand::Test {
paths: vec!["library/std".into()],
- skip: vec![],
test_args: vec![],
rustc_args: vec![],
fail_fast: true,
let mut config = configure(&["A"], &["A"]);
config.cmd = Subcommand::Test {
paths: vec![],
- skip: vec![],
test_args: vec![],
rustc_args: vec![],
fail_fast: true,
cargo_subcommand(builder.kind),
);
- cargo.arg("--all-targets");
+ // If we're not in stage 0, tests and examples will fail to compile
+ // from `core` definitions being loaded from two different `libcore`
+ // .rmeta and .rlib files.
+ if compiler.stage == 0 {
+ cargo.arg("--all-targets");
+ }
+
std_cargo(builder, target, compiler.stage, &mut cargo);
// Explicitly pass -p for all dependencies krates -- this will force cargo
compare_mode: Option<String>,
pass: Option<String>,
run: Option<String>,
- skip: Vec<String>,
test_args: Vec<String>,
rustc_args: Vec<String>,
fail_fast: bool,
compare_mode: matches.opt_str("compare-mode"),
pass: matches.opt_str("pass"),
run: matches.opt_str("run"),
- skip: matches.opt_strs("skip"),
test_args: matches.opt_strs("test-args"),
rustc_args: matches.opt_strs("rustc-args"),
fail_fast: !matches.opt_present("no-fail-fast"),
pub fn test_args(&self) -> Vec<&str> {
let mut args = vec![];
- match *self {
- Subcommand::Test { ref skip, .. } => {
- for s in skip {
- args.push("--skip");
- args.push(s.as_str());
- }
- }
- _ => (),
- };
-
match *self {
Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
args.extend(test_args.iter().flat_map(|s| s.split_whitespace()))
/// If any submodule has been initialized already, sync it unconditionally.
/// This avoids contributors checking in a submodule change by accident.
pub fn maybe_update_submodules(&self) {
- // WARNING: keep this in sync with the submodules hard-coded in bootstrap.py
- let mut bootstrap_submodules: Vec<&str> = vec![
- "src/tools/rust-installer",
- "src/tools/cargo",
- "src/tools/rls",
- "src/tools/miri",
- "library/backtrace",
- "library/stdarch",
- ];
- // As in bootstrap.py, we include `rust-analyzer` if `build.vendor` was set in
- // `config.toml`.
- if self.config.vendor {
- bootstrap_submodules.push("src/tools/rust-analyzer");
- }
// Avoid running git when there isn't a git checkout.
if !self.config.submodules(&self.rust_info) {
return;
// Look for `submodule.$name.path = $path`
// Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap());
- // avoid updating submodules twice
- if !bootstrap_submodules.iter().any(|&p| Path::new(p) == submodule)
- && channel::GitInfo::new(false, submodule).is_git()
- {
+ // Don't update the submodule unless it's already been cloned.
+ if channel::GitInfo::new(false, submodule).is_git() {
self.update_submodule(submodule);
}
}
/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.)
/// If the test is running and code is an error code, it will cause a panic.
fn detail_exit(code: i32) -> ! {
- // Successful exit
- if code == 0 {
- std::process::exit(0);
- }
- if cfg!(test) {
+ // if in test and code is an error code, panic with staus code provided
+ if cfg!(test) && code != 0 {
panic!("status code: {}", code);
} else {
- std::panic::resume_unwind(Box::new(code));
+ //otherwise,exit with provided status code
+ std::process::exit(code);
}
}
src/test/ui \
src/tools/linkchecker
+## MSVC native builders
+
+# these intentionally don't use `$(BOOTSTRAP)` so we can test the shebang on Windows
ci-subset-1:
- $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2:%=--exclude %)
+ $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 $(TESTS_IN_2:%=--exclude %)
ci-subset-2:
- $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2)
+ $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 $(TESTS_IN_2)
+
+## MingW native builders
TESTS_IN_MINGW_2 := \
src/test/ui
ci-mingw-subset-1:
- $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %)
+ $(Q)$(CFG_SRC_DIR)/x.sh test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %)
ci-mingw-subset-2:
$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2)
cfg.define("LLVM_PROFDATA_FILE", &path);
}
+ // Disable zstd to avoid a dependency on libzstd.so.
+ cfg.define("LLVM_ENABLE_ZSTD", "OFF");
+
if target != "aarch64-apple-darwin" && !target.contains("windows") {
cfg.define("LLVM_ENABLE_ZLIB", "ON");
} else {
cfg.define("LLVM_ENABLE_ZLIB", "OFF");
}
- if builder.config.llvm_thin_lto {
- cfg.define("LLVM_ENABLE_LTO", "Thin");
- if !target.contains("apple") {
- cfg.define("LLVM_ENABLE_LLD", "ON");
- }
- }
-
// This setting makes the LLVM tools link to the dynamic LLVM library,
// which saves both memory during parallel links and overall disk space
// for the tools. We don't do this on every platform as it doesn't work
cfg.define("LLVM_VERSION_SUFFIX", suffix);
}
- if let Some(ref linker) = builder.config.llvm_use_linker {
- cfg.define("LLVM_USE_LINKER", linker);
- }
-
- if builder.config.llvm_allow_old_toolchain {
- cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
- }
-
configure_cmake(builder, target, &mut cfg, true, ldflags);
+ configure_llvm(builder, target, &mut cfg);
for (key, val) in &builder.config.llvm_build_config {
cfg.define(key, val);
}
}
+fn configure_llvm(builder: &Builder<'_>, target: TargetSelection, cfg: &mut cmake::Config) {
+ // ThinLTO is only available when building with LLVM, enabling LLD is required.
+ // Apple's linker ld64 supports ThinLTO out of the box though, so don't use LLD on Darwin.
+ if builder.config.llvm_thin_lto {
+ cfg.define("LLVM_ENABLE_LTO", "Thin");
+ if !target.contains("apple") {
+ cfg.define("LLVM_ENABLE_LLD", "ON");
+ }
+ }
+
+ if let Some(ref linker) = builder.config.llvm_use_linker {
+ cfg.define("LLVM_USE_LINKER", linker);
+ }
+
+ if builder.config.llvm_allow_old_toolchain {
+ cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
+ }
+}
+
// Adapted from https://github.com/alexcrichton/cc-rs/blob/fba7feded71ee4f63cfe885673ead6d7b4f2f454/src/lib.rs#L2347-L2365
fn get_var(var_base: &str, host: &str, target: &str) -> Option<OsString> {
let kind = if host == target { "HOST" } else { "TARGET" };
}
configure_cmake(builder, target, &mut cfg, true, ldflags);
+ configure_llvm(builder, target, &mut cfg);
// This is an awful, awful hack. Discovered when we migrated to using
// clang-cl to compile LLVM/LLD it turns out that LLD, when built out of
.define("LLVM_CONFIG_PATH", llvm_config_shim)
.define("LLVM_INCLUDE_TESTS", "OFF");
- if builder.config.llvm_allow_old_toolchain {
- cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
- }
-
// While we're using this horrible workaround to shim the execution of
// llvm-config, let's just pile on more. I can't seem to figure out how
// to build LLD as a standalone project and also cross-compile it at the
// Don't run cross-compile tests, we may not have cross-compiled libstd libs
// available.
cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
- // Disable a test that has issues with mingw.
- cargo.env("CARGO_TEST_DISABLE_GIT_CLI", "1");
// Forcibly disable tests using nightly features since any changes to
// those features won't be able to land.
cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
cargo.env("MIRI_HOST_SYSROOT", sysroot);
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
cargo.env("MIRI", miri);
+ // propagate --bless
+ if builder.config.cmd.bless() {
+ cargo.env("MIRI_BLESS", "Gesundheit");
+ }
cargo.arg("--").args(builder.config.cmd.test_args());
one used in the CI (`{}`)",
installed_version, v
);
+ eprintln!(
+ "You can install this version using `npm update browser-ui-test` or by using \
+ `npm install browser-ui-test@{}`",
+ v,
+ );
}
}
Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e),
cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
}
+ for exclude in &builder.config.exclude {
+ cmd.arg("--skip");
+ cmd.arg(&exclude.path);
+ }
+
// Get paths from cmd args
let paths = match &builder.config.cmd {
Subcommand::Test { ref paths, .. } => &paths[..],
a transitive dependency has different features activated \
than in a previous build:\n"
);
- eprintln!(
- "the following dependencies are duplicated although they \
- have the same features enabled:"
- );
let (same, different): (Vec<_>, Vec<_>) =
duplicates.into_iter().partition(|(_, cur, prev)| cur.2 == prev.2);
- for (id, cur, prev) in same {
- eprintln!(" {}", id);
- // same features
- eprintln!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1);
- }
- eprintln!("the following dependencies have different features:");
- for (id, cur, prev) in different {
- eprintln!(" {}", id);
- let cur_features: HashSet<_> = cur.2.into_iter().collect();
- let prev_features: HashSet<_> = prev.2.into_iter().collect();
- eprintln!(
- " `{}` additionally enabled features {:?} at {:?}",
- cur.0,
- &cur_features - &prev_features,
- cur.1
- );
+ if !same.is_empty() {
eprintln!(
- " `{}` additionally enabled features {:?} at {:?}",
- prev.0,
- &prev_features - &cur_features,
- prev.1
+ "the following dependencies are duplicated although they \
+ have the same features enabled:"
);
+ for (id, cur, prev) in same {
+ eprintln!(" {}", id);
+ // same features
+ eprintln!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1);
+ }
+ }
+ if !different.is_empty() {
+ eprintln!("the following dependencies have different features:");
+ for (id, cur, prev) in different {
+ eprintln!(" {}", id);
+ let cur_features: HashSet<_> = cur.2.into_iter().collect();
+ let prev_features: HashSet<_> = prev.2.into_iter().collect();
+ eprintln!(
+ " `{}` additionally enabled features {:?} at {:?}",
+ cur.0,
+ &cur_features - &prev_features,
+ cur.1
+ );
+ eprintln!(
+ " `{}` additionally enabled features {:?} at {:?}",
+ prev.0,
+ &prev_features - &cur_features,
+ prev.1
+ );
+ }
}
eprintln!();
eprintln!(
For targets: `aarch64-unknown-linux-gnu`
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
- Target options > Target Architecture = arm
- Target options > Bitness = 64-bit
- Operating System > Target OS = linux
-- Operating System > Linux kernel version = 4.2.6
+- Operating System > Linux kernel version = 4.1.49
+- Binary utilities > Version of binutils = 2.32
- C-library > glibc version = 2.17 -- aarch64 support was introduced in this version
-- C compiler > gcc version = 5.2.0
+- C compiler > gcc version = 8.3.0
- C compiler > C++ = ENABLE -- to cross compile LLVM
### `powerpc-linux-gnu.config`
For targets: `powerpc-unknown-linux-gnu`
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
- Target options > Target Architecture = powerpc
- Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC
- Operating System > Target OS = linux
-- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
-- C compiler > gcc version = 5.2.0
+- Operating System > Linux kernel version = 3.2.101
+- Binary utilities > Version of binutils = 2.30
+- C-library > glibc version = 2.17 -- ~RHEL7 glibc
+- C compiler > gcc version = 8.3.0
- C compiler > C++ = ENABLE -- to cross compile LLVM
### `powerpc64-linux-gnu.config`
For targets: `powerpc64-unknown-linux-gnu`
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
- Target options > Target Architecture = powerpc
- Target options > Bitness = 64-bit
- Target options > Emit assembly for CPU = power4 -- (+)
- Target options > Tune for CPU = power6 -- (+)
- Operating System > Target OS = linux
-- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
-- C compiler > gcc version = 5.2.0
+- Operating System > Linux kernel version = 3.2.101
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.17 -- ~RHEL7 glibc
+- C compiler > gcc version = 8.3.0
- C compiler > C++ = ENABLE -- to cross compile LLVM
(+) These CPU options match the configuration of the toolchains in RHEL6.
For targets: `s390x-unknown-linux-gnu`
- Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
- Target options > Target Architecture = s390
- Target options > Bitness = 64-bit
- Operating System > Target OS = linux
-- Operating System > Linux kernel version = 2.6.32.71 -- ~RHEL6 kernel
-- C-library > glibc version = 2.12.1 -- ~RHEL6 glibc
+- Operating System > Linux kernel version = 3.2.101
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.17 -- ~RHEL7 glibc
- C compiler > gcc version = 8.3.0
- C compiler > gcc extra config = --with-arch=z10 -- LLVM's minimum support
- C compiler > C++ = ENABLE -- to cross compile LLVM
ENV TARGETS=arm-linux-androideabi
-ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14
+ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 \
+ --set llvm.allow-old-toolchain
ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
FROM ubuntu:20.04
-RUN apt-get update && \
- apt-get install -y --no-install-recommends \
- curl \
- ca-certificates
-WORKDIR /tmp
-RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
-
-FROM ubuntu:16.04
-
-# The ca-certificates in ubuntu-16 is too old, so update the certificates
-# with something more recent.
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
COPY scripts/cross-apt-packages.sh /scripts/
RUN sh /scripts/cross-apt-packages.sh
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
COPY scripts/rustbuild-setup.sh /scripts/
RUN sh /scripts/rustbuild-setup.sh
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
-ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin
+ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnu/bin
-ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \
- AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-ar \
- CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++
+ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-gcc \
+ AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-ar \
+ CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-g++
ENV HOSTS=aarch64-unknown-linux-gnu
#
# Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+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
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
CT_MODULES=y
#
#
# Paths
#
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
CT_RM_RF_PREFIX_DIR=y
CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
#
# Downloading
#
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
# CT_FORBID_DOWNLOAD is not set
# CT_FORCE_DOWNLOAD is not set
CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
# CT_ONLY_DOWNLOAD is not set
CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
#
# Extracting
#
# CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
# CT_ONLY_EXTRACT is not set
CT_PATCH_BUNDLED=y
-# CT_PATCH_LOCAL is not set
# CT_PATCH_BUNDLED_LOCAL is not set
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
CT_PATCH_ORDER="bundled"
#
#
# CT_LOG_ERROR is not set
# CT_LOG_WARN is not set
-CT_LOG_INFO=y
-# CT_LOG_EXTRA is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
# CT_LOG_ALL is not set
# CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="INFO"
+CT_LOG_LEVEL_MAX="EXTRA"
# CT_LOG_SEE_TOOLS_WARN is not set
CT_LOG_PROGRESS_BAR=y
CT_LOG_TO_FILE=y
#
# Target options
#
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+CT_ARCH_ARM=y
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+# CT_ARCH_POWERPC is not set
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
CT_ARCH="arm"
-CT_ARCH_SUPPORTS_BOTH_MMU=y
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ARCH=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_DEFAULT_HAS_MMU=y
-CT_ARCH_DEFAULT_LE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ARCH=""
+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_BE is not set
-CT_ARCH_LE=y
-# CT_ARCH_32 is not set
-CT_ARCH_64=y
-CT_ARCH_BITNESS=64
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-CT_ARCH_arm=y
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-# CT_ARCH_powerpc is not set
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_ARM_SHOW=y
+
+#
+# Options for arm
+#
+CT_ARCH_ARM_PKG_KSYM=""
+# CT_ARCH_ARM_MODE_ARM is not set
+# CT_ARCH_ARM_MODE_THUMB is not set
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
#
# Generic target options
#
# CT_MULTILIB is not set
+CT_DEMULTILIB=y
+CT_ARCH_SUPPORTS_BOTH_MMU=y
+CT_ARCH_DEFAULT_HAS_MMU=y
CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_FLAT_FORMAT=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_LE=y
+# CT_ARCH_BE is not set
+CT_ARCH_LE=y
CT_ARCH_ENDIAN="little"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=64
+# CT_ARCH_32 is not set
+CT_ARCH_64=y
#
# Target optimisations
#
+CT_ARCH_SUPPORTS_WITH_ARCH=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
CT_ARCH_EXCLUSIVE_WITH_CPU=y
-CT_ARCH_FLOAT=""
-
-#
-# arm other options
-#
-CT_ARCH_ARM_MODE="arm"
-CT_ARCH_ARM_MODE_ARM=y
-# CT_ARCH_ARM_MODE_THUMB is not set
-# CT_ARCH_ARM_INTERWORKING is not set
-CT_ARCH_ARM_EABI_FORCE=y
-CT_ARCH_ARM_EABI=y
+CT_ARCH_ARCH=""
+# CT_ARCH_FLOAT_AUTO is not set
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SOFTFP is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
#
# Toolchain options
CT_SYSROOT_NAME="sysroot"
CT_SYSROOT_DIR_PREFIX=""
CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
# CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
CT_TOOLCHAIN_PKGVERSION=""
CT_TOOLCHAIN_BUGURL=""
# Operating System
#
CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
CT_KERNEL="linux"
-CT_KERNEL_VERSION="4.2.6"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-CT_KERNEL_V_4_2=y
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-# CT_KERNEL_V_3_2 is not set
-# CT_KERNEL_V_2_6_32 is not set
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+CT_LINUX_V_4_1=y
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="4.1.49"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_later_than_3_7=y
+CT_LINUX_3_7_or_later=y
+CT_LINUX_REQUIRE_3_7_or_later=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
CT_KERNEL_LINUX_VERBOSITY_0=y
# CT_KERNEL_LINUX_VERBOSITY_1 is not set
# CT_KERNEL_LINUX_VERBOSITY_2 is not set
CT_KERNEL_LINUX_VERBOSE_LEVEL=0
CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
#
# Binary utilities
#
CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+# CT_BINUTILS_V_2_32 is not set
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+CT_BINUTILS_V_2_29=y
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.29.1"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_2_30_or_older=y
+CT_BINUTILS_older_than_2_30=y
+CT_BINUTILS_REQUIRE_older_than_2_30=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
#
# GNU binutils
#
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
CT_BINUTILS_HAS_HASH_STYLE=y
CT_BINUTILS_HAS_GOLD=y
-CT_BINUTILS_GOLD_SUPPORTS_ARCH=y
-CT_BINUTILS_GOLD_SUPPORT=y
CT_BINUTILS_HAS_PLUGINS=y
CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_GOLD_SUPPORTS_ARCH=y
+CT_BINUTILS_GOLD_SUPPORT=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
CT_BINUTILS_LINKER_LD=y
# CT_BINUTILS_LINKER_LD_GOLD is not set
-# CT_BINUTILS_LINKER_GOLD_LD is not set
CT_BINUTILS_LINKERS_LIST="ld"
CT_BINUTILS_LINKER_DEFAULT="bfd"
# CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
# CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+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_VERSION="2.17"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-CT_LIBC_GLIBC_V_2_17=y
-# CT_LIBC_GLIBC_V_2_16_0 is not set
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_GLIBC_2_17_or_later=y
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+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
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+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_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="4.1.49"
+# 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
# Common C library options
#
CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
CT_LIBC_XLDD=y
-#
-# glibc other options
-#
-# CT_LIBC_GLIBC_PORTS_EXTERNAL is not set
-CT_LIBC_GLIBC_MAY_FORCE_PORTS=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-CT_LIBC_GLIBC_USE_PORTS=y
-CT_LIBC_ADDONS_LIST=""
-
-#
-# WARNING !!!
-#
-
-#
-# For glibc >= 2.8, it can happen that the tarballs
-#
-
-#
-# for the addons are not available for download.
-#
-
-#
-# If that happens, bad luck... Try a previous version
-#
-
-#
-# or try again later... :-(
-#
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="4.2.6"
-
#
# C compiler
#
-CT_CC="gcc"
CT_CC_CORE_PASSES_NEEDED=y
CT_CC_CORE_PASS_1_NEEDED=y
CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
CT_CC_GCC_ENABLE_CXX_FLAGS=""
CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
CT_CC_GCC_STATIC_LIBSTDCXX=y
# CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
#
# Optimisation features
#
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
#
# Settings for libraries running on target
# CT_CC_GCC_DEC_FLOAT_BID is not set
# CT_CC_GCC_DEC_FLOAT_DPD is not set
# CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
#
# Additional supported languages:
#
CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
#
# Debug facilities
#
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
#
# Companion libraries
#
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# 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_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
CT_LIBICONV_NEEDED=y
CT_GETTEXT_NEEDED=y
CT_GMP_NEEDED=y
CT_MPFR_NEEDED=y
CT_ISL_NEEDED=y
CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
CT_LIBICONV=y
CT_GETTEXT=y
CT_GMP=y
CT_MPFR=y
CT_ISL=y
CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-# CT_CLOOG_V_0_18_4 is not set
-# CT_CLOOG_V_0_18_1 is not set
-# CT_CLOOG_V_0_18_0 is not set
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
#
# Companion tools
#
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
--i686-linux-android-ndk=/android/ndk/x86-14 \
--aarch64-linux-android-ndk=/android/ndk/arm64-21 \
--x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
- --disable-docs
+ --disable-docs \
+ --set llvm.allow-old-toolchain
ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin
ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin
ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin
ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \
ENV RUST_CONFIGURE_ARGS \
--musl-root-i586=/musl-i586 \
--musl-root-i686=/musl-i686 \
- --disable-docs
+ --disable-docs \
+ --set llvm.allow-old-toolchain
# Newer binutils broke things on some vms/distros (i.e., linking against
# unknown relocs disabled by the following flag), so we need to go out of our
-# We need recent curl, OpenSSL and CA certificates, so we can download further
-# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
-# those.
-FROM ubuntu:20.04
-RUN apt-get update && \
- apt-get install -y --no-install-recommends \
- curl \
- ca-certificates
-WORKDIR /tmp
-COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
-RUN ./download-openssl-curl.sh
-
-# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
-# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
-# SLES 11 SP4 (glibc 2.11, kernel 3.0).
-FROM debian:6
+# We document platform support for minimum glibc 2.17 and kernel 3.2.
+# CentOS 7 has headers for kernel 3.10, but that's fine as long as we don't
+# actually use newer APIs in rustc or std without a fallback. It's more
+# important that we match glibc for ELF symbol versioning.
+FROM centos:7
WORKDIR /build
-# Debian 6 is EOL and no longer available from the usual mirrors,
-# so we'll need to switch to http://archive.debian.org/
-RUN sed -i '/updates/d' /etc/apt/sources.list && \
- sed -i 's/httpredir/archive/' /etc/apt/sources.list
-
-RUN apt-get update && \
- apt-get install --allow-unauthenticated -y --no-install-recommends \
+RUN yum upgrade -y && \
+ yum install -y epel-release && \
+ yum install -y \
automake \
bzip2 \
file \
- g++ \
- g++-multilib \
+ cmake3 \
gcc \
- gcc-multilib \
+ gcc-c++ \
git \
- lib32z1-dev \
- libedit-dev \
- libncurses-dev \
+ glibc-devel.i686 \
+ glibc-devel.x86_64 \
+ libedit-devel \
+ libstdc++-devel.i686 \
+ libstdc++-devel.x86_64 \
make \
+ ncurses-devel \
+ openssl-devel \
patch \
perl \
- pkg-config \
+ pkgconfig \
+ python3 \
unzip \
wget \
- xz-utils \
- zlib1g-dev
+ xz \
+ zlib-devel.i686 \
+ zlib-devel.x86_64
+
+RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
ENV PATH=/rustroot/bin:$PATH
ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
RUN mkdir /home/user
COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
-# We need a build of openssl which supports SNI to download artifacts from
-# static.rust-lang.org. This'll be used to link into libcurl below (and used
-# later as well), so build a copy of OpenSSL with dynamic libraries into our
-# generic root.
-COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
-COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
-RUN ./build-openssl.sh
-
-# The `curl` binary on Debian 6 doesn't support SNI which is needed for fetching
-# some https urls we have, so install a new version of libcurl + curl which is
-# using the openssl we just built previously.
-#
-# Note that we also disable a bunch of optional features of curl that we don't
-# really need.
-COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
-COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh
-
-# Use up-to-date curl CA bundle
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
-
-# binutils < 2.22 has a bug where the 32-bit executables it generates
-# immediately segfault in Rust, so we need to install our own binutils.
-#
-# See https://github.com/rust-lang/rust/issues/20440 for more info
-COPY host-x86_64/dist-x86_64-linux/build-binutils.sh /tmp/
-RUN ./build-binutils.sh
-
# Need at least GCC 5.1 to compile LLVM nowadays
COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
-RUN ./build-gcc.sh && apt-get remove -y gcc g++
-
-COPY host-x86_64/dist-x86_64-linux/build-python.sh /tmp/
-# Build Python 3 needed for LLVM 12.
-RUN ./build-python.sh 3.9.1
-
-# LLVM needs cmake 3.13.4 or higher.
-COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
-RUN ./build-cmake.sh
+RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
# Now build LLVM+Clang, afterwards configuring further compilations to use the
# clang/clang++ compilers.
ENV HOSTS=mips-unknown-linux-gnu
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+ --set llvm.allow-old-toolchain
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
ENV HOSTS=mips64-unknown-linux-gnuabi64
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+ --set llvm.allow-old-toolchain
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
ENV HOSTS=mips64el-unknown-linux-gnuabi64
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+ --set llvm.allow-old-toolchain
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
ENV HOSTS=mipsel-unknown-linux-gnu
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+ --set llvm.allow-old-toolchain
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
-FROM ubuntu:16.04
+FROM ubuntu:20.04
COPY scripts/cross-apt-packages.sh /scripts/
RUN sh /scripts/cross-apt-packages.sh
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
COPY scripts/rustbuild-setup.sh /scripts/
RUN sh /scripts/rustbuild-setup.sh
USER rustbuild
WORKDIR /tmp
-COPY host-x86_64/dist-powerpc-linux/patches/ /tmp/patches/
COPY host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config host-x86_64/dist-powerpc-linux/build-powerpc-toolchain.sh /tmp/
RUN ./build-powerpc-toolchain.sh
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin
ENV \
+++ /dev/null
-From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
-From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
-Date: Thu, 1 Nov 2012 18:00:06 -0500
-Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
-
----
- sysdeps/powerpc/Makefile | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
-index 79dd6fa976d5..7442b6709ad1 100644
---- a/sysdeps/powerpc/Makefile
-+++ b/sysdeps/powerpc/Makefile
-@@ -1,7 +1,3 @@
--# We always want to use the new mnemonic syntax even if we are on a RS6000
--# machine.
--+cflags += -mnew-mnemonics
--
- ifeq ($(subdir),gmon)
- sysdep_routines += ppc-mcount
- endif
---
-2.9.3
-
+++ /dev/null
-diff --git a/configure b/configure
-index b6752d147c6b..6089a3403410 100755
---- a/configure
-+++ b/configure
-@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
- ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
- case $ac_prog_version in
- '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-- 3.4* | 4.[0-9]* )
-+ 3.4* | [4-9].* )
- ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
- *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
-
-diff --git a/configure.in b/configure.in
-index 56849dfc489a..09677eb3d0c1 100644
---- a/configure.in
-+++ b/configure.in
-@@ -960,7 +960,7 @@ fi
- # These programs are version sensitive.
- AC_CHECK_TOOL_PREFIX
- AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
-- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
-+ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
- critic_missing="$critic_missing gcc")
- AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
- [GNU Make[^0-9]*\([0-9][0-9.]*\)],
#
# Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+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
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
CT_MODULES=y
#
#
# Paths
#
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
CT_RM_RF_PREFIX_DIR=y
CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
#
# Downloading
#
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
# CT_FORBID_DOWNLOAD is not set
# CT_FORCE_DOWNLOAD is not set
CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
# CT_ONLY_DOWNLOAD is not set
CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
#
# Extracting
#
# CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
# CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-# CT_PATCH_LOCAL is not set
-CT_PATCH_BUNDLED_LOCAL=y
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
#
# Build behavior
#
# CT_LOG_ERROR is not set
# CT_LOG_WARN is not set
-CT_LOG_INFO=y
-# CT_LOG_EXTRA is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
# CT_LOG_ALL is not set
# CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="INFO"
+CT_LOG_LEVEL_MAX="EXTRA"
# CT_LOG_SEE_TOOLS_WARN is not set
CT_LOG_PROGRESS_BAR=y
CT_LOG_TO_FILE=y
#
# Target options
#
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+CT_ARCH_POWERPC=y
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
CT_ARCH="powerpc"
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ABI=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_SUPPORTS_WITH_FLOAT=y
-CT_ARCH_DEFAULT_BE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ABI=""
+CT_ARCH_CHOICE_KSYM="POWERPC"
CT_ARCH_CPU="powerpc"
CT_ARCH_TUNE=""
-CT_ARCH_BE=y
-# CT_ARCH_LE is not set
-CT_ARCH_32=y
-# CT_ARCH_64 is not set
-CT_ARCH_BITNESS=32
-# CT_ARCH_FLOAT_HW is not set
-# CT_ARCH_FLOAT_SW is not set
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-# CT_ARCH_arm is not set
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-CT_ARCH_powerpc=y
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_POWERPC_SHOW=y
+
+#
+# Options for powerpc
+#
+CT_ARCH_POWERPC_PKG_KSYM=""
+CT_ARCH_powerpc_ABI=""
+CT_ARCH_powerpc_ABI_DEFAULT=y
+# CT_ARCH_powerpc_ABI_SPE is not set
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
#
# Generic target options
#
# CT_MULTILIB is not set
+CT_DEMULTILIB=y
CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+CT_ARCH_BE=y
+# CT_ARCH_LE is not set
CT_ARCH_ENDIAN="big"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=32
+CT_ARCH_32=y
+# CT_ARCH_64 is not set
#
# Target optimisations
#
+CT_ARCH_SUPPORTS_WITH_ABI=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ABI=""
CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
CT_ARCH_FLOAT="auto"
-#
-# powerpc other options
-#
-CT_ARCH_powerpc_ABI=""
-CT_ARCH_powerpc_ABI_DEFAULT=y
-# CT_ARCH_powerpc_ABI_SPE is not set
-
#
# Toolchain options
#
CT_SYSROOT_NAME="sysroot"
CT_SYSROOT_DIR_PREFIX=""
CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
# CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
CT_TOOLCHAIN_PKGVERSION=""
CT_TOOLCHAIN_BUGURL=""
# Operating System
#
CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
CT_KERNEL="linux"
-CT_KERNEL_VERSION="2.6.32.68"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-# CT_KERNEL_V_4_2 is not set
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-# CT_KERNEL_V_3_2 is not set
-CT_KERNEL_V_2_6_32=y
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="3.2.101"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_3_7_or_older=y
+CT_LINUX_older_than_3_7=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
CT_KERNEL_LINUX_VERBOSITY_0=y
# CT_KERNEL_LINUX_VERBOSITY_1 is not set
# CT_KERNEL_LINUX_VERBOSITY_2 is not set
CT_KERNEL_LINUX_VERBOSE_LEVEL=0
CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
#
# Binary utilities
#
CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+# CT_BINUTILS_V_2_32 is not set
+# CT_BINUTILS_V_2_31 is not set
+CT_BINUTILS_V_2_30=y
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.30"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_2_30_or_older=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
#
# GNU binutils
#
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
CT_BINUTILS_HAS_HASH_STYLE=y
CT_BINUTILS_HAS_GOLD=y
CT_BINUTILS_HAS_PLUGINS=y
CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
CT_BINUTILS_LINKER_LD=y
CT_BINUTILS_LINKERS_LIST="ld"
CT_BINUTILS_LINKER_DEFAULT="bfd"
# CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
# CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
#
# C-library
#
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
CT_LIBC="glibc"
-CT_LIBC_VERSION="2.11.1"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-# CT_LIBC_GLIBC_V_2_17 is not set
-# CT_LIBC_GLIBC_V_2_16_0 is not set
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-CT_LIBC_GLIBC_V_2_11_1=y
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+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
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+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_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="3.2.101"
+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
# Common C library options
#
CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
CT_LIBC_XLDD=y
-#
-# glibc other options
-#
-CT_LIBC_GLIBC_PORTS_EXTERNAL=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-# CT_LIBC_GLIBC_USE_PORTS is not set
-CT_LIBC_ADDONS_LIST=""
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68"
-
#
# C compiler
#
-CT_CC="gcc"
CT_CC_CORE_PASSES_NEEDED=y
CT_CC_CORE_PASS_1_NEEDED=y
CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
CT_CC_GCC_ENABLE_CXX_FLAGS=""
CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
CT_CC_GCC_STATIC_LIBSTDCXX=y
# CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
#
# Optimisation features
#
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
#
# Settings for libraries running on target
# CT_CC_GCC_DEC_FLOAT_BID is not set
# CT_CC_GCC_DEC_FLOAT_DPD is not set
# CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
#
# Additional supported languages:
#
CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
#
# Debug facilities
#
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
#
# Companion libraries
#
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# 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_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
CT_LIBICONV_NEEDED=y
CT_GETTEXT_NEEDED=y
CT_GMP_NEEDED=y
CT_MPFR_NEEDED=y
CT_ISL_NEEDED=y
CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
CT_LIBICONV=y
CT_GETTEXT=y
CT_GMP=y
CT_MPFR=y
CT_ISL=y
CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-# CT_CLOOG_V_0_18_4 is not set
-# CT_CLOOG_V_0_18_1 is not set
-# CT_CLOOG_V_0_18_0 is not set
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
#
# Companion tools
#
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
-FROM ubuntu:16.04
+FROM ubuntu:20.04
COPY scripts/cross-apt-packages.sh /scripts/
RUN sh /scripts/cross-apt-packages.sh
-
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
COPY scripts/rustbuild-setup.sh /scripts/
RUN sh /scripts/rustbuild-setup.sh
USER rustbuild
WORKDIR /tmp
-COPY host-x86_64/dist-powerpc64-linux/patches/ /tmp/patches/
COPY host-x86_64/dist-powerpc64-linux/shared.sh host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config host-x86_64/dist-powerpc64-linux/build-powerpc64-toolchain.sh /tmp/
RUN ./build-powerpc64-toolchain.sh
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin
ENV \
source shared.sh
-BINUTILS=2.32
-TARGET=powerpc64-unknown-linux-gnu
-PREFIX=/x-tools/$TARGET
-SYSROOT=$PREFIX/$TARGET/sysroot
-
mkdir build
cd build
cp ../powerpc64-linux-gnu.config .config
hide_output ct-ng build
cd ..
rm -rf build
-
-chmod -R u+w $PREFIX
-
-# Next, download and build newer binutils.
-mkdir binutils-$TARGET
-pushd binutils-$TARGET
-curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
-mkdir binutils-build
-cd binutils-build
-hide_output ../binutils-$BINUTILS/configure --target=$TARGET \
- --prefix=$PREFIX --with-sysroot=$SYSROOT
-hide_output make -j10
-hide_output make install
-popd
-rm -rf binutils-$TARGET
+++ /dev/null
-From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
-From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
-Date: Thu, 1 Nov 2012 18:00:06 -0500
-Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
-
----
- sysdeps/powerpc/Makefile | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
-index 79dd6fa976d5..7442b6709ad1 100644
---- a/sysdeps/powerpc/Makefile
-+++ b/sysdeps/powerpc/Makefile
-@@ -1,7 +1,3 @@
--# We always want to use the new mnemonic syntax even if we are on a RS6000
--# machine.
--+cflags += -mnew-mnemonics
--
- ifeq ($(subdir),gmon)
- sysdep_routines += ppc-mcount
- endif
---
-2.9.3
-
+++ /dev/null
-From a4f388e111ce05e2ab7912cff3c9070334bb74ae Mon Sep 17 00:00:00 2001
-From: Josh Stone <jistone@redhat.com>
-Date: Fri, 20 Jan 2017 15:41:56 -0800
-Subject: [PATCH] Prevent inlining in PPC64 initfini.s
-
-Ref: https://sourceware.org/ml/libc-alpha/2012-01/msg00195.html
----
- sysdeps/powerpc/powerpc64/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/sysdeps/powerpc/powerpc64/Makefile b/sysdeps/powerpc/powerpc64/Makefile
-index 78d4f07e575f..fe96aae4d43e 100644
---- a/sysdeps/powerpc/powerpc64/Makefile
-+++ b/sysdeps/powerpc/powerpc64/Makefile
-@@ -28,7 +28,7 @@ elide-routines.os += hp-timing
- ifneq ($(elf),no)
- # The initfini generation code doesn't work in the presence of -fPIC, so
- # we use -fpic instead which is much better.
--CFLAGS-initfini.s += -fpic -O1
-+CFLAGS-initfini.s += -fpic -O1 -fno-inline
- endif
- endif
-
---
-2.9.3
-
+++ /dev/null
-diff --git a/configure b/configure
-index b6752d147c6b..6089a3403410 100755
---- a/configure
-+++ b/configure
-@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
- ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
- case $ac_prog_version in
- '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-- 3.4* | 4.[0-9]* )
-+ 3.4* | [4-9].* )
- ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
- *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
-
-diff --git a/configure.in b/configure.in
-index 56849dfc489a..09677eb3d0c1 100644
---- a/configure.in
-+++ b/configure.in
-@@ -960,7 +960,7 @@ fi
- # These programs are version sensitive.
- AC_CHECK_TOOL_PREFIX
- AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
-- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
-+ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
- critic_missing="$critic_missing gcc")
- AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
- [GNU Make[^0-9]*\([0-9][0-9.]*\)],
#
# Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+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
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
CT_MODULES=y
#
#
# Paths
#
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
CT_RM_RF_PREFIX_DIR=y
CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
# CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
#
# Downloading
#
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
# CT_FORBID_DOWNLOAD is not set
# CT_FORCE_DOWNLOAD is not set
CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
# CT_ONLY_DOWNLOAD is not set
CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
#
# Extracting
#
# CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
# CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-# CT_PATCH_LOCAL is not set
-CT_PATCH_BUNDLED_LOCAL=y
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
#
# Build behavior
#
# CT_LOG_ERROR is not set
# CT_LOG_WARN is not set
-CT_LOG_INFO=y
-# CT_LOG_EXTRA is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
# CT_LOG_ALL is not set
# CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="INFO"
+CT_LOG_LEVEL_MAX="EXTRA"
# CT_LOG_SEE_TOOLS_WARN is not set
CT_LOG_PROGRESS_BAR=y
CT_LOG_TO_FILE=y
#
# Target options
#
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+CT_ARCH_POWERPC=y
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
CT_ARCH="powerpc"
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ABI=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_SUPPORTS_WITH_FLOAT=y
-CT_ARCH_DEFAULT_BE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ABI=""
+CT_ARCH_CHOICE_KSYM="POWERPC"
CT_ARCH_CPU="power4"
CT_ARCH_TUNE="power6"
-CT_ARCH_BE=y
-# CT_ARCH_LE is not set
-# CT_ARCH_32 is not set
-CT_ARCH_64=y
-CT_ARCH_BITNESS=64
-# CT_ARCH_FLOAT_HW is not set
-# CT_ARCH_FLOAT_SW is not set
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-# CT_ARCH_arm is not set
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-CT_ARCH_powerpc=y
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_POWERPC_SHOW=y
+
+#
+# Options for powerpc
+#
+CT_ARCH_POWERPC_PKG_KSYM=""
+CT_ARCH_powerpc_ABI=""
+CT_ARCH_powerpc_ABI_DEFAULT=y
+# CT_ARCH_powerpc_ABI_SPE is not set
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
#
# Generic target options
#
# CT_MULTILIB is not set
+CT_DEMULTILIB=y
CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+CT_ARCH_BE=y
+# CT_ARCH_LE is not set
CT_ARCH_ENDIAN="big"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=64
+# CT_ARCH_32 is not set
+CT_ARCH_64=y
#
# Target optimisations
#
+CT_ARCH_SUPPORTS_WITH_ABI=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ABI=""
CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
CT_ARCH_FLOAT="auto"
-#
-# powerpc other options
-#
-CT_ARCH_powerpc_ABI=""
-CT_ARCH_powerpc_ABI_DEFAULT=y
-# CT_ARCH_powerpc_ABI_SPE is not set
-
#
# Toolchain options
#
CT_SYSROOT_NAME="sysroot"
CT_SYSROOT_DIR_PREFIX=""
CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
# CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
CT_TOOLCHAIN_PKGVERSION=""
CT_TOOLCHAIN_BUGURL=""
# Operating System
#
CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
CT_KERNEL="linux"
-CT_KERNEL_VERSION="2.6.32.68"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-# CT_KERNEL_V_4_2 is not set
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-# CT_KERNEL_V_3_2 is not set
-CT_KERNEL_V_2_6_32=y
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="3.2.101"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_3_7_or_older=y
+CT_LINUX_older_than_3_7=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
CT_KERNEL_LINUX_VERBOSITY_0=y
# CT_KERNEL_LINUX_VERBOSITY_1 is not set
# CT_KERNEL_LINUX_VERBOSITY_2 is not set
CT_KERNEL_LINUX_VERBOSE_LEVEL=0
CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
#
# Binary utilities
#
CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+CT_BINUTILS_V_2_32=y
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.32"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
#
# GNU binutils
#
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
CT_BINUTILS_HAS_HASH_STYLE=y
CT_BINUTILS_HAS_GOLD=y
CT_BINUTILS_HAS_PLUGINS=y
CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
CT_BINUTILS_LINKER_LD=y
CT_BINUTILS_LINKERS_LIST="ld"
CT_BINUTILS_LINKER_DEFAULT="bfd"
# CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
# CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
#
# C-library
#
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
CT_LIBC="glibc"
-CT_LIBC_VERSION="2.11.1"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-# CT_LIBC_GLIBC_V_2_17 is not set
-# CT_LIBC_GLIBC_V_2_16_0 is not set
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-CT_LIBC_GLIBC_V_2_11_1=y
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+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
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+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_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="3.2.101"
+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
# Common C library options
#
CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
CT_LIBC_XLDD=y
-#
-# glibc other options
-#
-CT_LIBC_GLIBC_PORTS_EXTERNAL=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-# CT_LIBC_GLIBC_USE_PORTS is not set
-CT_LIBC_ADDONS_LIST=""
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68"
-
#
# C compiler
#
-CT_CC="gcc"
CT_CC_CORE_PASSES_NEEDED=y
CT_CC_CORE_PASS_1_NEEDED=y
CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
CT_CC_GCC_ENABLE_CXX_FLAGS=""
CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
CT_CC_GCC_STATIC_LIBSTDCXX=y
# CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
#
# Optimisation features
#
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
#
# Settings for libraries running on target
# CT_CC_GCC_DEC_FLOAT_BID is not set
# CT_CC_GCC_DEC_FLOAT_DPD is not set
# CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
#
# Additional supported languages:
#
CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
#
# Debug facilities
#
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
#
# Companion libraries
#
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# 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_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
CT_LIBICONV_NEEDED=y
CT_GETTEXT_NEEDED=y
CT_GMP_NEEDED=y
CT_MPFR_NEEDED=y
CT_ISL_NEEDED=y
CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
CT_LIBICONV=y
CT_GETTEXT=y
CT_GMP=y
CT_MPFR=y
CT_ISL=y
CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
#
# Companion tools
#
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
-FROM ubuntu:16.04
+FROM ubuntu:20.04
COPY scripts/cross-apt-packages.sh /scripts/
RUN sh /scripts/cross-apt-packages.sh
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
-
COPY scripts/rustbuild-setup.sh /scripts/
RUN sh /scripts/rustbuild-setup.sh
USER rustbuild
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
ENV \
AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \
CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \
source shared.sh
BINUTILS=2.32
-GCC=5.3.0
+GCC=8.3.0
TARGET=powerpc64le-linux-gnu
SYSROOT=/usr/local/$TARGET/sysroot
# Next, download and build binutils.
mkdir binutils-$TARGET
pushd binutils-$TARGET
-curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
+curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.xz | tar xJf -
mkdir binutils-build
cd binutils-build
hide_output ../binutils-$BINUTILS/configure --target=$TARGET --with-sysroot=$SYSROOT
# Finally, download and build gcc.
mkdir gcc-$TARGET
pushd gcc-$TARGET
-curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
+curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | tar xJf -
cd gcc-$GCC
hide_output ./contrib/download_prerequisites
-FROM ubuntu:18.04
+FROM ubuntu:20.04
COPY scripts/cross-apt-packages.sh /scripts/
RUN sh /scripts/cross-apt-packages.sh
-COPY host-x86_64/dist-riscv64-linux/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
COPY scripts/rustbuild-setup.sh /scripts/
RUN sh /scripts/rustbuild-setup.sh
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
ENV PATH=$PATH:/x-tools/riscv64-unknown-linux-gnu/bin
ENV CC_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-gcc \
+++ /dev/null
-#!/bin/sh
-set -ex
-
-# Mirrored from https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-1.24.0.tar.gz
-url="https://ci-mirrors.rust-lang.org/rustc/crosstool-ng-1.24.0.tar.gz"
-curl -Lf $url | tar xzf -
-cd crosstool-ng-crosstool-ng-1.24.0
-./bootstrap
-./configure --prefix=/usr/local
-make -j$(nproc)
-make install
-cd ..
-rm -rf crosstool-ng-crosstool-ng-1.24.0
USER rustbuild
WORKDIR /tmp
-COPY host-x86_64/dist-s390x-linux/patches/ /tmp/patches/
COPY host-x86_64/dist-s390x-linux/s390x-linux-gnu.config host-x86_64/dist-s390x-linux/build-s390x-toolchain.sh /tmp/
RUN ./build-s390x-toolchain.sh
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin
ENV \
+++ /dev/null
-From 2739047682590b1df473401b4febf424f857fccf Mon Sep 17 00:00:00 2001
-From: Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
-Date: Sun, 17 Apr 2011 20:43:59 -0400
-Subject: [PATCH] Use .machine to prevent AS from complaining about z9-109
- instructions in iconv modules
-
----
- sysdeps/s390/s390-64/utf16-utf32-z9.c | 5 ++++-
- sysdeps/s390/s390-64/utf8-utf16-z9.c | 5 ++++-
- sysdeps/s390/s390-64/utf8-utf32-z9.c | 5 ++++-
- 3 files changed, 12 insertions(+), 3 deletions(-)
-
-diff --git a/sysdeps/s390/s390-64/utf16-utf32-z9.c b/sysdeps/s390/s390-64/utf16-utf32-z9.c
-index 14daf2118fe5..5bcaaaedec9c 100644
---- a/sysdeps/s390/s390-64/utf16-utf32-z9.c
-+++ b/sysdeps/s390/s390-64/utf16-utf32-z9.c
-@@ -169,7 +169,10 @@ gconv_end (struct __gconv_step *data)
- register unsigned long long outlen asm("11") = outend - outptr; \
- uint64_t cc = 0; \
- \
-- asm volatile ("0: " INSTRUCTION " \n\t" \
-+ asm volatile (".machine push \n\t" \
-+ ".machine \"z9-109\" \n\t" \
-+ "0: " INSTRUCTION " \n\t" \
-+ ".machine pop \n\t" \
- " jo 0b \n\t" \
- " ipm %2 \n" \
- : "+a" (pOutput), "+a" (pInput), "+d" (cc), \
-diff --git a/sysdeps/s390/s390-64/utf8-utf16-z9.c b/sysdeps/s390/s390-64/utf8-utf16-z9.c
-index 5f73f3c59e21..812a42fae44c 100644
---- a/sysdeps/s390/s390-64/utf8-utf16-z9.c
-+++ b/sysdeps/s390/s390-64/utf8-utf16-z9.c
-@@ -151,7 +151,10 @@ gconv_end (struct __gconv_step *data)
- register unsigned long long outlen asm("11") = outend - outptr; \
- uint64_t cc = 0; \
- \
-- asm volatile ("0: " INSTRUCTION " \n\t" \
-+ asm volatile (".machine push \n\t" \
-+ ".machine \"z9-109\" \n\t" \
-+ "0: " INSTRUCTION " \n\t" \
-+ ".machine pop \n\t" \
- " jo 0b \n\t" \
- " ipm %2 \n" \
- : "+a" (pOutput), "+a" (pInput), "+d" (cc), \
-diff --git a/sysdeps/s390/s390-64/utf8-utf32-z9.c b/sysdeps/s390/s390-64/utf8-utf32-z9.c
-index 17ef8bc890c3..0ffd848c8124 100644
---- a/sysdeps/s390/s390-64/utf8-utf32-z9.c
-+++ b/sysdeps/s390/s390-64/utf8-utf32-z9.c
-@@ -155,7 +155,10 @@ gconv_end (struct __gconv_step *data)
- register unsigned long long outlen asm("11") = outend - outptr; \
- uint64_t cc = 0; \
- \
-- asm volatile ("0: " INSTRUCTION " \n\t" \
-+ asm volatile (".machine push \n\t" \
-+ ".machine \"z9-109\" \n\t" \
-+ "0: " INSTRUCTION " \n\t" \
-+ ".machine pop \n\t" \
- " jo 0b \n\t" \
- " ipm %2 \n" \
- : "+a" (pOutput), "+a" (pInput), "+d" (cc), \
---
-2.9.3
-
#
# Paths
#
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
# CT_TARBALLS_BUILDROOT_LAYOUT is not set
CT_WORK_DIR="${CT_TOP_DIR}/.build"
CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
# CT_FORCE_EXTRACT is not set
CT_OVERRIDE_CONFIG_GUESS_SUB=y
# CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-CT_PATCH_BUNDLED_LOCAL=y
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
#
# Build behavior
# CT_ARCH_XTENSA is not set
CT_ARCH="s390"
CT_ARCH_CHOICE_KSYM="S390"
+# 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_S390_SHOW=y
#
# CT_LINUX_V_3_12 is not set
# CT_LINUX_V_3_10 is not set
# CT_LINUX_V_3_4 is not set
-# CT_LINUX_V_3_2 is not set
-CT_LINUX_V_2_6_32=y
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
# CT_LINUX_NO_VERSIONS is not set
-CT_LINUX_VERSION="2.6.32.71"
+CT_LINUX_VERSION="3.2.101"
CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
CT_LINUX_older_than_4_8=y
CT_LINUX_3_7_or_older=y
CT_LINUX_older_than_3_7=y
-CT_LINUX_3_2_or_older=y
-CT_LINUX_older_than_3_2=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
CT_KERNEL_LINUX_VERBOSITY_0=y
# CT_KERNEL_LINUX_VERBOSITY_1 is not set
# CT_KERNEL_LINUX_VERBOSITY_2 is not set
CT_BINUTILS_PKG_NAME="binutils"
CT_BINUTILS_SRC_RELEASE=y
CT_BINUTILS_PATCH_ORDER="global"
-# CT_BINUTILS_V_2_32 is not set
+CT_BINUTILS_V_2_32=y
# CT_BINUTILS_V_2_31 is not set
# CT_BINUTILS_V_2_30 is not set
# CT_BINUTILS_V_2_29 is not set
# CT_BINUTILS_V_2_28 is not set
# CT_BINUTILS_V_2_27 is not set
-CT_BINUTILS_V_2_26=y
+# CT_BINUTILS_V_2_26 is not set
# CT_BINUTILS_NO_VERSIONS is not set
-CT_BINUTILS_VERSION="2.26.1"
+CT_BINUTILS_VERSION="2.32"
CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_BINUTILS_ARCHIVE_FORMATS=".tar.bz2 .tar.gz"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
-CT_BINUTILS_2_30_or_older=y
-CT_BINUTILS_older_than_2_30=y
-CT_BINUTILS_2_27_or_older=y
-CT_BINUTILS_older_than_2_27=y
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
CT_BINUTILS_later_than_2_25=y
CT_BINUTILS_2_25_or_later=y
CT_BINUTILS_later_than_2_23=y
# 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"
# CT_GLIBC_V_2_24 is not set
# CT_GLIBC_V_2_23 is not set
# CT_GLIBC_V_2_19 is not set
-# CT_GLIBC_V_2_17 is not set
-CT_GLIBC_V_2_12_1=y
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
# CT_GLIBC_NO_VERSIONS is not set
-CT_GLIBC_VERSION="2.12.1"
+CT_GLIBC_VERSION="2.17"
CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
CT_GLIBC_older_than_2_23=y
CT_GLIBC_2_20_or_older=y
CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
CT_GLIBC_2_17_or_older=y
-CT_GLIBC_older_than_2_17=y
-CT_GLIBC_2_14_or_older=y
-CT_GLIBC_older_than_2_14=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
CT_GLIBC_DEP_BINUTILS=y
CT_GLIBC_DEP_GCC=y
CT_GLIBC_DEP_PYTHON=y
CT_GLIBC_HAS_NPTL_ADDON=y
CT_GLIBC_HAS_PORTS_ADDON=y
-CT_GLIBC_HAS_PORTS_ADDON_EXTERNAL=y
CT_GLIBC_HAS_LIBIDN_ADDON=y
CT_GLIBC_USE_NPTL_ADDON=y
# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
CT_GLIBC_EXTRA_CONFIG_ARRAY=""
CT_GLIBC_CONFIGPARMS=""
CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
# CT_GLIBC_DISABLE_VERSIONING is not set
CT_GLIBC_OLDEST_ABI=""
CT_GLIBC_FORCE_UNWIND=y
# CT_GLIBC_KERNEL_VERSION_NONE is not set
CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_GLIBC_MIN_KERNEL="2.6.32.71"
+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
ENV \
AR_x86_64_fuchsia=x86_64-fuchsia-ar \
CC_x86_64_fuchsia=x86_64-fuchsia-clang \
+ CFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \
+ CXXFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+ LDFLAGS_x86_64_fuchsia="--target=x86_64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib" \
AR_aarch64_fuchsia=aarch64-fuchsia-ar \
CC_aarch64_fuchsia=aarch64-fuchsia-clang \
+ CFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \
+ CXXFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -I/usr/local/core-linux-amd64-fuchsia-sdk/pkg/fdio/include" \
+ LDFLAGS_aarch64_fuchsia="--target=aarch64-fuchsia --sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot -L/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib" \
AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \
CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \
CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \
ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar
ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \
--C link-arg=--sysroot=/usr/local/x86_64-fuchsia \
--C link-arg=-L/usr/local/x86_64-fuchsia/lib \
--C link-arg=-L/usr/local/lib/x86_64-fuchsia/lib
+-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot \
+-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/sysroot/lib \
+-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/x64/lib
ENV CARGO_TARGET_AARCH64_FUCHSIA_AR /usr/local/bin/llvm-ar
ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \
--C link-arg=--sysroot=/usr/local/aarch64-fuchsia \
--C link-arg=-L/usr/local/aarch64-fuchsia/lib \
--C link-arg=-L/usr/local/lib/aarch64-fuchsia/lib
+-C link-arg=--sysroot=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot \
+-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/sysroot/lib \
+-Lnative=/usr/local/core-linux-amd64-fuchsia-sdk/arch/arm64/lib
ENV TARGETS=x86_64-fuchsia
ENV TARGETS=$TARGETS,aarch64-fuchsia
set -ex
source shared.sh
-ZIRCON=e9a26dbc70d631029f8ee9763103910b7e3a2fe1
-
-mkdir -p zircon
-pushd zircon > /dev/null
-
-# Download sources
-git init
-git remote add origin https://github.com/rust-lang-nursery/mirror-google-fuchsia-zircon
-git fetch --depth=1 origin $ZIRCON
-git reset --hard FETCH_HEAD
-
-# Download toolchain
-./scripts/download-toolchain
-chmod -R a+rx prebuilt/downloads/clang+llvm-x86_64-linux
-cp -a prebuilt/downloads/clang+llvm-x86_64-linux/. /usr/local
-
-build() {
- local arch="$1"
-
- case "${arch}" in
- x86_64) tgt="zircon-pc-x86-64" ;;
- aarch64) tgt="zircon-qemu-arm64" ;;
- esac
-
- hide_output make -j$(getconf _NPROCESSORS_ONLN) $tgt
- dst=/usr/local/${arch}-fuchsia
- mkdir -p $dst
- cp -a build-${tgt}/sysroot/include $dst/
- cp -a build-${tgt}/sysroot/lib $dst/
+FUCHSIA_SDK_URL=https://chrome-infra-packages.appspot.com/dl/fuchsia/sdk/core/linux-amd64
+FUCHSIA_SDK_ID=4xjxrGUrDbQ6_zJwj6cDN1IbWsWV5aCQXC_zO_Hu0XkC
+FUCHSIA_SDK_SHA256=e318f1ac652b0db43aff32708fa70337521b5ac595e5a0905c2ff33bf1eed179
+FUCHSIA_SDK_USR_DIR=/usr/local/core-linux-amd64-fuchsia-sdk
+CLANG_DOWNLOAD_URL=\
+https://chrome-infra-packages.appspot.com/dl/fuchsia/third_party/clang/linux-amd64
+CLANG_DOWNLOAD_ID=vU0vNjSihOV4Q6taQYCpy03JXGiCyVwxen3rFMNMIgsC
+CLANG_DOWNLOAD_SHA256=bd4d2f3634a284e57843ab5a4180a9cb4dc95c6882c95c317a7deb14c34c220b
+
+install_clang() {
+ mkdir -p clang_download
+ pushd clang_download > /dev/null
+
+ # Download clang+llvm
+ curl -LO "${CLANG_DOWNLOAD_URL}/+/${CLANG_DOWNLOAD_ID}"
+ echo "$(echo ${CLANG_DOWNLOAD_SHA256}) ${CLANG_DOWNLOAD_ID}" | sha256sum --check --status
+ unzip -qq ${CLANG_DOWNLOAD_ID} -d clang-linux-amd64
+
+ # Other dists currently depend on our Clang... moving into /usr/local for other
+ # dist usage instead of a Fuchsia /usr/local directory
+ chmod -R 777 clang-linux-amd64/.
+ cp -a clang-linux-amd64/. /usr/local
+
+ # CFLAGS and CXXFLAGS env variables in main Dockerfile handle sysroot linking
+ for arch in x86_64 aarch64; do
+ for tool in clang clang++; do
+ ln -s /usr/local/bin/${tool} /usr/local/bin/${arch}-fuchsia-${tool}
+ done
+ ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-fuchsia-ar
+ done
+
+ popd > /dev/null
+ rm -rf clang_download
}
-# Build sysroot
-for arch in x86_64 aarch64; do
- build ${arch}
-done
-
-popd > /dev/null
-rm -rf zircon
-
-for arch in x86_64 aarch64; do
- for tool in clang clang++; do
- cat >/usr/local/bin/${arch}-fuchsia-${tool} <<EOF
-#!/bin/sh
-${tool} --target=${arch}-fuchsia --sysroot=/usr/local/${arch}-fuchsia "\$@"
-EOF
- chmod +x /usr/local/bin/${arch}-fuchsia-${tool}
- done
- ln -s /usr/local/bin/llvm-ar /usr/local/bin/${arch}-fuchsia-ar
-done
+install_zircon_libs() {
+ mkdir -p zircon
+ pushd zircon > /dev/null
+
+ # Download Fuchsia SDK (with Zircon libs)
+ curl -LO "${FUCHSIA_SDK_URL}/+/${FUCHSIA_SDK_ID}"
+ echo "$(echo ${FUCHSIA_SDK_SHA256}) ${FUCHSIA_SDK_ID}" | sha256sum --check --status
+ unzip -qq ${FUCHSIA_SDK_ID} -d core-linux-amd64
+
+ # Moving SDK into Docker's user-space
+ mkdir -p ${FUCHSIA_SDK_USR_DIR}
+ chmod -R 777 core-linux-amd64/.
+ cp -r core-linux-amd64/* ${FUCHSIA_SDK_USR_DIR}
+
+ popd > /dev/null
+ rm -rf zircon
+}
+
+hide_output install_clang
+hide_output install_zircon_libs
-# We need recent curl, OpenSSL and CA certificates, so we can download further
-# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
-# those.
-FROM ubuntu:20.04
-RUN apt-get update && \
- apt-get install -y --no-install-recommends \
- curl \
- ca-certificates
-WORKDIR /tmp
-COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
-RUN ./download-openssl-curl.sh
-
-# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
-# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
-# SLES 11 SP4 (glibc 2.11, kernel 3.0).
-FROM debian:6
+# We document platform support for minimum glibc 2.17 and kernel 3.2.
+# CentOS 7 has headers for kernel 3.10, but that's fine as long as we don't
+# actually use newer APIs in rustc or std without a fallback. It's more
+# important that we match glibc for ELF symbol versioning.
+FROM centos:7
WORKDIR /build
-# Debian 6 is EOL and no longer available from the usual mirrors,
-# so we'll need to switch to http://archive.debian.org/
-RUN sed -i '/updates/d' /etc/apt/sources.list && \
- sed -i 's/httpredir/archive/' /etc/apt/sources.list
-
-RUN apt-get update && \
- apt-get install --allow-unauthenticated -y --no-install-recommends \
+RUN yum upgrade -y && \
+ yum install -y epel-release && \
+ yum install -y \
automake \
bzip2 \
file \
- g++ \
- g++-multilib \
+ cmake3 \
gcc \
- gcc-multilib \
+ gcc-c++ \
git \
- lib32z1-dev \
- libedit-dev \
- libncurses-dev \
+ glibc-devel.i686 \
+ glibc-devel.x86_64 \
+ libedit-devel \
+ libstdc++-devel.i686 \
+ libstdc++-devel.x86_64 \
make \
+ ncurses-devel \
+ openssl-devel \
patch \
perl \
- pkg-config \
+ pkgconfig \
+ python3 \
unzip \
wget \
- xz-utils \
- zlib1g-dev
+ xz \
+ zlib-devel.i686 \
+ zlib-devel.x86_64
+
+RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
ENV PATH=/rustroot/bin:$PATH
ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
RUN mkdir /home/user
COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
-# We need a build of openssl which supports SNI to download artifacts from
-# static.rust-lang.org. This'll be used to link into libcurl below (and used
-# later as well), so build a copy of OpenSSL with dynamic libraries into our
-# generic root.
-COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
-COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
-RUN ./build-openssl.sh
-
-# The `curl` binary on Debian 6 doesn't support SNI which is needed for fetching
-# some https urls we have, so install a new version of libcurl + curl which is
-# using the openssl we just built previously.
-#
-# Note that we also disable a bunch of optional features of curl that we don't
-# really need.
-COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
-COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh
-
-# Use up-to-date curl CA bundle
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
-
-# binutils < 2.22 has a bug where the 32-bit executables it generates
-# immediately segfault in Rust, so we need to install our own binutils.
-#
-# See https://github.com/rust-lang/rust/issues/20440 for more info
-COPY host-x86_64/dist-x86_64-linux/build-binutils.sh /tmp/
-RUN ./build-binutils.sh
-
# Need at least GCC 5.1 to compile LLVM nowadays
COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
-RUN ./build-gcc.sh && apt-get remove -y gcc g++
-
-COPY host-x86_64/dist-x86_64-linux/build-python.sh /tmp/
-# Build Python 3 needed for LLVM 12.
-RUN ./build-python.sh 3.9.1
-
-# LLVM needs cmake 3.13.4 or higher.
-COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
-RUN ./build-cmake.sh
+RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
# Now build LLVM+Clang, afterwards configuring further compilations to use the
# clang/clang++ compilers.
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-
-source shared.sh
-
-VERSION=2.26.1
-
-curl https://ftp.gnu.org/gnu/binutils/binutils-$VERSION.tar.bz2 | tar xfj -
-
-mkdir binutils-build
-cd binutils-build
-hide_output ../binutils-$VERSION/configure --prefix=/rustroot
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf binutils-build
-rm -rf binutils-$VERSION
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-CMAKE=3.13.4
-curl -L https://github.com/Kitware/CMake/releases/download/v$CMAKE/cmake-$CMAKE.tar.gz | tar xzf -
-
-mkdir cmake-build
-cd cmake-build
-hide_output ../cmake-$CMAKE/configure --prefix=/rustroot
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf cmake-build
-rm -rf cmake-$CMAKE
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-tar xJf curl.tar.xz
-
-mkdir curl-build
-cd curl-build
-hide_output ../curl-*/configure \
- --prefix=/rustroot \
- --with-ssl=/rustroot \
- --disable-sspi \
- --disable-gopher \
- --disable-smtp \
- --disable-smb \
- --disable-imap \
- --disable-pop3 \
- --disable-tftp \
- --disable-telnet \
- --disable-manual \
- --disable-dict \
- --disable-rtsp \
- --disable-ldaps \
- --disable-ldap
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf curl-build
-rm -rf curl-*
cd ..
rm -rf gcc-build
rm -rf gcc-$GCC
+
+# FIXME: clang doesn't find 32-bit libraries in /rustroot/lib,
+# but it does look all the way under /rustroot/lib/[...]/32,
+# so we can link stuff there to help it out.
+ln /rustroot/lib/*.{a,so} -rst /rustroot/lib/gcc/x86_64-pc-linux-gnu/$GCC/32/
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-tar xzf openssl.tar.gz
-
-cd openssl-*
-hide_output ./config --prefix=/rustroot shared -fPIC
-hide_output make -j$(nproc)
-hide_output make install
-cd ..
-rm -rf openssl-*
-
-# Make the system cert collection available to the new install.
-ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-VERSION=$1
-curl https://www.python.org/ftp/python/$VERSION/Python-$VERSION.tgz | \
- tar xzf -
-
-mkdir python-build
-cd python-build
-
-# Gotta do some hackery to tell python about our custom OpenSSL build, but other
-# than that fairly normal.
-CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \
- hide_output ../Python-$VERSION/configure --prefix=/rustroot
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf python-build
-rm -rf Python-$VERSION
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-
-OPENSSL_VERSION=1.0.2k
-CURL_VERSION=7.66.0
-
-curl -f https://ci-mirrors.rust-lang.org/rustc/openssl-$OPENSSL_VERSION.tar.gz -o openssl.tar.gz
-curl -f https://ci-mirrors.rust-lang.org/rustc/curl-$CURL_VERSION.tar.xz -o curl.tar.xz
-curl -f https://curl.se/ca/cacert.pem -o cacert.pem
+++ /dev/null
-diff --git a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
-index 176d6d6abf3..a6d63bf24b8 100644
---- a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
-+++ b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
-@@ -33,6 +33,13 @@ namespace {
- using namespace llvm;
- using namespace clang;
-
-+#define EPOLL_CLOEXEC -1
-+#define IN_CLOEXEC -1
-+#define O_CLOEXEC -1
-+static int epoll_create1(int flags) { return -1; }
-+static int inotify_init1(int flags) { return -1; }
-+static int pipe2(int *fds, int flags) { return -1; }
-+
- /// Pipe for inter-thread synchronization - for epoll-ing on multiple
- /// conditions. It is meant for uni-directional 1:1 signalling - specifically:
- /// no multiple consumers, no data passing. Thread waiting for signal should
ENV HOSTS=x86_64-unknown-netbsd
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+ --set llvm.allow-old-toolchain
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
RUN echo "[rust]" > /config/nopt-std-config.toml
RUN echo "optimize = false" >> /config/nopt-std-config.toml
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests \
+ --set llvm.allow-old-toolchain
ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
&& python3 ../x.py --stage 2 test
COPY scripts/cmake.sh /scripts/
RUN /scripts/cmake.sh
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu \
+ --set llvm.allow-old-toolchain
# Exclude some tests that are unlikely to be platform specific, to speed up
# this slow job.
ENV SCRIPT python3 ../x.py --stage 2 test \
COPY scripts/cmake.sh /scripts/
RUN /scripts/cmake.sh
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
+ --set llvm.allow-old-toolchain
ENV RUST_CHECK_TARGET check-aux
COPY scripts/cmake.sh /scripts/
RUN /scripts/cmake.sh
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false \
+ --set llvm.allow-old-toolchain
ENV SCRIPT python3 ../x.py --stage 2 test distcheck
ENV DIST_SRC 1
FROM ubuntu:20.04
ARG DEBIAN_FRONTEND=noninteractive
+
+# NOTE: intentionally installs both python2 and python3 so we can test support for both.
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
gcc-multilib \
curl \
ca-certificates \
python2.7 \
+ python3.9 \
git \
cmake \
sudo \
xz-utils \
nodejs
+# Install powershell so we can test x.ps1 on Linux
+RUN apt-get update && \
+ apt-get install -y apt-transport-https software-properties-common && \
+ curl -s "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" > packages-microsoft-prod.deb && \
+ dpkg -i packages-microsoft-prod.deb && \
+ apt-get update && \
+ apt-get install -y powershell
+
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
--enable-llvm-link-shared \
--set rust.thin-lto-import-instr-limit=10
-ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
+# NOTE: intentionally uses all of `x.py`, `x.sh`, and `x.ps1` to make sure they all work on Linux.
+ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \
# Run the `mir-opt` tests again but this time for a 32-bit target.
# This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
# both 32-bit and 64-bit outputs updated by the PR author, before
# the PR is approved and tested for merging.
# It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
# despite having different output on 32-bit vs 64-bit targets.
- python2.7 ../x.py --stage 2 test src/test/mir-opt \
+ ../x.sh --stage 2 test src/test/mir-opt \
--host='' --target=i686-unknown-linux-gnu && \
# Run the UI test suite again, but in `--pass=check` mode
#
# This is intended to make sure that both `--pass=check` continues to
# work.
#
- python2.7 ../x.py --stage 2 test src/test/ui --pass=check \
+ ../x.ps1 --stage 2 test src/test/ui --pass=check \
--host='' --target=i686-unknown-linux-gnu && \
# Run tidy at the very end, after all the other tests.
python2.7 ../x.py --stage 2 test src/tools/tidy
RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true
ENV RUST_CONFIGURE_ARGS \
+ --set llvm.allow-old-toolchain \
--build=x86_64-unknown-linux-gnu \
--save-toolstates=/tmp/toolstate/toolstates.json
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'
+ if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'
<<: *step
- name: collect CPU statistics
- name: i686-mingw-1
env:
- RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+ RUST_CONFIGURE_ARGS: >-
+ --build=i686-pc-windows-gnu
+ --set llvm.allow-old-toolchain
SCRIPT: make ci-mingw-subset-1
CUSTOM_MINGW: 1
<<: *job-windows-xl
- name: i686-mingw-2
env:
- RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+ RUST_CONFIGURE_ARGS: >-
+ --build=i686-pc-windows-gnu
+ --set llvm.allow-old-toolchain
SCRIPT: make ci-mingw-subset-2
CUSTOM_MINGW: 1
<<: *job-windows-xl
- name: x86_64-mingw-1
env:
SCRIPT: make ci-mingw-subset-1
- RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler
+ RUST_CONFIGURE_ARGS: >-
+ --build=x86_64-pc-windows-gnu
+ --enable-profiler
+ --set llvm.allow-old-toolchain
CUSTOM_MINGW: 1
<<: *job-windows-xl
- name: x86_64-mingw-2
env:
SCRIPT: make ci-mingw-subset-2
- RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler
+ RUST_CONFIGURE_ARGS: >-
+ --build=x86_64-pc-windows-gnu
+ --enable-profiler
+ --set llvm.allow-old-toolchain
CUSTOM_MINGW: 1
<<: *job-windows-xl
- name: dist-i686-mingw
env:
- RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
+ RUST_CONFIGURE_ARGS: >-
+ --build=i686-pc-windows-gnu
+ --enable-full-tools
+ --enable-profiler
+ --set llvm.allow-old-toolchain
SCRIPT: python x.py dist
CUSTOM_MINGW: 1
DIST_REQUIRE_ALL_TOOLS: 1
- name: dist-x86_64-mingw
env:
SCRIPT: python x.py dist
- RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
+ RUST_CONFIGURE_ARGS: >-
+ --build=x86_64-pc-windows-gnu
+ --enable-full-tools
+ --enable-profiler
+ --set llvm.allow-old-toolchain
CUSTOM_MINGW: 1
DIST_REQUIRE_ALL_TOOLS: 1
<<: *job-windows-xl
rm $cached
}
-# Archive downloads are temporarily disabled due to sudden 504
-# gateway timeout errors.
-# included="src/llvm-project src/doc/book src/doc/rust-by-example"
-included=""
+included="src/llvm-project src/doc/book src/doc/rust-by-example"
modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)"
modules=($modules)
use_git=""
retry sh -c "git submodule deinit -f $use_git && \
git submodule sync && \
git submodule update -j 16 --init --recursive --depth 1 $use_git"
-# STATUS=0
-# for pid in ${bg_pids[*]}
-# do
-# wait $pid || STATUS=1
-# done
-# exit ${STATUS}
+STATUS=0
+for pid in ${bg_pids[*]}
+do
+ wait $pid || STATUS=1
+done
+exit ${STATUS}
-Subproject commit 766979590da8100998f0d662499d4a901d8d1640
+Subproject commit befe6840874311635c417cf731377f07234ee373
\fIframework\fR.
If omitted, \fIdylib\fR is assumed.
.TP
-\fB\-\-crate\-type\fR [bin|lib|rlib|dylib|cdylib|staticlib]
+\fB\-\-crate\-type\fR [bin|lib|rlib|dylib|cdylib|staticlib|proc\-macro]
Comma separated list of types of crates for the compiler to emit.
.TP
\fB\-\-crate\-name\fR \fINAME\fR
Specify the name of the crate being built.
.TP
-\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info|mir][=\fIPATH\fR]
+\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|metadata|link|dep\-info|mir][=\fIPATH\fR]
Configure the output that \fBrustc\fR will produce. Each emission may also have
an optional explicit output \fIPATH\fR specified for that particular emission
kind. This path takes precedence over the \fB-o\fR option.
.TP
-\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs]
+\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:target\-libdir|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs|\:stack\-protector\-strategies|\:link\-args]
Comma separated list of compiler information to print on stdout.
.TP
\fB\-g\fR
-Subproject commit a92be0fef439b3d8e0468d82cb24812d303520a0
+Subproject commit f3d3953bf3b158d596c96d55ce5366f9f3f972e9
-Subproject commit 3155db49b0d57cd82c65456ac210b69ecec5ccb1
+Subproject commit ee342dc91e1ba1bb1e1f1318f84bbe3bfac04798
-Subproject commit d5201cddace979b299ec1bf9fd8997338151aa9d
+Subproject commit 04f3cf0bb2f5a6ee2bfc4b1a6a6cd8c11d1c5531
- [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
- [\*-apple-watchos\*](platform-support/apple-watchos.md)
- [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
+ - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
- [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
- [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
- [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
This modifier is only compatible with the `static` linking kind.
Using any other kind will result in a compiler error.
-When building a rlib or staticlib `+bundle` means that all object files from the native static
-library will be added to the rlib or staticlib archive, and then used from it during linking of
-the final binary.
+When building a rlib or staticlib `+bundle` means that the native static library
+will be packed into the rlib or staticlib archive, and then retrieved from there
+during linking of the final binary.
When building a rlib `-bundle` means that the native static library is registered as a dependency
of that rlib "by name", and object files from it are included only during linking of the final
# Compile the Rust staticlib
rustc --crate-type=staticlib -Clinker-plugin-lto -Copt-level=2 ./lib.rs
# Compile the C code with `-flto=thin`
-clang -c -O2 -flto=thin -o main.o ./main.c
+clang -c -O2 -flto=thin -o cmain.o ./cmain.c
# Link everything, making sure that we use an appropriate linker
clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o
```
# Compile the Rust staticlib
RUSTFLAGS="-Clinker-plugin-lto" cargo build --release
# Compile the C code with `-flto=thin`
-clang -c -O2 -flto=thin -o main.o ./main.c
+clang -c -O2 -flto=thin -o cmain.o ./cmain.c
# Link everything, making sure that we use an appropriate linker
clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o
```
target | notes
-------|-------
-`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
+`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+) [^missing-stack-probes]
`i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+) [^windows-support]
`i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+) [^windows-support]
-`i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+)
`x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+)
`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+) [^windows-support]
`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+) [^windows-support]
-`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
[^missing-stack-probes]: Stack probes support is missing on
`aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
-`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 2.6.32, glibc 2.11)
-`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 2.6.32, glibc 2.11)
+`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17)
+`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
`powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
`riscv64gc-unknown-linux-gnu` | RISC-V Linux (kernel 4.20, glibc 2.29)
-`s390x-unknown-linux-gnu` | S390x Linux (kernel 2.6.32, glibc 2.12)
+`s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
`x86_64-unknown-freebsd` | 64-bit FreeBSD
`x86_64-unknown-illumos` | illumos
`x86_64-unknown-linux-musl` | 64-bit Linux with MUSL
`riscv32imc-esp-espidf` | ✓ | | RISC-V ESP-IDF
`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD
`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
-`s390x-unknown-linux-musl` | | | S390x Linux (kernel 2.6.32, MUSL)
+`s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, MUSL)
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
[`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
--- /dev/null
+# armv4t-none-eabi
+
+Tier 3
+
+Bare-metal target for any cpu in the ARMv4T architecture family, supporting
+ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code
+generation.
+
+In particular this supports the Gameboy Advance (GBA), but there's nothing GBA
+specific with this target, so any ARMv4T device should work fine.
+
+## Target Maintainers
+
+* [@Lokathor](https://github.com/lokathor)
+
+## Requirements
+
+The target is cross-compiled, and uses static linking.
+
+The linker that comes with rustc cannot link for this platform (the platform is
+too old). You will need the `arm-none-eabi-ld` linker from a GNU Binutils
+targeting ARM. This can be obtained for Windows/Mac/Linux from the [ARM
+Developer Website][arm-dev], or possibly from your OS's package manager.
+
+[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
+
+This target doesn't provide a linker script, you'll need to bring your own
+according to the specific device you want to target. Pass
+`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
+`your_script.ld` during linking.
+
+## Building Rust Programs
+
+Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target.
+
+Just use the `build-std` nightly cargo feature to build the `core` library. You
+can pass this as a command line argument to cargo, or your `.cargo/config.toml`
+file might include the following lines:
+
+```toml
+[unstable]
+build-std = ["core"]
+```
+
+Most of `core` should work as expected, with the following notes:
+* the target is "soft float", so `f32` and `f64` operations are emulated in
+ software.
+* integer division is also emulated in software.
+* the target is old enough that it doesn't have atomic instructions.
+
+Rust programs are output as ELF files.
+
+For running on hardware, you'll generally need to extract the "raw" program code
+out of the ELF and into a file of its own. The `objcopy` program provided as
+part of the GNU Binutils can do this:
+
+```shell
+arm-none-eabi-objcopy --output-target binary [in_file] [out_file]
+```
+
+## Testing
+
+This is a cross-compiled target that you will need to emulate during testing.
+
+Because this is a device-agnostic target, and the exact emulator that you'll
+need depends on the specific device you want to run your code on.
+
+For example, when programming for the Gameboy Advance, the
+[mgba-test-runner](https://github.com/agbrs/agb) program could be used to make a
+normal set of rust tests be run within the `mgba` emulator.
for bound in binding["binding"]["constraint"]:
check_generic_bound(bound)
elif "parenthesized" in args:
- for ty in args["parenthesized"]["inputs"]:
- check_type(ty)
+ for input_ty in args["parenthesized"]["inputs"]:
+ check_type(input_ty)
if args["parenthesized"]["output"]:
check_type(args["parenthesized"]["output"])
if not valid_id(ty["inner"]["id"]):
pub(crate) cx: &'a mut core::DocContext<'tcx>,
}
-impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
+impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx>
+where
+ 'tcx: 'a, // should be an implied bound; rustc bug #98852.
+{
pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> Self {
AutoTraitFinder { cx }
}
kind: Box::new(ImplItem(Box::new(Impl {
unsafety: hir::Unsafety::Normal,
generics: new_generics,
- trait_: Some(trait_ref.clean(self.cx)),
+ trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, &[])),
for_: clean_middle_ty(ty, self.cx, None),
items: Vec::new(),
polarity,
fn make_final_bounds(
&self,
ty_to_bounds: FxHashMap<Type, FxHashSet<GenericBound>>,
- ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)>,
+ ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)>,
lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<GenericBound>>,
) -> Vec<WherePredicate> {
ty_to_bounds
.into_iter()
.flat_map(|(ty, mut bounds)| {
- if let Some(data) = ty_to_fn.get(&ty) {
- let (poly_trait, output) =
- (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new));
+ if let Some((ref poly_trait, ref output)) = ty_to_fn.get(&ty) {
let mut new_path = poly_trait.trait_.clone();
let last_segment = new_path.segments.pop().expect("segments were empty");
GenericArgs::Parenthesized { inputs, output } => (inputs, output),
};
+ let output = output.as_ref().cloned().map(Box::new);
if old_output.is_some() && old_output != output {
- panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, data.1);
+ panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, output);
}
let new_params = GenericArgs::Parenthesized { inputs: old_input, output };
.push(PathSegment { name: last_segment.name, args: new_params });
bounds.insert(GenericBound::TraitBound(
- PolyTrait { trait_: new_path, generic_params: poly_trait.generic_params },
+ PolyTrait {
+ trait_: new_path,
+ generic_params: poly_trait.generic_params.clone(),
+ },
hir::TraitBoundModifier::None,
));
}
let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
let mut ty_to_traits: FxHashMap<Type, FxHashSet<Path>> = Default::default();
- let mut ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)> = Default::default();
+ let mut ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)> = Default::default();
for p in clean_where_predicates {
- let (orig_p, p) = (p, p.clean(self.cx));
+ let (orig_p, p) = (p, clean_predicate(p, self.cx));
if p.is_none() {
continue;
}
if is_fn {
ty_to_fn
.entry(ty.clone())
- .and_modify(|e| *e = (Some(poly_trait.clone()), e.1.clone()))
- .or_insert(((Some(poly_trait.clone())), None));
+ .and_modify(|e| *e = (poly_trait.clone(), e.1.clone()))
+ .or_insert(((poly_trait.clone()), None));
ty_to_bounds.entry(ty.clone()).or_default();
} else {
.and_modify(|e| {
*e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
})
- .or_insert((None, Some(rhs.ty().unwrap().clone())));
+ .or_insert((
+ PolyTrait {
+ trait_: trait_.clone(),
+ generic_params: Vec::new(),
+ },
+ Some(rhs.ty().unwrap().clone()),
+ ));
continue;
}
),
// FIXME(eddyb) compute both `trait_` and `for_` from
// the post-inference `trait_ref`, as it's more accurate.
- trait_: Some(trait_ref.0.clean(cx)),
+ trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, &[])),
for_: clean_middle_ty(ty.0, cx, None),
items: cx.tcx
.associated_items(impl_def_id)
.in_definition_order()
- .map(|x| x.clean(cx))
+ .map(|x| clean_middle_assoc_item(x, cx))
.collect::<Vec<_>>(),
polarity: ty::ImplPolarity::Positive,
kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))),
use rustc_span::symbol::{kw, sym, Symbol};
use crate::clean::{
- self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty, clean_ty,
+ self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item,
+ clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty,
clean_ty_generics, clean_variant_def, clean_visibility, utils, Attributes, AttributesExt,
- Clean, ImplKind, ItemId, Type, Visibility,
+ ImplKind, ItemId, Type, Visibility,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
cx: &mut DocContext<'_>,
res: Res,
visited: &mut FxHashSet<DefId>,
+ inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Option<Vec<clean::Item>> {
let did = res.opt_def_id()?;
if did.is_local() {
match res {
Res::Def(DefKind::Mod, did) => {
- let m = build_module(cx, did, visited);
- Some(m.items)
+ let mut items = build_module_items(cx, did, visited, inlined_names);
+ items.drain_filter(|item| {
+ if let Some(name) = item.name {
+ // If an item with the same type and name already exists,
+ // it takes priority over the inlined stuff.
+ !inlined_names.insert((item.type_(), name))
+ } else {
+ false
+ }
+ });
+ Some(items)
}
// glob imports on things like enums aren't inlined even for local exports, so just bail
_ => None,
// which causes methods to have a `pub` prefix, which is invalid since items in traits
// can not have a visibility prefix. Thus we override the visibility here manually.
// See https://github.com/rust-lang/rust/issues/81274
- clean::Item { visibility: Visibility::Inherited, ..item.clean(cx) }
+ clean::Item { visibility: Visibility::Inherited, ..clean_middle_assoc_item(item, cx) }
})
.collect();
both.extend_from_slice(old_attrs);
(
if let Some(new_id) = parent_module {
- Attributes::from_ast(old_attrs, Some((inner, new_id)))
+ Attributes::from_ast_with_additional(old_attrs, (inner, new_id))
} else {
- Attributes::from_ast(&both, None)
+ Attributes::from_ast(&both)
},
both.cfg(cx.tcx, &cx.cache.hidden_cfg),
)
} else {
- (old_attrs.clean(cx), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
+ (Attributes::from_ast(&old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
}
}
true
}
})
- .map(|item| item.clean(cx))
+ .map(|item| clean_impl_item(item, cx))
.collect::<Vec<_>>(),
- impl_.generics.clean(cx),
+ clean_generics(impl_.generics, cx),
),
None => (
tcx.associated_items(did)
.unwrap(); // corresponding associated item has to exist
!tcx.is_doc_hidden(trait_item.def_id)
} else {
- item.vis.is_public()
+ item.visibility(tcx).is_public()
}
})
- .map(|item| item.clean(cx))
+ .map(|item| clean_middle_assoc_item(item, cx))
.collect::<Vec<_>>(),
clean::enter_impl_trait(cx, |cx| {
clean_ty_generics(cx, tcx.generics_of(did), predicates)
),
};
let polarity = tcx.impl_polarity(did);
- let trait_ = associated_trait.map(|t| t.clean(cx));
+ let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, &[]));
if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
super::build_deref_target_impls(cx, &trait_items, ret);
}
did: DefId,
visited: &mut FxHashSet<DefId>,
) -> clean::Module {
+ let items = build_module_items(cx, did, visited, &mut FxHashSet::default());
+
+ let span = clean::Span::new(cx.tcx.def_span(did));
+ clean::Module { items, span }
+}
+
+fn build_module_items(
+ cx: &mut DocContext<'_>,
+ did: DefId,
+ visited: &mut FxHashSet<DefId>,
+ inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
+) -> Vec<clean::Item> {
let mut items = Vec::new();
// If we're re-exporting a re-export it may actually re-export something in
if item.vis.is_public() {
let res = item.res.expect_non_local();
if let Some(def_id) = res.mod_def_id() {
- if did == def_id || !visited.insert(def_id) {
+ // If we're inlining a glob import, it's possible to have
+ // two distinct modules with the same name. We don't want to
+ // inline it, or mark any of its contents as visited.
+ if did == def_id
+ || inlined_names.contains(&(ItemType::Module, item.ident.name))
+ || !visited.insert(def_id)
+ {
continue;
}
}
}
}
- let span = clean::Span::new(cx.tcx.def_span(did));
- clean::Module { items, span }
+ items
}
pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
fn clean(&self, cx: &mut DocContext<'tcx>) -> T;
}
-impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
- let mut items: Vec<Item> = vec![];
- items.extend(
- self.foreigns
- .iter()
- .map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
- );
- items.extend(self.mods.iter().map(|x| x.clean(cx)));
-
- // Split up imports from all other items.
- //
- // This covers the case where somebody does an import which should pull in an item,
- // but there's already an item with the same namespace and same name. Rust gives
- // priority to the not-imported one, so we should, too.
- let mut inserted = FxHashSet::default();
- items.extend(self.items.iter().flat_map(|(item, renamed)| {
- // First, lower everything other than imports.
- if matches!(item.kind, hir::ItemKind::Use(..)) {
- return Vec::new();
- }
- let v = clean_maybe_renamed_item(cx, item, *renamed);
- for item in &v {
- if let Some(name) = item.name {
- inserted.insert((item.type_(), name));
- }
- }
- v
- }));
- items.extend(self.items.iter().flat_map(|(item, renamed)| {
- // Now we actually lower the imports, skipping everything else.
- if !matches!(item.kind, hir::ItemKind::Use(..)) {
- return Vec::new();
- }
- let mut v = clean_maybe_renamed_item(cx, item, *renamed);
- v.drain_filter(|item| {
- if let Some(name) = item.name {
- // If an item with the same type and name already exists,
- // it takes priority over the inlined stuff.
- !inserted.insert((item.type_(), name))
- } else {
- false
- }
- });
- v
- }));
-
- // determine if we should display the inner contents or
- // the outer `mod` item for the source code.
-
- let span = Span::new({
- let where_outer = self.where_outer(cx.tcx);
- let sm = cx.sess().source_map();
- let outer = sm.lookup_char_pos(where_outer.lo());
- let inner = sm.lookup_char_pos(self.where_inner.lo());
- if outer.file.start_pos == inner.file.start_pos {
- // mod foo { ... }
- where_outer
- } else {
- // mod foo; (and a separate SourceFile for the contents)
- self.where_inner
+pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+ let mut items: Vec<Item> = vec![];
+ let mut inserted = FxHashSet::default();
+ items.extend(doc.foreigns.iter().map(|(item, renamed)| {
+ let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
+ if let Some(name) = item.name {
+ inserted.insert((item.type_(), name));
+ }
+ item
+ }));
+ items.extend(doc.mods.iter().map(|x| {
+ inserted.insert((ItemType::Module, x.name));
+ clean_doc_module(x, cx)
+ }));
+
+ // Split up imports from all other items.
+ //
+ // This covers the case where somebody does an import which should pull in an item,
+ // but there's already an item with the same namespace and same name. Rust gives
+ // priority to the not-imported one, so we should, too.
+ items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+ // First, lower everything other than imports.
+ if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
+ return Vec::new();
+ }
+ let v = clean_maybe_renamed_item(cx, item, *renamed);
+ for item in &v {
+ if let Some(name) = item.name {
+ inserted.insert((item.type_(), name));
}
- });
-
- Item::from_hir_id_and_parts(
- self.id,
- Some(self.name),
- ModuleItem(Module { items, span }),
- cx,
- )
- }
-}
+ }
+ v
+ }));
+ items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+ // Now we actually lower the imports, skipping everything else.
+ if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
+ let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
+ clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
+ } else {
+ // skip everything else
+ Vec::new()
+ }
+ }));
+
+ // determine if we should display the inner contents or
+ // the outer `mod` item for the source code.
+
+ let span = Span::new({
+ let where_outer = doc.where_outer(cx.tcx);
+ let sm = cx.sess().source_map();
+ let outer = sm.lookup_char_pos(where_outer.lo());
+ let inner = sm.lookup_char_pos(doc.where_inner.lo());
+ if outer.file.start_pos == inner.file.start_pos {
+ // mod foo { ... }
+ where_outer
+ } else {
+ // mod foo; (and a separate SourceFile for the contents)
+ doc.where_inner
+ }
+ });
-impl<'tcx> Clean<'tcx, Attributes> for [ast::Attribute] {
- fn clean(&self, _cx: &mut DocContext<'_>) -> Attributes {
- Attributes::from_ast(self, None)
- }
+ Item::from_hir_id_and_parts(doc.id, Some(doc.name), ModuleItem(Module { items, span }), cx)
}
-impl<'tcx> Clean<'tcx, Option<GenericBound>> for hir::GenericBound<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<GenericBound> {
- Some(match *self {
- hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
- 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).skip_binder();
-
- let generic_args = generic_args.clean(cx);
- let GenericArgs::AngleBracketed { bindings, .. } = generic_args
- else {
- bug!("clean: parenthesized `GenericBound::LangItemTrait`");
- };
+fn clean_generic_bound<'tcx>(
+ bound: &hir::GenericBound<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> Option<GenericBound> {
+ Some(match *bound {
+ hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
+ 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).skip_binder();
+
+ let generic_args = clean_generic_args(generic_args, cx);
+ let GenericArgs::AngleBracketed { bindings, .. } = generic_args
+ else {
+ bug!("clean: parenthesized `GenericBound::LangItemTrait`");
+ };
- let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
- GenericBound::TraitBound(
- PolyTrait { trait_, generic_params: vec![] },
- hir::TraitBoundModifier::None,
- )
+ let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
+ GenericBound::TraitBound(
+ PolyTrait { trait_, generic_params: vec![] },
+ hir::TraitBoundModifier::None,
+ )
+ }
+ hir::GenericBound::Trait(ref t, modifier) => {
+ // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
+ if modifier == hir::TraitBoundModifier::MaybeConst
+ && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
+ {
+ return None;
}
- hir::GenericBound::Trait(ref t, modifier) => {
- // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
- if modifier == hir::TraitBoundModifier::MaybeConst
- && cx.tcx.lang_items().destruct_trait()
- == Some(t.trait_ref.trait_def_id().unwrap())
- {
- return None;
- }
- GenericBound::TraitBound(t.clean(cx), modifier)
- }
- })
- }
+ GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
+ }
+ })
}
-fn clean_trait_ref_with_bindings<'tcx>(
+pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
cx: &mut DocContext<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
bindings: &[TypeBinding],
path
}
-impl<'tcx> Clean<'tcx, Path> for ty::TraitRef<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
- clean_trait_ref_with_bindings(cx, *self, &[])
- }
-}
-
fn clean_poly_trait_ref_with_bindings<'tcx>(
cx: &mut DocContext<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
)
}
-impl<'tcx> Clean<'tcx, GenericBound> for ty::PolyTraitRef<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericBound {
- clean_poly_trait_ref_with_bindings(cx, *self, &[])
- }
-}
-
-impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Lifetime {
- let def = cx.tcx.named_region(self.hir_id);
- if let Some(
- rl::Region::EarlyBound(_, node_id)
- | rl::Region::LateBound(_, _, node_id)
- | rl::Region::Free(_, node_id),
- ) = def
- {
- if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
- return lt;
- }
+fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
+ let def = cx.tcx.named_region(lifetime.hir_id);
+ if let Some(
+ rl::Region::EarlyBound(_, node_id)
+ | rl::Region::LateBound(_, _, node_id)
+ | rl::Region::Free(_, node_id),
+ ) = def
+ {
+ if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
+ return lt;
}
- Lifetime(self.name.ident().name)
}
+ Lifetime(lifetime.name.ident().name)
}
pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant {
}
}
-impl<'tcx> Clean<'tcx, Option<Lifetime>> for ty::Region<'tcx> {
- fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
- match **self {
- ty::ReStatic => Some(Lifetime::statik()),
- ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
- if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
- }
- ty::ReEarlyBound(ref data) => {
- if data.name != kw::UnderscoreLifetime {
- Some(Lifetime(data.name))
- } else {
- None
- }
- }
- ty::ReLateBound(..)
- | ty::ReFree(..)
- | ty::ReVar(..)
- | ty::RePlaceholder(..)
- | ty::ReEmpty(_)
- | ty::ReErased => {
- debug!("cannot clean region {:?}", self);
+pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> {
+ match *region {
+ ty::ReStatic => Some(Lifetime::statik()),
+ ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
+ if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
+ }
+ ty::ReEarlyBound(ref data) => {
+ if data.name != kw::UnderscoreLifetime {
+ Some(Lifetime(data.name))
+ } else {
None
}
}
+ ty::ReLateBound(..)
+ | ty::ReFree(..)
+ | ty::ReVar(..)
+ | ty::RePlaceholder(..)
+ | ty::ReEmpty(_)
+ | ty::ReErased => {
+ debug!("cannot clean region {:?}", region);
+ None
+ }
}
}
-impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
- if !self.in_where_clause() {
- return None;
- }
- Some(match *self {
- hir::WherePredicate::BoundPredicate(ref wbp) => {
- let bound_params = wbp
- .bound_generic_params
- .iter()
- .map(|param| {
- // Higher-ranked params must be lifetimes.
- // Higher-ranked lifetimes can't have bounds.
- assert_matches!(
- param,
- hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
- );
- Lifetime(param.name.ident().name)
- })
- .collect();
- WherePredicate::BoundPredicate {
- ty: clean_ty(wbp.bounded_ty, cx),
- bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
- bound_params,
- }
+fn clean_where_predicate<'tcx>(
+ predicate: &hir::WherePredicate<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+ if !predicate.in_where_clause() {
+ return None;
+ }
+ Some(match *predicate {
+ hir::WherePredicate::BoundPredicate(ref wbp) => {
+ let bound_params = wbp
+ .bound_generic_params
+ .iter()
+ .map(|param| {
+ // Higher-ranked params must be lifetimes.
+ // Higher-ranked lifetimes can't have bounds.
+ assert_matches!(
+ param,
+ hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
+ );
+ Lifetime(param.name.ident().name)
+ })
+ .collect();
+ WherePredicate::BoundPredicate {
+ ty: clean_ty(wbp.bounded_ty, cx),
+ bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+ bound_params,
}
+ }
- hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
- lifetime: wrp.lifetime.clean(cx),
- bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
- },
+ hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
+ lifetime: clean_lifetime(wrp.lifetime, cx),
+ bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+ },
- hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
- lhs: clean_ty(wrp.lhs_ty, cx),
- rhs: clean_ty(wrp.rhs_ty, cx).into(),
- },
- })
- }
+ hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
+ lhs: clean_ty(wrp.lhs_ty, cx),
+ rhs: clean_ty(wrp.rhs_ty, cx).into(),
+ },
+ })
}
-impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::Predicate<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
- let bound_predicate = self.kind();
- match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(pred) => {
- clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
- }
- ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred, cx),
- ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
- ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
- ty::PredicateKind::ConstEvaluatable(..) => None,
- ty::PredicateKind::WellFormed(..) => None,
-
- ty::PredicateKind::Subtype(..)
- | ty::PredicateKind::Coerce(..)
- | ty::PredicateKind::ObjectSafe(..)
- | ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
+pub(crate) fn clean_predicate<'tcx>(
+ predicate: ty::Predicate<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> Option<WherePredicate> {
+ let bound_predicate = predicate.kind();
+ match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(pred) => {
+ clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
}
+ ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
+ ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
+ ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
+ ty::PredicateKind::ConstEvaluatable(..) => None,
+ ty::PredicateKind::WellFormed(..) => None,
+
+ ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
}
}
let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
Some(WherePredicate::BoundPredicate {
ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
- bounds: vec![poly_trait_ref.clean(cx)],
+ bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, &[])],
bound_params: Vec::new(),
})
}
fn clean_region_outlives_predicate<'tcx>(
pred: ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>,
- cx: &mut DocContext<'tcx>,
) -> Option<WherePredicate> {
let ty::OutlivesPredicate(a, b) = pred;
}
Some(WherePredicate::RegionPredicate {
- lifetime: a.clean(cx).expect("failed to clean lifetime"),
- bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))],
+ lifetime: clean_middle_region(a).expect("failed to clean lifetime"),
+ bounds: vec![GenericBound::Outlives(
+ clean_middle_region(b).expect("failed to clean bounds"),
+ )],
})
}
Some(WherePredicate::BoundPredicate {
ty: clean_middle_ty(ty, cx, None),
- bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
+ bounds: vec![GenericBound::Outlives(
+ clean_middle_region(lt).expect("failed to clean lifetimes"),
+ )],
bound_params: Vec::new(),
})
}
def_id: Option<DefId>,
) -> Type {
let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
- let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
+ let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), &[]);
let self_type = clean_middle_ty(ty.self_ty(), cx, None);
let self_def_id = if let Some(def_id) = def_id {
cx.tcx.opt_parent(def_id).or(Some(def_id))
.filter(|bp| !bp.in_where_clause)
.flat_map(|bp| bp.bounds)
.map(|bound| match bound {
- hir::GenericBound::Outlives(lt) => lt.clean(cx),
+ hir::GenericBound::Outlives(lt) => clean_lifetime(*lt, cx),
_ => panic!(),
})
.collect()
.bounds_for_param(did)
.filter(|bp| bp.origin != PredicateOrigin::WhereClause)
.flat_map(|bp| bp.bounds)
- .filter_map(|x| x.clean(cx))
+ .filter_map(|x| clean_generic_bound(x, cx))
.collect()
} else {
Vec::new()
matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided })
}
-impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics {
- let impl_trait_params = self
- .params
- .iter()
- .filter(|param| is_impl_trait(param))
- .map(|param| {
- let param = clean_generic_param(cx, Some(self), param);
- match param.kind {
- GenericParamDefKind::Lifetime { .. } => unreachable!(),
- GenericParamDefKind::Type { did, ref bounds, .. } => {
- cx.impl_trait_bounds.insert(did.into(), bounds.clone());
- }
- GenericParamDefKind::Const { .. } => unreachable!(),
+pub(crate) fn clean_generics<'tcx>(
+ gens: &hir::Generics<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> Generics {
+ let impl_trait_params = gens
+ .params
+ .iter()
+ .filter(|param| is_impl_trait(param))
+ .map(|param| {
+ let param = clean_generic_param(cx, Some(gens), param);
+ match param.kind {
+ GenericParamDefKind::Lifetime { .. } => unreachable!(),
+ GenericParamDefKind::Type { did, ref bounds, .. } => {
+ cx.impl_trait_bounds.insert(did.into(), bounds.clone());
}
- param
- })
- .collect::<Vec<_>>();
+ GenericParamDefKind::Const { .. } => unreachable!(),
+ }
+ param
+ })
+ .collect::<Vec<_>>();
- let mut params = Vec::with_capacity(self.params.len());
- for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
- let p = clean_generic_param(cx, Some(self), p);
- params.push(p);
- }
- params.extend(impl_trait_params);
+ let mut params = Vec::with_capacity(gens.params.len());
+ for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
+ let p = clean_generic_param(cx, Some(gens), p);
+ params.push(p);
+ }
+ params.extend(impl_trait_params);
- let mut generics = Generics {
- params,
- where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(),
- };
+ let mut generics = Generics {
+ params,
+ where_predicates: gens
+ .predicates
+ .iter()
+ .filter_map(|x| clean_where_predicate(x, cx))
+ .collect(),
+ };
- // Some duplicates are generated for ?Sized bounds between type params and where
- // predicates. The point in here is to move the bounds definitions from type params
- // to where predicates when such cases occur.
- for where_pred in &mut generics.where_predicates {
- match *where_pred {
- WherePredicate::BoundPredicate {
- ty: Generic(ref name), ref mut bounds, ..
- } => {
- if bounds.is_empty() {
- for param in &mut generics.params {
- match param.kind {
- GenericParamDefKind::Lifetime { .. } => {}
- GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
- if ¶m.name == name {
- mem::swap(bounds, ty_bounds);
- break;
- }
+ // Some duplicates are generated for ?Sized bounds between type params and where
+ // predicates. The point in here is to move the bounds definitions from type params
+ // to where predicates when such cases occur.
+ for where_pred in &mut generics.where_predicates {
+ match *where_pred {
+ WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => {
+ if bounds.is_empty() {
+ for param in &mut generics.params {
+ match param.kind {
+ GenericParamDefKind::Lifetime { .. } => {}
+ GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
+ if ¶m.name == name {
+ mem::swap(bounds, ty_bounds);
+ break;
}
- GenericParamDefKind::Const { .. } => {}
}
+ GenericParamDefKind::Const { .. } => {}
}
}
}
- _ => continue,
}
+ _ => continue,
}
- generics
}
+ generics
}
fn clean_ty_generics<'tcx>(
if let Some(param_idx) = param_idx {
if let Some(b) = impl_trait.get_mut(¶m_idx.into()) {
- let p: WherePredicate = p.clean(cx)?;
+ let p: WherePredicate = clean_predicate(*p, cx)?;
b.extend(
p.get_bounds()
// Now that `cx.impl_trait_bounds` is populated, we can process
// remaining predicates which could contain `impl Trait`.
let mut where_predicates =
- where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
+ where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
// Type parameters have a Sized bound by default unless removed with
// ?Sized. Scan through the predicates and mark any type parameter with
) -> Box<Function> {
let (generics, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
- let generics = generics.clean(cx);
+ let generics = clean_generics(generics, cx);
let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
let decl = clean_fn_decl_with_args(cx, sig.decl, args);
(generics, decl)
decl: &hir::FnDecl<'tcx>,
args: Arguments,
) -> FnDecl {
- FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic }
+ let output = match decl.output {
+ hir::FnRetTy::Return(typ) => Return(clean_ty(typ, cx)),
+ hir::FnRetTy::DefaultReturn(..) => DefaultReturn,
+ };
+ FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
}
fn clean_fn_decl_from_did_and_sig<'tcx>(
}
}
-impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy {
- match *self {
- Self::Return(typ) => Return(clean_ty(typ, cx)),
- Self::DefaultReturn(..) => DefaultReturn,
- }
- }
-}
-
-impl<'tcx> Clean<'tcx, bool> for hir::IsAuto {
- fn clean(&self, _: &mut DocContext<'tcx>) -> bool {
- match *self {
- hir::IsAuto::Yes => true,
- hir::IsAuto::No => false,
- }
- }
-}
-
-impl<'tcx> Clean<'tcx, Path> for hir::TraitRef<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
- let path = clean_path(self.path, cx);
- register_res(cx, path.res);
- path
- }
+fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
+ let path = clean_path(trait_ref.path, cx);
+ register_res(cx, path.res);
+ path
}
-impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> PolyTrait {
- PolyTrait {
- trait_: self.trait_ref.clean(cx),
- generic_params: self
- .bound_generic_params
- .iter()
- .filter(|p| !is_elided_lifetime(p))
- .map(|x| clean_generic_param(cx, None, x))
- .collect(),
- }
+fn clean_poly_trait_ref<'tcx>(
+ poly_trait_ref: &hir::PolyTraitRef<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> PolyTrait {
+ PolyTrait {
+ trait_: clean_trait_ref(&poly_trait_ref.trait_ref, cx),
+ generic_params: poly_trait_ref
+ .bound_generic_params
+ .iter()
+ .filter(|p| !is_elided_lifetime(p))
+ .map(|x| clean_generic_param(cx, None, x))
+ .collect(),
}
}
-impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
- let local_did = self.def_id.to_def_id();
- cx.with_param_env(local_did, |cx| {
- let inner = match self.kind {
- hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
- clean_ty(ty, cx),
- ConstantKind::Local { def_id: local_did, body: default },
- ),
- hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- let m = clean_function(cx, sig, self.generics, body);
- MethodItem(m, None)
- }
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
- let (generics, decl) = enter_impl_trait(cx, |cx| {
- // NOTE: generics must be cleaned before args
- let generics = self.generics.clean(cx);
- let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
- let decl = clean_fn_decl_with_args(cx, sig.decl, args);
- (generics, decl)
- });
- TyMethodItem(Box::new(Function { decl, generics }))
- }
- hir::TraitItemKind::Type(bounds, Some(default)) => {
- let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
- let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
- let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
- AssocTypeItem(
- Box::new(Typedef {
- type_: clean_ty(default, cx),
- generics,
- item_type: Some(item_type),
- }),
- bounds,
- )
- }
- hir::TraitItemKind::Type(bounds, None) => {
- let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
- let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
- TyAssocTypeItem(Box::new(generics), bounds)
- }
- };
- let what_rustc_thinks =
- Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
- // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
- Item { visibility: Inherited, ..what_rustc_thinks }
- })
- }
+fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+ let local_did = trait_item.def_id.to_def_id();
+ cx.with_param_env(local_did, |cx| {
+ let inner = match trait_item.kind {
+ hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
+ clean_ty(ty, cx),
+ ConstantKind::Local { def_id: local_did, body: default },
+ ),
+ hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
+ hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
+ let m = clean_function(cx, sig, trait_item.generics, body);
+ MethodItem(m, None)
+ }
+ hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
+ let (generics, decl) = enter_impl_trait(cx, |cx| {
+ // NOTE: generics must be cleaned before args
+ let generics = clean_generics(trait_item.generics, cx);
+ let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
+ let decl = clean_fn_decl_with_args(cx, sig.decl, args);
+ (generics, decl)
+ });
+ TyMethodItem(Box::new(Function { decl, generics }))
+ }
+ hir::TraitItemKind::Type(bounds, Some(default)) => {
+ let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
+ let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
+ let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
+ AssocTypeItem(
+ Box::new(Typedef {
+ type_: clean_ty(default, cx),
+ generics,
+ item_type: Some(item_type),
+ }),
+ bounds,
+ )
+ }
+ hir::TraitItemKind::Type(bounds, None) => {
+ let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
+ let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
+ TyAssocTypeItem(Box::new(generics), bounds)
+ }
+ };
+ let what_rustc_thinks =
+ Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx);
+ // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
+ Item { visibility: Inherited, ..what_rustc_thinks }
+ })
}
-impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
- let local_did = self.def_id.to_def_id();
- cx.with_param_env(local_did, |cx| {
- let inner = match self.kind {
- hir::ImplItemKind::Const(ty, expr) => {
- let default = ConstantKind::Local { def_id: local_did, body: expr };
- AssocConstItem(clean_ty(ty, cx), default)
- }
- hir::ImplItemKind::Fn(ref sig, body) => {
- let m = clean_function(cx, sig, self.generics, body);
- let defaultness = cx.tcx.associated_item(self.def_id).defaultness;
- MethodItem(m, Some(defaultness))
- }
- hir::ImplItemKind::TyAlias(hir_ty) => {
- let type_ = clean_ty(hir_ty, cx);
- let generics = self.generics.clean(cx);
- let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
- AssocTypeItem(
- Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
- Vec::new(),
- )
- }
- };
+pub(crate) fn clean_impl_item<'tcx>(
+ impl_: &hir::ImplItem<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> Item {
+ let local_did = impl_.def_id.to_def_id();
+ cx.with_param_env(local_did, |cx| {
+ let inner = match impl_.kind {
+ hir::ImplItemKind::Const(ty, expr) => {
+ let default = ConstantKind::Local { def_id: local_did, body: expr };
+ AssocConstItem(clean_ty(ty, cx), default)
+ }
+ hir::ImplItemKind::Fn(ref sig, body) => {
+ let m = clean_function(cx, sig, impl_.generics, body);
+ let defaultness = cx.tcx.impl_defaultness(impl_.def_id);
+ MethodItem(m, Some(defaultness))
+ }
+ hir::ImplItemKind::TyAlias(hir_ty) => {
+ let type_ = clean_ty(hir_ty, cx);
+ let generics = clean_generics(impl_.generics, cx);
+ let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
+ AssocTypeItem(
+ Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
+ Vec::new(),
+ )
+ }
+ };
- let mut what_rustc_thinks =
- Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
+ let mut what_rustc_thinks =
+ Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx);
- let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id));
+ let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id));
- // Trait impl items always inherit the impl's visibility --
- // we don't want to show `pub`.
- if impl_ref.is_some() {
- what_rustc_thinks.visibility = Inherited;
- }
+ // Trait impl items always inherit the impl's visibility --
+ // we don't want to show `pub`.
+ if impl_ref.is_some() {
+ what_rustc_thinks.visibility = Inherited;
+ }
- what_rustc_thinks
- })
- }
+ what_rustc_thinks
+ })
}
-impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
- let tcx = cx.tcx;
- let kind = match self.kind {
- ty::AssocKind::Const => {
- let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id));
-
- let provided = match self.container {
- ty::ImplContainer(_) => true,
- ty::TraitContainer(_) => self.defaultness.has_value(),
- };
- if provided {
- AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id })
- } else {
- TyAssocConstItem(ty)
- }
+pub(crate) fn clean_middle_assoc_item<'tcx>(
+ assoc_item: &ty::AssocItem,
+ cx: &mut DocContext<'tcx>,
+) -> Item {
+ let tcx = cx.tcx;
+ let kind = match assoc_item.kind {
+ ty::AssocKind::Const => {
+ let ty = clean_middle_ty(tcx.type_of(assoc_item.def_id), cx, Some(assoc_item.def_id));
+
+ let provided = match assoc_item.container {
+ ty::ImplContainer => true,
+ ty::TraitContainer => tcx.impl_defaultness(assoc_item.def_id).has_value(),
+ };
+ if provided {
+ AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id })
+ } else {
+ TyAssocConstItem(ty)
}
- ty::AssocKind::Fn => {
- let generics = clean_ty_generics(
- cx,
- tcx.generics_of(self.def_id),
- tcx.explicit_predicates_of(self.def_id),
- );
- let sig = tcx.fn_sig(self.def_id);
- let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(self.def_id), sig);
-
- if self.fn_has_self_parameter {
- let self_ty = match self.container {
- ty::ImplContainer(def_id) => tcx.type_of(def_id),
- ty::TraitContainer(_) => tcx.types.self_param,
- };
- let self_arg_ty = sig.input(0).skip_binder();
- if self_arg_ty == self_ty {
- decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
- } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
- if ty == self_ty {
- match decl.inputs.values[0].type_ {
- BorrowedRef { ref mut type_, .. } => {
- **type_ = Generic(kw::SelfUpper)
- }
- _ => unreachable!(),
- }
+ }
+ ty::AssocKind::Fn => {
+ let generics = clean_ty_generics(
+ cx,
+ tcx.generics_of(assoc_item.def_id),
+ tcx.explicit_predicates_of(assoc_item.def_id),
+ );
+ let sig = tcx.fn_sig(assoc_item.def_id);
+ let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
+
+ if assoc_item.fn_has_self_parameter {
+ let self_ty = match assoc_item.container {
+ ty::ImplContainer => tcx.type_of(assoc_item.container_id(tcx)),
+ ty::TraitContainer => tcx.types.self_param,
+ };
+ let self_arg_ty = sig.input(0).skip_binder();
+ if self_arg_ty == self_ty {
+ decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
+ } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
+ if ty == self_ty {
+ match decl.inputs.values[0].type_ {
+ BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
+ _ => unreachable!(),
}
}
}
+ }
- let provided = match self.container {
- ty::ImplContainer(_) => true,
- ty::TraitContainer(_) => self.defaultness.has_value(),
+ let provided = match assoc_item.container {
+ ty::ImplContainer => true,
+ ty::TraitContainer => assoc_item.defaultness(tcx).has_value(),
+ };
+ if provided {
+ let defaultness = match assoc_item.container {
+ ty::ImplContainer => Some(assoc_item.defaultness(tcx)),
+ ty::TraitContainer => None,
};
- if provided {
- let defaultness = match self.container {
- ty::ImplContainer(_) => Some(self.defaultness),
- ty::TraitContainer(_) => None,
- };
- MethodItem(Box::new(Function { generics, decl }), defaultness)
- } else {
- TyMethodItem(Box::new(Function { generics, decl }))
- }
+ MethodItem(Box::new(Function { generics, decl }), defaultness)
+ } else {
+ TyMethodItem(Box::new(Function { generics, decl }))
}
- ty::AssocKind::Type => {
- let my_name = self.name;
-
- fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
- match (¶m.kind, arg) {
- (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
- if *ty == param.name =>
- {
- true
- }
- (
- GenericParamDefKind::Lifetime { .. },
- GenericArg::Lifetime(Lifetime(lt)),
- ) if *lt == param.name => true,
- (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => {
- match &c.kind {
- ConstantKind::TyConst { expr } => expr == param.name.as_str(),
- _ => false,
- }
- }
- _ => false,
+ }
+ ty::AssocKind::Type => {
+ let my_name = assoc_item.name;
+
+ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
+ match (¶m.kind, arg) {
+ (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
+ if *ty == param.name =>
+ {
+ true
+ }
+ (GenericParamDefKind::Lifetime { .. }, GenericArg::Lifetime(Lifetime(lt)))
+ if *lt == param.name =>
+ {
+ true
}
+ (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
+ ConstantKind::TyConst { expr } => expr == param.name.as_str(),
+ _ => false,
+ },
+ _ => false,
}
+ }
- if let ty::TraitContainer(_) = self.container {
- let bounds = tcx.explicit_item_bounds(self.def_id);
- let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
- let mut generics =
- clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
- // Filter out the bounds that are (likely?) directly attached to the associated type,
- // as opposed to being located in the where clause.
- let mut bounds = generics
- .where_predicates
- .drain_filter(|pred| match *pred {
- WherePredicate::BoundPredicate {
- ty: QPath { ref assoc, ref self_type, ref trait_, .. },
- ..
- } => {
- if assoc.name != my_name {
- return false;
- }
- if trait_.def_id() != self.container.id() {
- return false;
- }
- match **self_type {
- Generic(ref s) if *s == kw::SelfUpper => {}
- _ => return false,
- }
- match &assoc.args {
- GenericArgs::AngleBracketed { args, bindings } => {
- if !bindings.is_empty()
- || generics
- .params
- .iter()
- .zip(args.iter())
- .any(|(param, arg)| !param_eq_arg(param, arg))
- {
- return false;
- }
- }
- GenericArgs::Parenthesized { .. } => {
- // The only time this happens is if we're inside the rustdoc for Fn(),
- // which only has one associated type, which is not a GAT, so whatever.
+ if let ty::TraitContainer = assoc_item.container {
+ let bounds = tcx.explicit_item_bounds(assoc_item.def_id);
+ let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
+ let mut generics =
+ clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates);
+ // Filter out the bounds that are (likely?) directly attached to the associated type,
+ // as opposed to being located in the where clause.
+ let mut bounds = generics
+ .where_predicates
+ .drain_filter(|pred| match *pred {
+ WherePredicate::BoundPredicate {
+ ty: QPath { ref assoc, ref self_type, ref trait_, .. },
+ ..
+ } => {
+ if assoc.name != my_name {
+ return false;
+ }
+ if trait_.def_id() != assoc_item.container_id(tcx) {
+ return false;
+ }
+ match **self_type {
+ Generic(ref s) if *s == kw::SelfUpper => {}
+ _ => return false,
+ }
+ match &assoc.args {
+ GenericArgs::AngleBracketed { args, bindings } => {
+ if !bindings.is_empty()
+ || generics
+ .params
+ .iter()
+ .zip(args.iter())
+ .any(|(param, arg)| !param_eq_arg(param, arg))
+ {
+ return false;
}
}
- true
- }
- _ => false,
- })
- .flat_map(|pred| {
- if let WherePredicate::BoundPredicate { bounds, .. } = pred {
- bounds
- } else {
- unreachable!()
+ GenericArgs::Parenthesized { .. } => {
+ // The only time this happens is if we're inside the rustdoc for Fn(),
+ // which only has one associated type, which is not a GAT, so whatever.
+ }
}
- })
- .collect::<Vec<_>>();
- // Our Sized/?Sized bound didn't get handled when creating the generics
- // because we didn't actually get our whole set of bounds until just now
- // (some of them may have come from the trait). If we do have a sized
- // bound, we remove it, and if we don't then we add the `?Sized` bound
- // at the end.
- match bounds.iter().position(|b| b.is_sized_bound(cx)) {
- Some(i) => {
- bounds.remove(i);
+ true
}
- None => bounds.push(GenericBound::maybe_sized(cx)),
+ _ => false,
+ })
+ .flat_map(|pred| {
+ if let WherePredicate::BoundPredicate { bounds, .. } = pred {
+ bounds
+ } else {
+ unreachable!()
+ }
+ })
+ .collect::<Vec<_>>();
+ // Our Sized/?Sized bound didn't get handled when creating the generics
+ // because we didn't actually get our whole set of bounds until just now
+ // (some of them may have come from the trait). If we do have a sized
+ // bound, we remove it, and if we don't then we add the `?Sized` bound
+ // at the end.
+ match bounds.iter().position(|b| b.is_sized_bound(cx)) {
+ Some(i) => {
+ bounds.remove(i);
}
+ None => bounds.push(GenericBound::maybe_sized(cx)),
+ }
- if self.defaultness.has_value() {
- AssocTypeItem(
- Box::new(Typedef {
- type_: clean_middle_ty(
- tcx.type_of(self.def_id),
- cx,
- Some(self.def_id),
- ),
- generics,
- // FIXME: should we obtain the Type from HIR and pass it on here?
- item_type: None,
- }),
- bounds,
- )
- } else {
- TyAssocTypeItem(Box::new(generics), bounds)
- }
- } else {
- // FIXME: when could this happen? Associated items in inherent impls?
+ if tcx.impl_defaultness(assoc_item.def_id).has_value() {
AssocTypeItem(
Box::new(Typedef {
- type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)),
- generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
+ type_: clean_middle_ty(
+ tcx.type_of(assoc_item.def_id),
+ cx,
+ Some(assoc_item.def_id),
+ ),
+ generics,
+ // FIXME: should we obtain the Type from HIR and pass it on here?
item_type: None,
}),
- Vec::new(),
+ bounds,
)
+ } else {
+ TyAssocTypeItem(Box::new(generics), bounds)
}
+ } else {
+ // FIXME: when could this happen? Associated items in inherent impls?
+ AssocTypeItem(
+ Box::new(Typedef {
+ type_: clean_middle_ty(
+ tcx.type_of(assoc_item.def_id),
+ cx,
+ Some(assoc_item.def_id),
+ ),
+ generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
+ item_type: None,
+ }),
+ Vec::new(),
+ )
}
- };
+ }
+ };
- let mut what_rustc_thinks =
- Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx);
+ let mut what_rustc_thinks =
+ Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx);
- let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id));
+ let impl_ref = tcx.impl_trait_ref(tcx.parent(assoc_item.def_id));
- // Trait impl items always inherit the impl's visibility --
- // we don't want to show `pub`.
- if impl_ref.is_some() {
- what_rustc_thinks.visibility = Visibility::Inherited;
- }
-
- what_rustc_thinks
+ // Trait impl items always inherit the impl's visibility --
+ // we don't want to show `pub`.
+ if impl_ref.is_some() {
+ what_rustc_thinks.visibility = Visibility::Inherited;
}
+
+ what_rustc_thinks
}
fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
}
let trait_segments = &p.segments[..p.segments.len() - 1];
- let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
+ let trait_def = cx.tcx.associated_item(p.res.def_id()).container_id(cx.tcx);
let trait_ = self::Path {
res: Res::Def(DefKind::Trait, trait_def),
segments: trait_segments.iter().map(|x| x.clean(cx)).collect(),
});
if let Some(lt) = lifetime.cloned() {
let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let cleaned = if !lt.is_elided() { lt.clean(cx) } else { Lifetime::elided() };
+ let cleaned =
+ if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() };
substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
}
indices.lifetimes += 1;
// there's no case where it could cause the function to fail to compile.
let elided =
l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
- let lifetime = if elided { None } else { Some(l.clean(cx)) };
+ let lifetime = if elided { None } else { Some(clean_lifetime(*l, cx)) };
BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
}
TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
TyKind::OpaqueDef(item_id, _) => {
let item = cx.tcx.hir().item(item_id);
if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
- ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
+ ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
} else {
unreachable!()
}
}
TyKind::Path(_) => clean_qpath(ty, cx),
TyKind::TraitObject(bounds, ref lifetime, _) => {
- let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
- let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
+ let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
+ let lifetime =
+ if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None };
DynTrait(bounds, lifetime)
}
TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))),
}
ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
ty::Ref(r, ty, mutbl) => BorrowedRef {
- lifetime: r.clean(cx),
+ lifetime: clean_middle_region(r),
mutability: mutbl,
type_: Box::new(clean_middle_ty(ty, cx, None)),
},
// HACK: pick the first `did` as the `did` of the trait object. Someone
// might want to implement "native" support for marker-trait-only
// trait objects.
- let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
- let did = dids
- .next()
+ let mut dids = obj.auto_traits();
+ let did = obj
+ .principal_def_id()
+ .or_else(|| dids.next())
.unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this));
let substs = match obj.principal() {
Some(principal) => principal.skip_binder().substs,
inline::record_extern_fqn(cx, did, ItemType::Trait);
- let lifetime = reg.clean(cx);
- let mut bounds = vec![];
-
- for did in dids {
- let empty = cx.tcx.intern_substs(&[]);
- let path = external_path(cx, did, false, vec![], empty);
- inline::record_extern_fqn(cx, did, ItemType::Trait);
- let bound = PolyTrait { trait_: path, generic_params: Vec::new() };
- bounds.push(bound);
- }
+ let lifetime = clean_middle_region(*reg);
+ let mut bounds = dids
+ .map(|did| {
+ let empty = cx.tcx.intern_substs(&[]);
+ let path = external_path(cx, did, false, vec![], empty);
+ inline::record_extern_fqn(cx, did, ItemType::Trait);
+ PolyTrait { trait_: path, generic_params: Vec::new() }
+ })
+ .collect::<Vec<_>>();
- let mut bindings = vec![];
- for pb in obj.projection_bounds() {
- bindings.push(TypeBinding {
+ let bindings = obj
+ .projection_bounds()
+ .map(|pb| TypeBinding {
assoc: projection_to_path_segment(
pb.skip_binder()
.lift_to_tcx(cx.tcx)
kind: TypeBindingKind::Equality {
term: clean_middle_term(pb.skip_binder().term, cx),
},
- });
- }
+ })
+ .collect();
let path = external_path(cx, did, false, bindings, substs);
bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
let trait_ref = match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
- if let Some(r) = reg.clean(cx) {
+ if let Some(r) = clean_middle_region(reg) {
regions.push(GenericBound::Outlives(r));
}
return None;
Path { res: path.res, segments: path.segments.iter().map(|x| x.clean(cx)).collect() }
}
-impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
- fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs {
- if self.parenthesized {
- let output = clean_ty(self.bindings[0].ty(), cx);
- let output =
- if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
- let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
- GenericArgs::Parenthesized { inputs, output }
- } else {
- let args = self
- .args
- .iter()
- .map(|arg| match arg {
- hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
- GenericArg::Lifetime(lt.clean(cx))
- }
- hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
- hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
- hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
- hir::GenericArg::Infer(_inf) => GenericArg::Infer,
- })
- .collect::<Vec<_>>()
- .into();
- let bindings =
- self.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::<Vec<_>>().into();
- GenericArgs::AngleBracketed { args, bindings }
- }
+fn clean_generic_args<'tcx>(
+ generic_args: &hir::GenericArgs<'tcx>,
+ cx: &mut DocContext<'tcx>,
+) -> GenericArgs {
+ if generic_args.parenthesized {
+ let output = clean_ty(generic_args.bindings[0].ty(), cx);
+ let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
+ let inputs =
+ generic_args.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
+ GenericArgs::Parenthesized { inputs, output }
+ } else {
+ let args = generic_args
+ .args
+ .iter()
+ .map(|arg| match arg {
+ hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
+ GenericArg::Lifetime(clean_lifetime(*lt, cx))
+ }
+ hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+ hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
+ hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
+ hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+ })
+ .collect::<Vec<_>>()
+ .into();
+ let bindings = generic_args
+ .bindings
+ .iter()
+ .map(|x| clean_type_binding(x, cx))
+ .collect::<Vec<_>>()
+ .into();
+ GenericArgs::AngleBracketed { args, bindings }
}
}
impl<'tcx> Clean<'tcx, PathSegment> for hir::PathSegment<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> PathSegment {
- PathSegment { name: self.ident.name, args: self.args().clean(cx) }
+ PathSegment { name: self.ident.name, args: clean_generic_args(self.args(), cx) }
}
}
kind: ConstantKind::Local { body: body_id, def_id },
}),
ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
- bounds: ty.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
- generics: ty.generics.clean(cx),
+ bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
+ generics: clean_generics(ty.generics, cx),
}),
ItemKind::TyAlias(hir_ty, generics) => {
let rustdoc_ty = clean_ty(hir_ty, cx);
let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
TypedefItem(Box::new(Typedef {
type_: rustdoc_ty,
- generics: generics.clean(cx),
+ generics: clean_generics(generics, cx),
item_type: Some(ty),
}))
}
ItemKind::Enum(ref def, generics) => EnumItem(Enum {
variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
- generics: generics.clean(cx),
+ generics: clean_generics(generics, cx),
}),
ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
- generics: generics.clean(cx),
- bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+ generics: clean_generics(generics, cx),
+ bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
}),
ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
- generics: generics.clean(cx),
+ generics: clean_generics(generics, cx),
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
struct_type: CtorKind::from_hir(variant_data),
- generics: generics.clean(cx),
+ generics: clean_generics(generics, cx),
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx),
})
}
ItemKind::Trait(_, _, generics, bounds, item_ids) => {
- let items =
- item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
+ let items = item_ids
+ .iter()
+ .map(|ti| clean_trait_item(cx.tcx.hir().trait_item(ti.id), cx))
+ .collect();
TraitItem(Trait {
def_id,
items,
- generics: generics.clean(cx),
- bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+ generics: clean_generics(generics, cx),
+ bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
})
}
ItemKind::ExternCrate(orig_name) => {
return clean_extern_crate(item, name, orig_name, cx);
}
ItemKind::Use(path, kind) => {
- return clean_use_statement(item, name, path, kind, cx);
+ return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default());
}
_ => unreachable!("not yet converted"),
};
) -> Vec<Item> {
let tcx = cx.tcx;
let mut ret = Vec::new();
- let trait_ = impl_.of_trait.as_ref().map(|t| t.clean(cx));
- let items =
- impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
+ let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx));
+ let items = impl_
+ .items
+ .iter()
+ .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx))
+ .collect::<Vec<_>>();
let def_id = tcx.hir().local_def_id(hir_id);
// If this impl block is an implementation of the Deref trait, then we
let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
let kind = ImplItem(Box::new(Impl {
unsafety: impl_.unsafety,
- generics: impl_.generics.clean(cx),
+ generics: clean_generics(impl_.generics, cx),
trait_,
for_,
items,
// FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
vec![Item {
name: Some(name),
- attrs: Box::new(attrs.clean(cx)),
+ attrs: Box::new(Attributes::from_ast(attrs)),
item_id: crate_def_id.into(),
visibility: clean_visibility(ty_vis),
kind: Box::new(ExternCrateItem { src: orig_name }),
path: &hir::Path<'tcx>,
kind: hir::UseKind,
cx: &mut DocContext<'tcx>,
+ inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Vec<Item> {
// We need this comparison because some imports (for std types for example)
// are "inserted" as well but directly by the compiler and they should not be
let inner = if kind == hir::UseKind::Glob {
if !denied {
let mut visited = FxHashSet::default();
- if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
+ if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited, inlined_names)
+ {
return items;
}
}
hir::ForeignItemKind::Fn(decl, names, generics) => {
let (generics, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
- let generics = generics.clean(cx);
+ let generics = clean_generics(generics, cx);
let args = clean_args_from_types_and_names(cx, decl.inputs, names);
let decl = clean_fn_decl_with_args(cx, decl, args);
(generics, decl)
cx: &mut DocContext<'tcx>,
) -> TypeBinding {
TypeBinding {
- assoc: PathSegment { name: type_binding.ident.name, args: type_binding.gen_args.clean(cx) },
+ assoc: PathSegment {
+ name: type_binding.ident.name,
+ args: clean_generic_args(type_binding.gen_args, cx),
+ },
kind: match type_binding.kind {
hir::TypeBindingKind::Equality { ref term } => {
TypeBindingKind::Equality { term: clean_hir_term(term, cx) }
}
hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
- bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
+ bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(),
},
},
}
use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
use crate::clean::cfg::Cfg;
+use crate::clean::clean_visibility;
use crate::clean::external_path;
use crate::clean::inline::{self, print_inlined_const};
use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
-use crate::clean::{clean_visibility, Clean};
use crate::core::DocContext;
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
}
-// `Crate` is frequently moved by-value. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Crate, 72);
-
impl Crate {
pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
ExternalCrate::LOCAL.name(tcx)
}
}
-// `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Item, 56);
-
pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
Span::new(def_id.as_local().map_or_else(
|| tcx.def_span(def_id),
def_id,
name,
kind,
- Box::new(ast_attrs.clean(cx)),
+ Box::new(Attributes::from_ast(ast_attrs)),
cx,
ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
)
KeywordItem,
}
-// `ItemKind` is an enum and large variants can bloat up memory usage even for smaller ones
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ItemKind, 112);
-
impl ItemKind {
/// Some items contain others such as structs (for their fields) and Enums
/// (for their variants). This method returns those contained items.
pub(crate) indent: usize,
}
-// `DocFragment` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(DocFragment, 32);
-
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) enum DocFragmentKind {
/// A doc fragment created from a `///` or `//!` doc comment.
false
}
- pub(crate) fn from_ast(
+ pub(crate) fn from_ast(attrs: &[ast::Attribute]) -> Attributes {
+ Attributes::from_ast_iter(attrs.iter().map(|attr| (attr, None)), false)
+ }
+
+ pub(crate) fn from_ast_with_additional(
attrs: &[ast::Attribute],
- additional_attrs: Option<(&[ast::Attribute], DefId)>,
+ (additional_attrs, def_id): (&[ast::Attribute], DefId),
) -> Attributes {
// Additional documentation should be shown before the original documentation.
- let attrs1 = additional_attrs
- .into_iter()
- .flat_map(|(attrs, def_id)| attrs.iter().map(move |attr| (attr, Some(def_id))));
+ let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
let attrs2 = attrs.iter().map(|attr| (attr, None));
Attributes::from_ast_iter(attrs1.chain(attrs2), false)
}
pub(crate) kind: GenericParamDefKind,
}
-// `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericParamDef, 56);
-
impl GenericParamDef {
pub(crate) fn is_synthetic_type_param(&self) -> bool {
match self.kind {
ImplTrait(Vec<GenericBound>),
}
-// `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Type, 72);
-
impl Type {
/// When comparing types for equality, it can help to ignore `&` wrapping.
pub(crate) fn without_borrowed_ref(&self) -> &Type {
Infer,
}
-// `GenericArg` can occur many times in a single `Path`, so make sure it
-// doesn't increase in size unexpectedly.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericArg, 80);
-
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) enum GenericArgs {
AngleBracketed { args: Box<[GenericArg]>, bindings: ThinVec<TypeBinding> },
Parenthesized { inputs: Box<[Type]>, output: Option<Box<Type>> },
}
-// `GenericArgs` is in every `PathSegment`, so its size can significantly
-// affect rustdoc's memory usage.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericArgs, 32);
-
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) struct PathSegment {
pub(crate) name: Symbol,
pub(crate) args: GenericArgs,
}
-// `PathSegment` usually occurs multiple times in every `Path`, so its size can
-// significantly affect rustdoc's memory usage.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PathSegment, 40);
-
#[derive(Clone, Debug)]
pub(crate) struct Typedef {
pub(crate) type_: Type,
if let Self::Lifetime(lt) = self { Some(lt) } else { None }
}
}
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+ use super::*;
+ use rustc_data_structures::static_assert_size;
+ // These are in alphabetical order, which is easy to maintain.
+ static_assert_size!(Crate, 72); // frequently moved by-value
+ static_assert_size!(DocFragment, 32);
+ static_assert_size!(GenericArg, 80);
+ static_assert_size!(GenericArgs, 32);
+ static_assert_size!(GenericParamDef, 56);
+ static_assert_size!(Item, 56);
+ static_assert_size!(ItemKind, 112);
+ static_assert_size!(PathSegment, 40);
+ static_assert_size!(Type, 72);
+}
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::render_macro_matchers::render_macro_matcher;
use crate::clean::{
- clean_middle_const, clean_middle_ty, inline, Clean, Crate, ExternalCrate, Generic, GenericArg,
- GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, Primitive,
- PrimitiveType, Type, TypeBinding, Visibility,
+ clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate,
+ ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path,
+ PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
// Clean the crate, translating the entire librustc_ast AST to one that is
// understood by rustdoc.
- let mut module = module.clean(cx);
+ let mut module = clean_doc_module(&module, cx);
match *module.kind {
ItemKind::ModuleItem(ref module) => {
Vec::with_capacity(substs.len().saturating_sub(if skip_first { 1 } else { 0 }));
ret_val.extend(substs.iter().filter_map(|kind| match kind.unpack() {
GenericArgKind::Lifetime(lt) => {
- Some(GenericArg::Lifetime(lt.clean(cx).unwrap_or(Lifetime::elided())))
+ Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided())))
}
GenericArgKind::Type(_) if skip_first => {
skip_first = false;
// The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
// anything else, this will combine them for us.
- let attrs = Attributes::from_ast(ast_attrs, None);
+ let attrs = Attributes::from_ast(ast_attrs);
if let Some(doc) = attrs.collapsed_doc_value() {
// Use the outermost invocation, so that doctest names come from where the docs were written.
let span = ast_attrs
});
}
- fn visit_variant(
- &mut self,
- v: &'hir hir::Variant<'_>,
- g: &'hir hir::Generics<'_>,
- item_id: hir::HirId,
- ) {
+ fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) {
self.visit_testable(v.ident.to_string(), v.id, v.span, |this| {
- intravisit::walk_variant(this, v, g, item_id);
+ intravisit::walk_variant(this, v);
});
}
}
}
-fn comma_sep<T: fmt::Display>(
+pub(crate) fn comma_sep<T: fmt::Display>(
items: impl Iterator<Item = T>,
space_after_comma: bool,
) -> impl fmt::Display {
/// Decorations are represented as a map from CSS class to vector of character ranges.
/// Each range will be wrapped in a span with that class.
+#[derive(Default)]
pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>);
-/// Highlights `src`, returning the HTML output.
-pub(crate) fn render_with_highlighting(
+#[derive(Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Tooltip {
+ Ignore,
+ CompileFail,
+ ShouldPanic,
+ Edition(Edition),
+ None,
+}
+
+/// Highlights `src` as an inline example, returning the HTML output.
+pub(crate) fn render_example_with_highlighting(
src: &str,
out: &mut Buffer,
- class: Option<&str>,
+ tooltip: Tooltip,
playground_button: Option<&str>,
- tooltip: Option<(Option<Edition>, &str)>,
- edition: Edition,
- extra_content: Option<Buffer>,
- href_context: Option<HrefContext<'_, '_, '_>>,
- decoration_info: Option<DecorationInfo>,
) {
- debug!("highlighting: ================\n{}\n==============", src);
- if let Some((edition_info, class)) = tooltip {
+ let class = match tooltip {
+ Tooltip::Ignore => " ignore",
+ Tooltip::CompileFail => " compile_fail",
+ Tooltip::ShouldPanic => " should_panic",
+ Tooltip::Edition(_) => " edition",
+ Tooltip::None => "",
+ };
+
+ if tooltip != Tooltip::None {
write!(
out,
- "<div class='information'><div class='tooltip {}'{}>ⓘ</div></div>",
+ "<div class='information'><div class='tooltip{}'{}>ⓘ</div></div>",
class,
- if let Some(edition_info) = edition_info {
+ if let Tooltip::Edition(edition_info) = tooltip {
format!(" data-edition=\"{}\"", edition_info)
} else {
String::new()
);
}
- write_header(out, class, extra_content);
- write_code(out, src, edition, href_context, decoration_info);
+ write_header(out, &format!("rust-example-rendered{}", class), None);
+ write_code(out, src, None, None);
write_footer(out, playground_button);
}
-fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buffer>) {
+/// Highlights `src` as a macro, returning the HTML output.
+pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) {
+ write_header(out, "macro", None);
+ write_code(out, src, None, None);
+ write_footer(out, None);
+}
+
+/// Highlights `src` as a source code page, returning the HTML output.
+pub(crate) fn render_source_with_highlighting(
+ src: &str,
+ out: &mut Buffer,
+ line_numbers: Buffer,
+ href_context: HrefContext<'_, '_, '_>,
+ decoration_info: DecorationInfo,
+) {
+ write_header(out, "", Some(line_numbers));
+ write_code(out, src, Some(href_context), Some(decoration_info));
+ write_footer(out, None);
+}
+
+fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>) {
write!(out, "<div class=\"example-wrap\">");
if let Some(extra) = extra_content {
out.push_buffer(extra);
}
- if let Some(class) = class {
- write!(out, "<pre class=\"rust {}\">", class);
- } else {
+ if class.is_empty() {
write!(out, "<pre class=\"rust\">");
+ } else {
+ write!(out, "<pre class=\"rust {}\">", class);
}
write!(out, "<code>");
}
fn write_code(
out: &mut Buffer,
src: &str,
- edition: Edition,
href_context: Option<HrefContext<'_, '_, '_>>,
decoration_info: Option<DecorationInfo>,
) {
let mut closing_tags: Vec<&'static str> = Vec::new();
Classifier::new(
&src,
- edition,
href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
decoration_info,
)
return None;
}
let token = rustc_lexer::first_token(self.src);
- let (text, rest) = self.src.split_at(token.len);
+ let (text, rest) = self.src.split_at(token.len as usize);
self.src = rest;
Some((token.kind, text))
}
}
/// Classifies into identifier class; returns `None` if this is a non-keyword identifier.
-fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> {
+fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class> {
let ignore: &[&str] =
if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
if ignore.iter().any(|k| *k == text) {
Some(match text {
"ref" | "mut" => Class::RefKeyWord,
"false" | "true" => Class::Bool,
- _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord,
+ _ if Symbol::intern(text).is_reserved(|| Edition::Edition2021) => Class::KeyWord,
_ => return None,
})
}
in_attribute: bool,
in_macro: bool,
in_macro_nonterminal: bool,
- edition: Edition,
byte_pos: u32,
file_span: Span,
src: &'a str,
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,
- decoration_info: Option<DecorationInfo>,
- ) -> Classifier<'_> {
+ fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
let tokens = PeekIter::new(TokenIter { src });
let decorations = decoration_info.map(Decorations::new);
Classifier {
in_attribute: false,
in_macro: false,
in_macro_nonterminal: false,
- edition,
byte_pos: 0,
file_span,
src,
let start = self.byte_pos as usize;
let mut pos = start;
let mut has_ident = false;
- let edition = self.edition;
loop {
let mut nb = 0;
if let Some((None, text)) = self.tokens.peek().map(|(token, text)| {
if *token == TokenKind::Ident {
- let class = get_real_ident_class(text, edition, true);
+ let class = get_real_ident_class(text, true);
(class, text)
} else {
// Doesn't matter which Class we put in here...
sink(Highlight::Token { text, class: None });
return;
}
- TokenKind::Ident => match get_real_ident_class(text, self.edition, false) {
+ TokenKind::Ident => match get_real_ident_class(text, false) {
None => match text {
"Option" | "Result" => Class::PreludeTy,
"Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
use expect_test::expect_file;
use rustc_data_structures::fx::FxHashMap;
use rustc_span::create_default_session_globals_then;
-use rustc_span::edition::Edition;
const STYLE: &str = r#"
<style>
let src = include_str!("fixtures/sample.rs");
let html = {
let mut out = Buffer::new();
- write_code(&mut out, src, Edition::Edition2018, None, None);
+ write_code(&mut out, src, None, None);
format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
};
expect_file!["fixtures/sample.html"].assert_eq(&html);
println!(\"foo\");\r\n\
}\r\n";
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None, None);
+ write_code(&mut html, src, None, None);
expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
});
}
let y = Self::whatever;";
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None, None);
+ write_code(&mut html, src, None, None);
expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
});
}
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, None);
+ write_code(&mut html, src, None, None);
expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
});
}
decorations.insert("example", vec![(0, 10)]);
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations)));
+ write_code(&mut html, src, None, Some(DecorationInfo(decorations)));
expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
});
}
});
let tooltip = if ignore != Ignore::None {
- Some((None, "ignore"))
+ highlight::Tooltip::Ignore
} else if compile_fail {
- Some((None, "compile_fail"))
+ highlight::Tooltip::CompileFail
} else if should_panic {
- Some((None, "should_panic"))
+ highlight::Tooltip::ShouldPanic
} else if explicit_edition {
- Some((Some(edition), "edition"))
+ highlight::Tooltip::Edition(edition)
} else {
- None
+ highlight::Tooltip::None
};
// insert newline to clearly separate it from the
// previous block so we can shorten the html output
let mut s = Buffer::new();
s.push_str("\n");
- highlight::render_with_highlighting(
+
+ highlight::render_example_with_highlighting(
&text,
&mut s,
- Some(&format!(
- "rust-example-rendered{}",
- if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() }
- )),
- playground_button.as_deref(),
tooltip,
- edition,
- None,
- None,
- None,
+ playground_button.as_deref(),
);
Some(Event::Html(s.into_inner().into()))
}
map.insert("not-displayed".into(), 1);
map.insert("alternative-display".into(), 1);
map.insert("search".into(), 1);
+ map.insert("crate-search".into(), 1);
+ map.insert("crate-search-div".into(), 1);
// This is the list of IDs used in HTML generated in Rust (including the ones
// used in tera template files).
map.insert("mainThemeStyle".into(), 1);
map.insert("settings-menu".into(), 1);
map.insert("help-button".into(), 1);
map.insert("main-content".into(), 1);
- map.insert("crate-search".into(), 1);
map.insert("toggle-all-docs".into(), 1);
map.insert("all-types".into(), 1);
map.insert("default-settings".into(), 1);
rendering_params: ImplRenderingParameters,
) {
for trait_item in &t.items {
+ // Skip over any default trait items that are impossible to call
+ // (e.g. if it has a `Self: Sized` bound on an unsized type).
+ if let Some(impl_def_id) = parent.item_id.as_def_id()
+ && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
+ && cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
+ {
+ continue;
+ }
+
let n = trait_item.name;
if i.items.iter().any(|m| m.name == n) {
continue;
sources::print_src(
w,
contents_subset,
- call_data.edition,
file_span,
cx,
&root_path,
- Some(highlight::DecorationInfo(decoration_info)),
+ highlight::DecorationInfo(decoration_info),
sources::SourceContext::Embedded { offset: line_min },
);
write!(w, "</div></div>");
clean::ImportItem(ref import) => {
let (stab, stab_tags) = if let Some(import_def_id) = import.source.did {
let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id);
- let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs, None));
+ let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs));
// Just need an item with the correct def_id and attrs
let import_item = clean::Item {
fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
wrap_into_docblock(w, |w| {
- highlight::render_with_highlighting(
- &t.source,
- w,
- Some("macro"),
- None,
- None,
- it.span(cx.tcx()).inner().edition(),
- None,
- None,
- None,
- );
+ highlight::render_macro_with_highlighting(&t.source, w);
});
document(w, cx, it, None, HeadingOffset::H2)
}
use std::ffi::OsStr;
-use std::fmt::Write;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, BufReader};
use itertools::Itertools;
use rustc_data_structures::flock;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use serde::Serialize;
+use serde::ser::SerializeSeq;
+use serde::{Serialize, Serializer};
use super::{collect_paths_for_type, ensure_trailing_slash, Context, BASIC_KEYWORDS};
use crate::clean::Crate;
cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?;
}
- fn collect(path: &Path, krate: &str, key: &str) -> io::Result<(Vec<String>, Vec<String>)> {
+ /// Read a file and return all lines that match the `"{crate}":{data},` format,
+ /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
+ ///
+ /// This forms the payload of files that look like this:
+ ///
+ /// ```javascript
+ /// var data = {
+ /// "{crate1}":{data},
+ /// "{crate2}":{data}
+ /// };
+ /// use_data(data);
+ /// ```
+ ///
+ /// The file needs to be formatted so that *only crate data lines start with `"`*.
+ fn collect(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
let mut ret = Vec::new();
let mut krates = Vec::new();
if path.exists() {
- let prefix = format!(r#"{}["{}"]"#, key, krate);
+ let prefix = format!("\"{}\"", krate);
for line in BufReader::new(File::open(path)?).lines() {
let line = line?;
- if !line.starts_with(key) {
+ if !line.starts_with('"') {
continue;
}
if line.starts_with(&prefix) {
continue;
}
- ret.push(line.to_string());
+ if line.ends_with(",") {
+ ret.push(line[..line.len() - 1].to_string());
+ } else {
+ // No comma (it's the case for the last added crate line)
+ ret.push(line.to_string());
+ }
krates.push(
- line[key.len() + 2..]
- .split('"')
- .next()
+ line.split('"')
+ .find(|s| !s.is_empty())
.map(|s| s.to_owned())
.unwrap_or_else(String::new),
);
Ok((ret, krates))
}
+ /// Read a file and return all lines that match the <code>"{crate}":{data},\</code> format,
+ /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
+ ///
+ /// This forms the payload of files that look like this:
+ ///
+ /// ```javascript
+ /// var data = JSON.parse('{\
+ /// "{crate1}":{data},\
+ /// "{crate2}":{data}\
+ /// }');
+ /// use_data(data);
+ /// ```
+ ///
+ /// The file needs to be formatted so that *only crate data lines start with `"`*.
fn collect_json(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
let mut ret = Vec::new();
let mut krates = Vec::new();
.collect::<Vec<_>>();
files.sort_unstable();
let subs = subs.iter().map(|s| s.to_json_string()).collect::<Vec<_>>().join(",");
- let dirs =
- if subs.is_empty() { String::new() } else { format!(",\"dirs\":[{}]", subs) };
+ let dirs = if subs.is_empty() && files.is_empty() {
+ String::new()
+ } else {
+ format!(",[{}]", subs)
+ };
let files = files.join(",");
- let files =
- if files.is_empty() { String::new() } else { format!(",\"files\":[{}]", files) };
+ let files = if files.is_empty() { String::new() } else { format!(",[{}]", files) };
format!(
- "{{\"name\":\"{name}\"{dirs}{files}}}",
+ "[\"{name}\"{dirs}{files}]",
name = self.elem.to_str().expect("invalid osstring conversion"),
dirs = dirs,
files = files
let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
let make_sources = || {
let (mut all_sources, _krates) =
- try_err!(collect(&dst, krate.name(cx.tcx()).as_str(), "sourcesIndex"), &dst);
+ try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst);
all_sources.push(format!(
- "sourcesIndex[\"{}\"] = {};",
+ r#""{}":{}"#,
&krate.name(cx.tcx()),
- hierarchy.to_json_string()
+ hierarchy
+ .to_json_string()
+ // All these `replace` calls are because we have to go through JS string for JSON content.
+ .replace('\\', r"\\")
+ .replace('\'', r"\'")
+ // We need to escape double quotes for the JSON.
+ .replace("\\\"", "\\\\\"")
));
all_sources.sort();
- Ok(format!(
- "var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n",
- all_sources.join("\n")
- )
- .into_bytes())
+ let mut v = String::from("var sourcesIndex = JSON.parse('{\\\n");
+ v.push_str(&all_sources.join(",\\\n"));
+ v.push_str("\\\n}');\ncreateSourceSidebar();\n");
+ Ok(v.into_bytes())
};
write_crate("source-files.js", &make_sources)?;
}
},
};
- #[derive(Serialize)]
struct Implementor {
text: String,
synthetic: bool,
types: Vec<String>,
}
+ impl Serialize for Implementor {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ let mut seq = serializer.serialize_seq(None)?;
+ seq.serialize_element(&self.text)?;
+ if self.synthetic {
+ seq.serialize_element(&1)?;
+ seq.serialize_element(&self.types)?;
+ }
+ seq.end()
+ }
+ }
+
let implementors = imps
.iter()
.filter_map(|imp| {
}
let implementors = format!(
- r#"implementors["{}"] = {};"#,
+ r#""{}":{}"#,
krate.name(cx.tcx()),
- serde_json::to_string(&implementors).unwrap()
+ serde_json::to_string(&implementors).expect("failed serde conversion"),
);
let mut mydst = dst.clone();
mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1]));
let (mut all_implementors, _) =
- try_err!(collect(&mydst, krate.name(cx.tcx()).as_str(), "implementors"), &mydst);
+ try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst);
all_implementors.push(implementors);
// Sort the implementors by crate so the file will be generated
// identically even with rustdoc running in parallel.
all_implementors.sort();
- let mut v = String::from("(function() {var implementors = {};\n");
- for implementor in &all_implementors {
- writeln!(v, "{}", *implementor).unwrap();
- }
+ let mut v = String::from("(function() {var implementors = {\n");
+ v.push_str(&all_implementors.join(",\n"));
+ v.push_str("\n};");
v.push_str(
"if (window.register_implementors) {\
window.register_implementors(implementors);\
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
-use rustc_span::edition::Edition;
use rustc_span::source_map::FileName;
use std::ffi::OsStr;
print_src(
buf,
contents,
- cx.shared.edition(),
file_span,
cx,
&root_path,
- None,
+ highlight::DecorationInfo::default(),
SourceContext::Standalone,
)
},
pub(crate) fn print_src(
buf: &mut Buffer,
s: &str,
- edition: Edition,
file_span: rustc_span::Span,
context: &Context<'_>,
root_path: &str,
- decoration_info: Option<highlight::DecorationInfo>,
+ decoration_info: highlight::DecorationInfo,
source_context: SourceContext,
) {
let lines = s.lines().count();
}
}
line_numbers.write_str("</pre>");
- highlight::render_with_highlighting(
+ highlight::render_source_with_highlighting(
s,
buf,
- None,
- None,
- None,
- edition,
- Some(line_numbers),
- Some(highlight::HrefContext { context, file_span, root_path }),
+ line_numbers,
+ highlight::HrefContext { context, file_span, root_path },
decoration_info,
);
}
height: 100%;
}
.search-results-title {
- display: inline;
+ margin-top: 0;
+ white-space: nowrap;
+ /* flex layout allows shrinking the <select> appropriately if it becomes too large */
+ display: inline-flex;
+ max-width: 100%;
+ /* make things look like in a line, despite the fact that we're using a layout
+ with boxes (i.e. from the flex layout) */
+ align-items: baseline;
}
-#search-settings {
- font-size: 1.5rem;
- font-weight: 500;
- margin-bottom: 20px;
+#crate-search-div {
+ display: inline-block;
+ /* ensures that 100% in properties of #crate-search-div:after
+ are relative to the size of this div */
+ position: relative;
+ /* allows this div (and with it the <select>-element "#crate-search") to be shrunk */
+ min-width: 5em;
}
#crate-search {
min-width: 115px;
- margin-top: 5px;
- padding-left: 0.15em;
+ padding: 0;
+ /* keep these two in sync with "@-moz-document url-prefix()" below */
+ padding-left: 4px;
padding-right: 23px;
+ /* prevents the <select> from overflowing the containing div in case it's shrunk */
+ max-width: 100%;
+ /* contents can overflow because of max-width limit, then show ellipsis */
+ text-overflow: ellipsis;
border: 1px solid;
border-radius: 4px;
outline: none;
-moz-appearance: none;
-webkit-appearance: none;
/* Removes default arrow from firefox */
+ text-indent: 0.01px;
+ background-color: var(--main-background-color);
+}
+/* cancel stylistic differences in padding in firefox
+for "appearance: none"-style (or equivalent) <select>s */
+@-moz-document url-prefix() {
+ #crate-search {
+ padding-left: 0px; /* == 4px - 4px */
+ padding-right: 19px; /* == 23px - 4px */
+ }
+}
+/* pseudo-element for holding the dropdown-arrow image; needs to be a separate thing
+so that we can apply CSS-filters to change the arrow color in themes */
+#crate-search-div::after {
+ /* lets clicks through! */
+ pointer-events: none;
+ /* completely covers the underlying div */
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ content: "";
background-repeat: no-repeat;
- background-color: transparent;
background-size: 20px;
- background-position: calc(100% - 1px) 56%;
+ background-position: calc(100% - 2px) 56%;
+ /* image is black color, themes should apply a "filter" property to change the color */
background-image: /* AUTOREPLACE: */url("down-arrow.svg");
- max-width: 100%;
- text-overflow: ellipsis;
+}
+#crate-search > option {
+ font-size: 1rem;
}
.search-container {
margin-top: 4px;
}
.item-info .stab {
- display: inline-block;
+ width: fit-content;
+ /* This min-height is needed to unify the height of the stab elements because some of them
+ have emojis.
+ */
+ min-height: 36px;
+ display: flex;
+ align-items: center;
+ white-space: pre-wrap;
}
.stab {
padding: 3px;
}
.stab p {
display: inline;
+ margin: 0;
}
.stab .emoji {
filter: invert(100%);
}
-#crate-search, .search-input {
+.search-input {
background-color: #141920;
border-color: #424c57;
}
/* Without the `!important`, the border-color is ignored for `<select>`...
It cannot be in the group above because `.search-input` has a different border color on
hover. */
- border-color: #424c57 !important;
+ border-color: #5c6773 !important;
+}
+#crate-search-div::after {
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);
+}
+#crate-search:hover, #crate-search:focus {
+ border-color: #e0e0e0 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+ filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);
}
.search-input {
color: #000;
}
-/* Created this empty rule to satisfy the theme checks. */
-.stab.empty-impl {}
-.stab.must_implement {}
-
-.stab.unstable,
-.stab.deprecated,
-.stab.portability,
-.stab.empty-impl,
-.stab.must_implement {
+.stab {
color: #c5c5c5;
background: #314559 !important;
- border-style: none !important;
- border-radius: 4px;
- padding: 3px 6px 3px 6px;
}
.stab.portability > code {
filter: invert(100%);
}
-#crate-search, .search-input {
+.search-input {
color: #111;
background-color: #f0f0f0;
border-color: #f0f0f0;
/* Without the `!important`, the border-color is ignored for `<select>`...
It cannot be in the group above because `.search-input` has a different border color on
hover. */
- border-color: #f0f0f0 !important;
+ border-color: #d2d2d2 !important;
+}
+#crate-search-div::after {
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);
+}
+#crate-search:hover, #crate-search:focus {
+ border-color: #2196f3 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+ filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);
}
.search-input {
border-color: #008dfd;
}
-.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; }
-.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
-.stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
-.stab.portability > code { background: none; }
+.stab { background: #314559; }
+
+.stab.portability > code {
+ color: #e6e1cf;
+ background: none;
+}
.rightside,
.out-of-band {
color: #999;
}
-#crate-search, .search-input {
+.search-input {
background-color: white;
border-color: #e0e0e0;
}
-
#crate-search {
/* Without the `!important`, the border-color is ignored for `<select>`...
It cannot be in the group above because `.search-input` has a different border color on
hover. */
border-color: #e0e0e0 !important;
}
+#crate-search-div::after {
+ /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+ filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);
+}
+#crate-search:hover, #crate-search:focus {
+ border-color: #717171 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+ filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);
+}
.search-input:focus {
border-color: #66afe9;
}
-.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; }
-.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
-.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; }
-.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; }
-.stab.portability { background: #F3DFFF; border-color: #b07bdb; }
+.stab { background: #FFF5D6; border-color: #FFC600; }
.stab.portability > code { background: none; }
.rightside,
.popover, .popover::before,
#help-button span.top, #help-button span.bottom {
- border-color: #DDDDDD;
+ border-color: #e0e0e0;
}
#copy-path {
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg>
\ No newline at end of file
function onHashChange(ev) {
// If we're in mobile mode, we should hide the sidebar in any case.
- const sidebar = document.getElementsByClassName("sidebar")[0];
- removeClass(sidebar, "shown");
+ hideSidebar();
handleHashes(ev);
}
const synthetic_implementors = document.getElementById("synthetic-implementors-list");
const inlined_types = new Set();
+ const TEXT_IDX = 0;
+ const SYNTHETIC_IDX = 1;
+ const TYPES_IDX = 2;
+
if (synthetic_implementors) {
// This `inlined_types` variable is used to avoid having the same implementation
// showing up twice. For example "String" in the "Sync" doc page.
struct_loop:
for (const struct of structs) {
- const list = struct.synthetic ? synthetic_implementors : implementors;
+ const list = struct[SYNTHETIC_IDX] ? synthetic_implementors : implementors;
- if (struct.synthetic) {
- for (const struct_type of struct.types) {
+ // The types list is only used for synthetic impls.
+ // If this changes, `main.js` and `write_shared.rs` both need changed.
+ if (struct[SYNTHETIC_IDX]) {
+ for (const struct_type of struct[TYPES_IDX]) {
if (inlined_types.has(struct_type)) {
continue struct_loop;
}
}
const code = document.createElement("h3");
- code.innerHTML = struct.text;
+ code.innerHTML = struct[TEXT_IDX];
addClass(code, "code-header");
addClass(code, "in-band");
});
}());
+ let oldSidebarScrollPosition = null;
+
+ function showSidebar() {
+ if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+ // This is to keep the scroll position on mobile.
+ oldSidebarScrollPosition = window.scrollY;
+ document.body.style.width = `${document.body.offsetWidth}px`;
+ document.body.style.position = "fixed";
+ document.body.style.top = `-${oldSidebarScrollPosition}px`;
+ document.querySelector(".mobile-topbar").style.top = `${oldSidebarScrollPosition}px`;
+ document.querySelector(".mobile-topbar").style.position = "relative";
+ } else {
+ oldSidebarScrollPosition = null;
+ }
+ const sidebar = document.getElementsByClassName("sidebar")[0];
+ addClass(sidebar, "shown");
+ }
+
function hideSidebar() {
+ if (oldSidebarScrollPosition !== null) {
+ // This is to keep the scroll position on mobile.
+ document.body.style.width = "";
+ document.body.style.position = "";
+ document.body.style.top = "";
+ document.querySelector(".mobile-topbar").style.top = "";
+ document.querySelector(".mobile-topbar").style.position = "";
+ // The scroll position is lost when resetting the style, hence why we store it in
+ // `oldSidebarScrollPosition`.
+ window.scrollTo(0, oldSidebarScrollPosition);
+ oldSidebarScrollPosition = null;
+ }
const sidebar = document.getElementsByClassName("sidebar")[0];
removeClass(sidebar, "shown");
}
+ window.addEventListener("resize", () => {
+ if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT &&
+ oldSidebarScrollPosition !== null) {
+ // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
+ // we need to switch away from mobile mode and make the main content area scrollable.
+ hideSidebar();
+ }
+ });
+
function handleClick(id, f) {
const elem = document.getElementById(id);
if (elem) {
sidebar_menu_toggle.addEventListener("click", () => {
const sidebar = document.getElementsByClassName("sidebar")[0];
if (!hasClass(sidebar, "shown")) {
- addClass(sidebar, "shown");
+ showSidebar();
} else {
- removeClass(sidebar, "shown");
+ hideSidebar();
}
});
}
<code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
and <code>const</code>.",
"Search functions by type signature (e.g., <code>vec -> usize</code> or \
- <code>* -> vec</code>)",
+ <code>-> vec</code>)",
"Search multiple things at once by splitting your query with comma (e.g., \
<code>str,u8</code> or <code>String,struct:Vec,test</code>)",
"You can look for items with an exact name by putting double quotes around \
}
const posBefore = parserState.pos;
getNextElem(query, parserState, elems, endChar === ">");
- // This case can be encountered if `getNextElem` encounted a "stop character" right from
- // the start. For example if you have `,,` or `<>`. In this case, we simply move up the
- // current position to continue the parsing.
+ // This case can be encountered if `getNextElem` encountered a "stop character" right
+ // from the start. For example if you have `,,` or `<>`. In this case, we simply move up
+ // the current position to continue the parsing.
if (posBefore === parserState.pos) {
parserState.pos += 1;
}
const elem = document.getElementById("crate-search");
if (elem &&
- elem.value !== "All crates" &&
+ elem.value !== "all crates" &&
hasOwnPropertyRustdoc(rawSearchIndex, elem.value)
) {
return elem.value;
return [displayPath, href];
}
- function escape(content) {
- const h1 = document.createElement("h1");
- h1.textContent = content;
- return h1.innerHTML;
- }
-
function pathSplitter(path) {
const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
if (tmp.endsWith("<span>")) {
let crates = "";
const crates_list = Object.keys(rawSearchIndex);
if (crates_list.length > 1) {
- crates = " in <select id=\"crate-search\"><option value=\"All crates\">" +
- "All crates</option>";
+ crates = " in <div id=\"crate-search-div\"><select id=\"crate-search\">" +
+ "<option value=\"all crates\">all crates</option>";
for (const c of crates_list) {
crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`;
}
- crates += "</select>";
- }
-
- let typeFilter = "";
- if (results.query.typeFilter !== NO_TYPE_FILTER) {
- typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+ crates += "</select></div>";
}
- let output = "<div id=\"search-settings\">" +
- `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
- `${typeFilter}</h1>${crates}</div>`;
+ let output = `<h1 class="search-results-title">Results${crates}</h1>`;
if (results.query.error !== null) {
output += `<h3>Query parser error: "${results.query.error}".</h3>`;
output += "<div id=\"titles\">" +
}
function updateCrate(ev) {
- if (ev.target.value === "All crates") {
+ if (ev.target.value === "all crates") {
// If we don't remove it from the URL, it'll be picked up again by the search.
const params = searchState.getQueryStringParams();
const query = searchState.input.value.trim();
(function() {
const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
-let oldScrollPosition = 0;
+let oldScrollPosition = null;
+
+const NAME_OFFSET = 0;
+const DIRS_OFFSET = 1;
+const FILES_OFFSET = 2;
function closeSidebarIfMobile() {
if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
dirEntry.className = "dir-entry";
- fullPath += elem["name"] + "/";
+ fullPath += elem[NAME_OFFSET] + "/";
- summary.innerText = elem["name"];
+ summary.innerText = elem[NAME_OFFSET];
dirEntry.appendChild(summary);
const folders = document.createElement("div");
folders.className = "folders";
- if (elem.dirs) {
- for (const dir of elem.dirs) {
+ if (elem[DIRS_OFFSET]) {
+ for (const dir of elem[DIRS_OFFSET]) {
if (createDirEntry(dir, folders, fullPath, false)) {
dirEntry.open = true;
hasFoundFile = true;
const files = document.createElement("div");
files.className = "files";
- if (elem.files) {
- for (const file_text of elem.files) {
+ if (elem[FILES_OFFSET]) {
+ for (const file_text of elem[FILES_OFFSET]) {
const file = document.createElement("a");
file.innerText = file_text;
file.href = rootPath + "src/" + fullPath + file_text + ".html";
oldScrollPosition = window.scrollY;
document.body.style.position = "fixed";
document.body.style.top = `-${oldScrollPosition}px`;
+ } else {
+ oldScrollPosition = null;
}
addClass(document.documentElement, "source-sidebar-expanded");
child.innerText = "<";
updateLocalStorage("source-sidebar-show", "true");
} else {
- if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+ if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
// This is to keep the scroll position on mobile.
document.body.style.position = "";
document.body.style.top = "";
// The scroll position is lost when resetting the style, hence why we store it in
- // `oldScroll`.
+ // `oldScrollPosition`.
window.scrollTo(0, oldScrollPosition);
+ oldScrollPosition = null;
}
removeClass(document.documentElement, "source-sidebar-expanded");
child.innerText = ">";
}
}
+window.addEventListener("resize", () => {
+ if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
+ // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
+ // we need to switch away from mobile mode and make the main content area scrollable.
+ document.body.style.position = "";
+ document.body.style.top = "";
+ window.scrollTo(0, oldScrollPosition);
+ oldScrollPosition = null;
+ }
+});
+
function createSidebarToggle() {
const sidebarToggle = document.createElement("div");
sidebarToggle.id = "sidebar-toggle";
title.innerText = "Files";
sidebar.appendChild(title);
Object.keys(sourcesIndex).forEach(key => {
- sourcesIndex[key].name = key;
+ sourcesIndex[key][NAME_OFFSET] = key;
hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
hasFoundFile);
});
}
}
+impl<I, T, U> FromWithTcx<I> for Vec<U>
+where
+ I: IntoIterator<Item = T>,
+ U: FromWithTcx<T>,
+{
+ fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec<U> {
+ f.into_iter().map(|x| x.into_tcx(tcx)).collect()
+ }
+}
+
pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
#[rustfmt::skip]
let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
use clean::GenericArgs::*;
match args {
AngleBracketed { args, bindings } => GenericArgs::AngleBracketed {
- args: args.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(),
- bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(),
+ args: args.into_vec().into_tcx(tcx),
+ bindings: bindings.into_tcx(tcx),
},
Parenthesized { inputs, output } => GenericArgs::Parenthesized {
- inputs: inputs.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(),
+ inputs: inputs.into_vec().into_tcx(tcx),
output: output.map(|a| (*a).into_tcx(tcx)),
},
}
fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self {
use clean::GenericArg::*;
match arg {
- Lifetime(l) => GenericArg::Lifetime(l.0.to_string()),
+ Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)),
Type(t) => GenericArg::Type(t.into_tcx(tcx)),
Const(box c) => GenericArg::Const(c.into_tcx(tcx)),
Infer => GenericArg::Infer,
use clean::TypeBindingKind::*;
match kind {
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
- Constraint { bounds } => {
- TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
- }
+ Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)),
}
}
}
TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)),
MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)),
TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)),
- ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)),
+ ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignTypeItem => ItemEnum::ForeignType,
}
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
generics: (*g).into_tcx(tcx),
- bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+ bounds: b.into_tcx(tcx),
default: None,
},
AssocTypeItem(t, b) => ItemEnum::AssocType {
generics: t.generics.into_tcx(tcx),
- bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+ bounds: b.into_tcx(tcx),
default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
},
// `convert_item` early returns `None` for stripped items and keywords.
}
}
+fn convert_lifetime(l: clean::Lifetime) -> String {
+ l.0.to_string()
+}
+
impl FromWithTcx<clean::Generics> for Generics {
fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self {
Generics {
- params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
- where_predicates: generics
- .where_predicates
- .into_iter()
- .map(|x| x.into_tcx(tcx))
- .collect(),
+ params: generics.params.into_tcx(tcx),
+ where_predicates: generics.where_predicates.into_tcx(tcx),
}
}
}
use clean::GenericParamDefKind::*;
match kind {
Lifetime { outlives } => GenericParamDefKind::Lifetime {
- outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(),
+ outlives: outlives.into_iter().map(convert_lifetime).collect(),
},
Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
- bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+ bounds: bounds.into_tcx(tcx),
default: default.map(|x| (*x).into_tcx(tcx)),
synthetic,
},
match predicate {
BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
type_: ty.into_tcx(tcx),
- bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+ bounds: bounds.into_tcx(tcx),
generic_params: bound_params
.into_iter()
.map(|x| GenericParamDef {
.collect(),
},
RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
- lifetime: lifetime.0.to_string(),
- bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+ lifetime: convert_lifetime(lifetime),
+ bounds: bounds.into_tcx(tcx),
},
EqPredicate { lhs, rhs } => {
WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) }
let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
GenericBound::TraitBound {
trait_,
- generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+ generic_params: generic_params.into_tcx(tcx),
modifier: from_trait_bound_modifier(modifier),
}
}
- Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()),
+ Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)),
}
}
}
impl FromWithTcx<clean::Type> for Type {
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
use clean::Type::{
- Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive,
- QPath, RawPointer, Slice, Tuple,
+ Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
+ RawPointer, Slice, Tuple,
};
match ty {
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: Vec::new(),
},
- DynTrait(mut bounds, lt) => {
- let first_trait = bounds.remove(0).trait_;
-
- Type::ResolvedPath {
- name: first_trait.whole_name(),
- id: from_item_id(first_trait.def_id().into(), tcx),
- args: first_trait
- .segments
- .last()
- .map(|args| Box::new(args.clone().args.into_tcx(tcx))),
- param_names: bounds
- .into_iter()
- .map(|t| {
- clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None)
- })
- .chain(lt.map(clean::GenericBound::Outlives))
- .map(|bound| bound.into_tcx(tcx))
- .collect(),
- }
- }
+ clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
+ lifetime: lt.map(convert_lifetime),
+ traits: bounds.into_tcx(tcx),
+ }),
Generic(s) => Type::Generic(s.to_string()),
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()),
+ Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
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()),
+ ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
Infer => Type::Infer,
RawPointer(mutability, type_) => Type::RawPointer {
mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)),
},
BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
- lifetime: lifetime.map(|l| l.0.to_string()),
+ lifetime: lifetime.map(convert_lifetime),
mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)),
},
async_: false,
abi: convert_abi(abi),
},
- generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+ generic_params: generic_params.into_tcx(tcx),
decl: decl.into_tcx(tcx),
}
}
is_unsafe,
items: ids(items, tcx),
generics: generics.into_tcx(tcx),
- bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
+ bounds: bounds.into_tcx(tcx),
implementations: Vec::new(), // Added in JsonRenderer::item
}
}
}
-impl FromWithTcx<Box<clean::Impl>> for Impl {
- fn from_tcx(impl_: Box<clean::Impl>, tcx: TyCtxt<'_>) -> Self {
+impl FromWithTcx<clean::PolyTrait> for PolyTrait {
+ fn from_tcx(
+ clean::PolyTrait { trait_, generic_params }: clean::PolyTrait,
+ tcx: TyCtxt<'_>,
+ ) -> Self {
+ PolyTrait {
+ trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx),
+ generic_params: generic_params.into_tcx(tcx),
+ }
+ }
+}
+
+impl FromWithTcx<clean::Impl> for Impl {
+ fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
let provided_trait_methods = impl_.provided_trait_methods(tcx);
- let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = *impl_;
+ let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
// FIXME: use something like ImplKind in JSON?
impl FromWithTcx<clean::Import> for Import {
fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
use clean::ImportKind::*;
- match import.kind {
- Simple(s) => Import {
- source: import.source.path.whole_name(),
- name: s.to_string(),
- id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
- glob: false,
- },
- Glob => Import {
- source: import.source.path.whole_name(),
- name: import
- .source
- .path
- .last_opt()
- .unwrap_or_else(|| Symbol::intern("*"))
- .to_string(),
- id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
- glob: true,
- },
+ let (name, glob) = match import.kind {
+ Simple(s) => (s.to_string(), false),
+ Glob => (
+ import.source.path.last_opt().unwrap_or_else(|| Symbol::intern("*")).to_string(),
+ true,
+ ),
+ };
+ Import {
+ source: import.source.path.whole_name(),
+ name,
+ id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
+ glob,
}
}
}
impl FromWithTcx<clean::OpaqueTy> for OpaqueTy {
fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self {
- OpaqueTy {
- bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
- generics: opaque.generics.into_tcx(tcx),
- }
+ OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) }
}
}
impl FromWithTcx<clean::TraitAlias> for TraitAlias {
fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self {
- TraitAlias {
- generics: alias.generics.into_tcx(tcx),
- params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
- }
+ TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) }
}
}
&UrlFragment::Item(def_id) => {
let kind = match tcx.def_kind(def_id) {
DefKind::AssocFn => {
- if tcx.associated_item(def_id).defaultness.has_value() {
+ if tcx.impl_defaultness(def_id).has_value() {
"method."
} else {
"tymethod."
/// Strip items marked `#[doc(hidden)]`
pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
let mut retained = ItemIdSet::default();
+ let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
// strip all #[doc(hidden)] items
let krate = {
};
// strip all impls referencing stripped items
- let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
+ let mut stripper = ImplStripper {
+ retained: &retained,
+ cache: &cx.cache,
+ is_json_output,
+ document_private: cx.render_options.document_private,
+ };
stripper.fold_crate(krate)
}
pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
// This stripper collects all *retained* nodes.
let mut retained = ItemIdSet::default();
+ let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
// strip all private items
{
retained: &mut retained,
access_levels: &cx.cache.access_levels,
update_retained: true,
- is_json_output: cx.output_format.is_json() && !cx.show_coverage,
+ is_json_output,
};
krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
}
// strip all impls referencing private items
- let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
+ let mut stripper = ImplStripper {
+ retained: &retained,
+ cache: &cx.cache,
+ is_json_output,
+ document_private: cx.render_options.document_private,
+ };
stripper.fold_crate(krate)
}
pub(crate) is_json_output: bool,
}
-impl<'a> Stripper<'a> {
- // We need to handle this differently for the JSON output because some non exported items could
- // be used in public API. And so, we need these items as well. `is_exported` only checks if they
- // are in the public API, which is not enough.
- #[inline]
- fn is_item_reachable(&self, item_id: ItemId) -> bool {
- if self.is_json_output {
- self.access_levels.is_reachable(item_id.expect_def_id())
- } else {
- self.access_levels.is_exported(item_id.expect_def_id())
- }
+// We need to handle this differently for the JSON output because some non exported items could
+// be used in public API. And so, we need these items as well. `is_exported` only checks if they
+// are in the public API, which is not enough.
+#[inline]
+fn is_item_reachable(
+ is_json_output: bool,
+ access_levels: &AccessLevels<DefId>,
+ item_id: ItemId,
+) -> bool {
+ if is_json_output {
+ access_levels.is_reachable(item_id.expect_def_id())
+ } else {
+ access_levels.is_exported(item_id.expect_def_id())
}
}
| clean::MacroItem(..)
| clean::ForeignTypeItem => {
let item_id = i.item_id;
- if item_id.is_local() && !self.is_item_reachable(item_id) {
+ if item_id.is_local()
+ && !is_item_reachable(self.is_json_output, self.access_levels, item_id)
+ {
debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
return None;
}
pub(crate) struct ImplStripper<'a> {
pub(crate) retained: &'a ItemIdSet,
pub(crate) cache: &'a Cache,
+ pub(crate) is_json_output: bool,
+ pub(crate) document_private: bool,
}
impl<'a> DocFolder for ImplStripper<'a> {
if let clean::ImplItem(ref imp) = *i.kind {
// Impl blocks can be skipped if they are: empty; not a trait impl; and have no
// documentation.
- if imp.trait_.is_none() && imp.items.is_empty() && i.doc_value().is_none() {
- return None;
+ //
+ // There is one special case: if the impl block contains only private items.
+ if imp.trait_.is_none() {
+ // If the only items present are private ones and we're not rendering private items,
+ // we don't document it.
+ if !imp.items.is_empty()
+ && !self.document_private
+ && imp.items.iter().all(|i| {
+ let item_id = i.item_id;
+ item_id.is_local()
+ && !is_item_reachable(
+ self.is_json_output,
+ &self.cache.access_levels,
+ item_id,
+ )
+ })
+ {
+ return None;
+ } else if imp.items.is_empty() && i.doc_value().is_none() {
+ return None;
+ }
}
if let Some(did) = imp.for_.def_id(self.cache) {
if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
tcx.hir().visit_all_item_likes_in_crate(&mut finder);
+ // The visitor might have found a type error, which we need to
+ // promote to a fatal error
+ if tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() {
+ return Err(String::from("Compilation failed, aborting rustdoc"));
+ }
+
// Sort call locations within a given file in document order
for fn_calls in calls.values_mut() {
for file_calls in fn_calls.values_mut() {
-Subproject commit 8b6b5014fdad3a750f7242a6bfdcad83619498d4
+Subproject commit e3be3f64ecac101d14ceda759ba078ad0aaf3747
use serde::{Deserialize, Serialize};
/// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 16;
+pub const FORMAT_VERSION: u32 = 17;
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow
},
}
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+pub struct DynTrait {
+ /// All the traits implemented. One of them is the vtable, and the rest must be auto traits.
+ pub traits: Vec<PolyTrait>,
+ /// The lifetime of the whole dyn object
+ /// ```text
+ /// dyn Debug + 'static
+ /// ^^^^^^^
+ /// |
+ /// this part
+ /// ```
+ pub lifetime: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+/// A trait and potential HRTBs
+pub struct PolyTrait {
+ #[serde(rename = "trait")]
+ pub trait_: Type,
+ /// Used for Higher-Rank Trait Bounds (HRTBs)
+ /// ```text
+ /// dyn for<'a> Fn() -> &'a i32"
+ /// ^^^^^^^
+ /// |
+ /// this part
+ /// ```
+ pub generic_params: Vec<GenericParamDef>,
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum GenericArgs {
type_: Type,
bounds: Vec<GenericBound>,
/// Used for Higher-Rank Trait Bounds (HRTBs)
- /// ```plain
+ /// ```text
/// where for<'a> &'a T: Iterator,"
/// ^^^^^^^
/// |
#[serde(rename = "trait")]
trait_: Type,
/// Used for Higher-Rank Trait Bounds (HRTBs)
- /// ```plain
+ /// ```text
/// where F: for<'a, 'b> Fn(&'a u8, &'b u8)
/// ^^^^^^^^^^^
/// |
args: Option<Box<GenericArgs>>,
param_names: Vec<GenericBound>,
},
+ DynTrait(DynTrait),
/// Parameterized types
Generic(String),
/// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples
pub struct FunctionPointer {
pub decl: FnDecl,
/// Used for Higher-Rank Trait Bounds (HRTBs)
- /// ```plain
+ /// ```text
/// for<'c> fn(val: &'c i32) -> i32
/// ^^^^^^^
/// |
/// May be different from the last segment of `source` when renaming imports:
/// `use source as name;`
pub name: String,
- /// The ID of the item being imported.
- pub id: Option<Id>, // FIXME is this actually ever None?
+ /// The ID of the item being imported. Will be `None` in case of re-exports of primitives:
+ /// ```rust
+ /// pub use i32 as my_i32;
+ /// ```
+ pub id: Option<Id>,
/// Whether this import uses a glob: `use source::*;`
pub glob: bool,
}
// CHECK-LABEL: sym_static:
// CHECK: #APP
// CHECK: auipc t0, %pcrel_hi(extern_static)
-// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi0)(t0)
+// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi{{[0-9]+}})(t0)
// CHECK: #NO_APP
#[no_mangle]
pub unsafe fn sym_static() {
}
-struct NonGenericNoDrop(i32);
+struct NonGenericNoDrop(#[allow(unused_tuple_struct_fields)] i32);
-struct NonGenericWithDrop(i32);
+struct NonGenericWithDrop(#[allow(unused_tuple_struct_fields)] i32);
//~ MONO_ITEM fn std::ptr::drop_in_place::<NonGenericWithDrop> - shim(Some(NonGenericWithDrop)) @@ generic_drop_glue-cgu.0[Internal]
impl Drop for NonGenericWithDrop {
#![feature(start)]
//~ MONO_ITEM fn std::ptr::drop_in_place::<Root> - shim(Some(Root)) @@ transitive_drop_glue-cgu.0[Internal]
-struct Root(Intermediate);
+struct Root(#[allow(unused_tuple_struct_fields)] Intermediate);
//~ MONO_ITEM fn std::ptr::drop_in_place::<Intermediate> - shim(Some(Intermediate)) @@ transitive_drop_glue-cgu.0[Internal]
-struct Intermediate(Leaf);
+struct Intermediate(#[allow(unused_tuple_struct_fields)] Leaf);
//~ MONO_ITEM fn std::ptr::drop_in_place::<Leaf> - shim(Some(Leaf)) @@ transitive_drop_glue-cgu.0[Internal]
struct Leaf;
fn drop(&mut self) {}
}
-struct RootGen<T>(IntermediateGen<T>);
-struct IntermediateGen<T>(LeafGen<T>);
-struct LeafGen<T>(T);
+struct RootGen<T>(#[allow(unused_tuple_struct_fields)] IntermediateGen<T>);
+struct IntermediateGen<T>(#[allow(unused_tuple_struct_fields)] LeafGen<T>);
+struct LeafGen<T>(#[allow(unused_tuple_struct_fields)] T);
impl<T> Drop for LeafGen<T> {
fn drop(&mut self) {}
}
#[derive(Clone, Copy)]
-struct Wrapper<T: ?Sized>(*const T);
+struct Wrapper<T: ?Sized>(#[allow(unused_tuple_struct_fields)] *const T);
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
--- /dev/null
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+use std::alloc::Layout;
+
+type RGB48 = [u16; 3];
+
+// CHECK-LABEL: @layout_array_rgb48
+#[no_mangle]
+pub fn layout_array_rgb48(n: usize) -> Layout {
+ // CHECK-NOT: llvm.umul.with.overflow.i64
+ // CHECK: icmp ugt i64 %n, 1537228672809129301
+ // CHECK-NOT: llvm.umul.with.overflow.i64
+ // CHECK: mul nuw nsw i64 %n, 6
+ // CHECK-NOT: llvm.umul.with.overflow.i64
+ Layout::array::<RGB48>(n).unwrap()
+}
+
+// CHECK-LABEL: @layout_array_i32
+#[no_mangle]
+pub fn layout_array_i32(n: usize) -> Layout {
+ // CHECK-NOT: llvm.umul.with.overflow.i64
+ // CHECK: icmp ugt i64 %n, 2305843009213693951
+ // CHECK-NOT: llvm.umul.with.overflow.i64
+ // CHECK: shl nuw nsw i64 %n, 2
+ // CHECK-NOT: llvm.umul.with.overflow.i64
+ Layout::array::<i32>(n).unwrap()
+}
-// compile-flags: -O
+// revisions: O Os
+//[Os] compile-flags: -Copt-level=s
+//[O] compile-flags: -O
#![crate_type = "lib"]
-// CHECK: @func2 = {{.*}}alias{{.*}}@func1
+// CHECK: @func{{2|1}} = {{.*}}alias{{.*}}@func{{1|2}}
#[no_mangle]
pub fn func1(c: char) -> bool {
--- /dev/null
+// compile-flags:-g
+// min-gdb-version: 10.1
+
+// === GDB TESTS ===================================================================================
+// gdb-command:run
+// gdb-command:p TEST
+// gdb-check:$1 = 3735928559
+// gdb-command:p no_mangle_info::namespace::OTHER_TEST
+// gdb-check:$2 = 42
+
+// === LLDB TESTS ==================================================================================
+// lldb-command:run
+// lldb-command:p TEST
+// lldb-check: (unsigned long) $0 = 3735928559
+// lldb-command:p OTHER_TEST
+// lldb-check: (unsigned long) $1 = 42
+
+// === CDB TESTS ==================================================================================
+// cdb-command: g
+// Note: LLDB and GDB allow referring to items that are in the same namespace of the symbol
+// we currently have a breakpoint on in an unqualified way. CDB does not, and thus we need to
+// refer to it in a fully qualified way.
+// cdb-command: dx a!no_mangle_info::TEST
+// cdb-check: a!no_mangle_info::TEST : 0xdeadbeef [Type: unsigned __int64]
+// cdb-command: dx a!no_mangle_info::namespace::OTHER_TEST
+// cdb-check: a!no_mangle_info::namespace::OTHER_TEST : 0x2a [Type: unsigned __int64]
+
+#[no_mangle]
+pub static TEST: u64 = 0xdeadbeef;
+
+// FIXME(rylev, wesleywiser): uncommenting this item breaks the test, and we're not sure why
+// pub static OTHER_TEST: u64 = 43;
+pub mod namespace {
+ pub static OTHER_TEST: u64 = 42;
+}
+
+pub fn main() {
+ println!("TEST: {}", TEST);
+ println!("OTHER TEST: {}", namespace::OTHER_TEST); // #break
+}
// Change Method Privacy -------------------------------------------------------
#[cfg(any(cfail1,cfail4))]
impl Foo {
- //----------------------------------------------------
//--------------------------
- //------------------------------------------------------------------------------
+ //--------------------------
+ //--------------------------------------------------------------
//--------------------------
pub fn method_privacy() { }
}
#[rustc_clean(cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
impl Foo {
- #[rustc_clean(cfg="cfail2", except="associated_item")]
+ #[rustc_clean(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
- #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item")]
+ #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
fn method_privacy() { }
}
// Add default implementation to method
#[cfg(any(cfail1,cfail4))]
trait TraitAddMethodAutoImplementation {
- // -----------------------------------------------------------------------------
+ // -------------------------------------------------------------
// -------------------------
- // -----------------------------------------------------------------------------
+ // -------------------------------------------------------------
// -------------------------
fn method() ;
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
trait TraitAddMethodAutoImplementation {
- #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
- #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
fn method() {}
}
// Add default to associated type
#[cfg(any(cfail1,cfail4))]
trait TraitAddDefaultToAssociatedType {
- type Associated;
+ //--------------------------------------------------------------
+ //--------------------------
+ //--------------------------------------------------------------
+ //--------------------------
+ type Associated ;
fn method();
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
trait TraitAddDefaultToAssociatedType {
- #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
- #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
type Associated = ReferenceType0;
// Add initializer to associated constant
#[cfg(any(cfail1,cfail4))]
trait TraitAddInitializerToAssociatedConstant {
- const Value: u32;
+ //--------------------------------------------------------------
+ //--------------------------
+ //--------------------------------------------------------------
+ //--------------------------
+ const Value: u32 ;
+ //--------------------------
+ //--------------------------
+ //--------------------------
+ //--------------------------
fn method();
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
trait TraitAddInitializerToAssociatedConstant {
- #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
- #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
const Value: u32 = 1;
#[cfg(any(cfail1,cfail4))]
pub trait ChangeHasValueTrait {
- fn method_name();
+ //--------------------------------------------------------------
+ //--------------------------
+ //--------------------------------------------------------------
+ //--------------------------
+ fn method_name() ;
}
#[cfg(any(cfail1,cfail4))]
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
pub trait ChangeHasValueTrait {
- #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
- #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
fn method_name() { }
}
#[cfg(any(cfail1,cfail4))]
impl AddDefaultTrait for Foo {
- // ----------------------------------------------------
+ // -------------------------------------------------------------
// -------------------------
- // ----------------------------------------------------
+ // -------------------------------------------------------------
// -------------------------
fn method_name() { }
}
#[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
impl AddDefaultTrait for Foo {
- #[rustc_clean(except="associated_item", cfg="cfail2")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
- #[rustc_clean(except="associated_item", cfg="cfail5")]
+ #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
default fn method_name() { }
}
to your test, causing separate files to be generated for 32bit and 64bit systems.
+## Unit testing
+
+If you are only testing the behavior of a particular mir-opt pass on some specific input (as is
+usually the case), you should add
+
+```
+// unit-test: PassName
+```
+
+to the top of the file. This makes sure that other passes don't run which means you'll get the input
+you expected and your test won't break when other code changes.
+
## Emit a diff of the mir for a specific optimization
This is what you want most often when you want to see how an optimization changes the MIR.
+// unit-test: InstCombine
+
// EMIT_MIR bool_compare.opt1.InstCombine.diff
fn opt1(x: bool) -> u32 {
if x != true { 0 } else { 1 }
+++ /dev/null
-- // MIR for `norm2` before InstCombine
-+ // MIR for `norm2` after InstCombine
-
- fn norm2(_1: [f32; 2]) -> f32 {
- debug x => _1; // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11
- let mut _0: f32; // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29
- let _2: f32; // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
- let _3: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
- let mut _4: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- let mut _5: bool; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- let _7: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16
- let mut _8: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
- let mut _9: bool; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
- let mut _10: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8
- let mut _11: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6
- let mut _12: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8
- let mut _13: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14
- let mut _14: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12
- let mut _15: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14
- scope 1 {
- debug a => _2; // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10
- let _6: f32; // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
- scope 2 {
- debug b => _6; // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10
- }
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
- StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
- _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
-- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-+ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- }
-
- bb1: {
- _2 = _1[_3]; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18
- StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
- StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
- _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
-- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-+ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
- _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
- }
-
- bb2: {
- _6 = _1[_7]; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
- StorageDead(_7); // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18
- StorageLive(_10); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
- StorageLive(_11); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
- _11 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
- StorageLive(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
- _12 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
- _10 = Mul(move _11, move _12); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
- StorageDead(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
- StorageDead(_11); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
- StorageLive(_13); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
- StorageLive(_14); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
- _14 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
- StorageLive(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- _15 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- _13 = Mul(move _14, move _15); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
- StorageDead(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- StorageDead(_14); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- _0 = Add(move _10, move _13); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14
- StorageDead(_13); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- StorageDead(_10); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- StorageDead(_6); // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2
- StorageDead(_2); // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2
- return; // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2
- }
- }
-
+++ /dev/null
-- // MIR for `norm2` before InstCombine
-+ // MIR for `norm2` after InstCombine
-
- fn norm2(_1: [f32; 2]) -> f32 {
- debug x => _1; // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11
- let mut _0: f32; // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29
- let _2: f32; // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
- let _3: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
- let mut _4: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- let mut _5: bool; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- let _7: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16
- let mut _8: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
- let mut _9: bool; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
- let mut _10: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8
- let mut _11: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6
- let mut _12: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8
- let mut _13: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14
- let mut _14: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12
- let mut _15: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14
- scope 1 {
- debug a => _2; // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10
- let _6: f32; // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
- scope 2 {
- debug b => _6; // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10
- }
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
- StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
- _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
-- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-+ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- }
-
- bb1: {
- _2 = _1[_3]; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
- StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18
- StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
- StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
- _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
-- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-+ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
- _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
- }
-
- bb2: {
- _6 = _1[_7]; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
- StorageDead(_7); // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18
- StorageLive(_10); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
- StorageLive(_11); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
- _11 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
- StorageLive(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
- _12 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
- _10 = Mul(move _11, move _12); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
- StorageDead(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
- StorageDead(_11); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
- StorageLive(_13); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
- StorageLive(_14); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
- _14 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
- StorageLive(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- _15 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- _13 = Mul(move _14, move _15); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
- StorageDead(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- StorageDead(_14); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- _0 = Add(move _10, move _13); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14
- StorageDead(_13); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- StorageDead(_10); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
- StorageDead(_6); // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2
- StorageDead(_2); // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2
- return; // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2
- }
- }
-
--- /dev/null
+- // MIR for `norm2` before InstCombine
++ // MIR for `norm2` after InstCombine
+
+ fn norm2(_1: [f32; 2]) -> f32 {
+ debug x => _1; // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11
+ let mut _0: f32; // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29
+ let _2: f32; // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
+ let _3: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
+ let mut _4: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+ let mut _5: bool; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+ let _7: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16
+ let mut _8: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
+ let mut _9: bool; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
+ let mut _10: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8
+ let mut _11: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6
+ let mut _12: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8
+ let mut _13: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14
+ let mut _14: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12
+ let mut _15: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14
+ scope 1 {
+ debug a => _2; // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10
+ let _6: f32; // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
+ scope 2 {
+ debug b => _6; // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10
+ }
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
+ StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
+ _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
+- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
++ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+ _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+ }
+
+ bb1: {
+ _2 = _1[_3]; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
+ StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18
+ StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
+ StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
+ _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
+- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
++ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
+ _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
+ assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
+ }
+
+ bb2: {
+ _6 = _1[_7]; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
+ StorageDead(_7); // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18
+ StorageLive(_10); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
+ StorageLive(_11); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
+ _11 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
+ StorageLive(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
+ _12 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
+ _10 = Mul(move _11, move _12); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
+ StorageDead(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
+ StorageDead(_11); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
+ StorageLive(_13); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
+ StorageLive(_14); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
+ _14 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
+ StorageLive(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+ _15 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+ _13 = Mul(move _14, move _15); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
+ StorageDead(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+ StorageDead(_14); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+ _0 = Add(move _10, move _13); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14
+ StorageDead(_13); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+ StorageDead(_10); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
+ StorageDead(_6); // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2
+ StorageDead(_2); // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2
+ }
+ }
+
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// unit-test: InstCombine
// EMIT_MIR combine_array_len.norm2.InstCombine.diff
fn norm2(x: [f32; 2]) -> f32 {
+// unit-test: ConstGoto
+
pub enum Foo {
A,
B,
bb0: {
StorageLive(_1); // scope 0 at $DIR/const_goto_storage.rs:+1:9: +1:12
- StorageLive(_2); // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
-- nop; // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
+- Deinit(_2); // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
- StorageLive(_3); // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10
- StorageLive(_4); // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76
- StorageLive(_5); // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52
+// unit-test: ConstGoto
+
// EMIT_MIR const_goto_storage.match_nested_if.ConstGoto.diff
fn match_nested_if() -> bool {
let val = match () {
let mut _7: std::boxed::Box<i32>; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
let mut _8: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
let mut _9: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
- let mut _10: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
- let mut _11: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
scope 1 {
debug x => _1; // in scope 1 at $DIR/boxes.rs:+1:9: +1:10
}
+// unit-test: Deaggregator
+
struct Baz {
x: usize,
y: f32,
+// unit-test: Deaggregator
+
enum Baz {
Empty,
Foo { x: usize },
+// unit-test: Deaggregator
// Test that deaggregate fires in more than one basic block
enum Foo {
+// unit-test: Deaggregator
// Test that deaggregate fires more than once per block
enum Foo {
let mut _2: &[u8]; // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
let mut _3: &str; // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
let mut _4: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
- let mut _5: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
- let mut _6: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
- let mut _7: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
- scope 1 (inlined core::str::<impl str>::as_bytes) { // at $DIR/deduplicate_blocks.rs:3:11: 3:23
- debug self => _3; // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL
- let mut _8: &str; // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL
- scope 2 {
- }
- }
+ let mut _5: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+ let mut _6: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+ let mut _7: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+ let mut _8: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+ let mut _9: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
bb0: {
StorageLive(_2); // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
StorageLive(_3); // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
- _3 = _1; // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
- StorageLive(_8); // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
- _8 = _3; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-- _2 = transmute::<&str, &[u8]>(move _8) -> bb14; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-+ _2 = transmute::<&str, &[u8]>(move _8) -> bb12; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
+ _3 = &(*_1); // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
+ _2 = core::str::<impl str>::as_bytes(move _3) -> bb1; // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
// mir::Constant
- // + span: $SRC_DIR/core/src/str/mod.rs:LL:COL
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {transmute::<&str, &[u8]>}, val: Value(<ZST>) }
+ // + span: $DIR/deduplicate_blocks.rs:5:13: 5:21
+ // + literal: Const { ty: for<'r> fn(&'r str) -> &'r [u8] {core::str::<impl str>::as_bytes}, val: Value(<ZST>) }
}
bb1: {
- switchInt((*_2)[0 of 4]) -> [47_u8: bb2, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+ StorageDead(_3); // scope 0 at $DIR/deduplicate_blocks.rs:+1:22: +1:23
+ _7 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+ _8 = const 4_usize; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+ _9 = Ge(move _7, move _8); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+ switchInt(move _9) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
}
bb2: {
- switchInt((*_2)[1 of 4]) -> [47_u8: bb3, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+ switchInt((*_2)[0 of 4]) -> [47_u8: bb3, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
}
bb3: {
- switchInt((*_2)[2 of 4]) -> [47_u8: bb4, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+ switchInt((*_2)[1 of 4]) -> [47_u8: bb4, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
}
bb4: {
-- switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
-+ switchInt((*_2)[3 of 4]) -> [47_u8: bb9, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+ switchInt((*_2)[2 of 4]) -> [47_u8: bb5, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
}
bb5: {
- _4 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
- _5 = Ge(move _4, const 3_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
- switchInt(move _5) -> [false: bb9, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+- switchInt((*_2)[3 of 4]) -> [47_u8: bb11, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
++ switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
}
bb6: {
- switchInt((*_2)[0 of 3]) -> [47_u8: bb7, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+ _4 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+ _5 = const 3_usize; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+ _6 = Ge(move _4, move _5); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+ switchInt(move _6) -> [false: bb10, otherwise: bb7]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
}
bb7: {
- switchInt((*_2)[1 of 3]) -> [47_u8: bb8, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+ switchInt((*_2)[0 of 3]) -> [47_u8: bb8, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
}
bb8: {
-- switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb12, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
-+ switchInt((*_2)[2 of 3]) -> [47_u8: bb10, 33_u8: bb10, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+ switchInt((*_2)[1 of 3]) -> [47_u8: bb9, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
}
bb9: {
+- switchInt((*_2)[2 of 3]) -> [47_u8: bb12, 33_u8: bb13, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
++ switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb11, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+ }
+
+ bb10: {
- _0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19
-- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19
+- goto -> bb14; // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19
- }
-
-- bb10: {
+- bb11: {
_0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
-- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
-+ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
+- goto -> bb14; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
++ goto -> bb12; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
}
-- bb11: {
+- bb12: {
- _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39
-- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39
+- goto -> bb14; // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39
- }
-
-- bb12: {
-+ bb10: {
- _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
-- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
-+ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
- }
-
- bb13: {
+ bb11: {
- StorageDead(_2); // scope 0 at $DIR/deduplicate_blocks.rs:+7:1: +7:2
- return; // scope 0 at $DIR/deduplicate_blocks.rs:+7:2: +7:2
+ _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
+- goto -> bb14; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
++ goto -> bb12; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
}
- bb14: {
+ bb12: {
- StorageDead(_8); // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
- StorageDead(_3); // scope 0 at $DIR/deduplicate_blocks.rs:+1:22: +1:23
- _6 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
- _7 = Ge(move _6, const 4_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
- switchInt(move _7) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+ StorageDead(_2); // scope 0 at $DIR/deduplicate_blocks.rs:+7:1: +7:2
+ return; // scope 0 at $DIR/deduplicate_blocks.rs:+7:2: +7:2
}
}
+// unit-test: DeduplicateBlocks
+
// EMIT_MIR deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
pub const fn is_line_doc_comment_2(s: &str) -> bool {
match s.as_bytes() {
StorageLive(_2); // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
_14 = const main::promoted[0]; // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
// mir::Constant
- // + span: $DIR/derefer_complex_case.rs:5:17: 5:26
+ // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
// + literal: Const { ty: &[i32; 2], val: Unevaluated(main, [], Some(promoted[0])) }
_2 = &(*_14); // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
_1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
// mir::Constant
- // + span: $DIR/derefer_complex_case.rs:5:17: 5:26
+ // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
// + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(<ZST>) }
}
_8 = &mut (*_9); // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
_7 = <std::slice::Iter<i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
// mir::Constant
- // + span: $DIR/derefer_complex_case.rs:5:17: 5:26
+ // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
// + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(<ZST>) }
}
_13 = _12; // scope 2 at $DIR/derefer_complex_case.rs:+1:34: +1:37
_6 = std::mem::drop::<i32>(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:+1:29: +1:38
// mir::Constant
- // + span: $DIR/derefer_complex_case.rs:5:29: 5:33
+ // + span: $DIR/derefer_complex_case.rs:6:29: 6:33
// + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) }
}
StorageDead(_6); // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40
_5 = const (); // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40
goto -> bb2; // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40
-+ }
-+
-+ bb8 (cleanup): {
-+ resume; // scope 0 at $DIR/derefer_complex_case.rs:+0:1: +2:2
}
}
+// unit-test: Derefer
// EMIT_MIR derefer_complex_case.main.Derefer.diff
// ignore-wasm32
_3 = AlignOf(std::boxed::Box<u32>); // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12
_4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12
// mir::Constant
- // + span: $DIR/derefer_inline_test.rs:10:5: 10:12
+ // + span: $DIR/derefer_inline_test.rs:11:5: 11:12
// + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
}
_5 = ShallowInitBox(move _4, std::boxed::Box<u32>); // scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12
(*_5) = f() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:+1:9: +1:12
// mir::Constant
- // + span: $DIR/derefer_inline_test.rs:10:9: 10:10
+ // + span: $DIR/derefer_inline_test.rs:11:9: 11:10
// + literal: Const { ty: fn() -> Box<u32> {f}, val: Value(<ZST>) }
}
+// unit-test: Derefer
// EMIT_MIR derefer_inline_test.main.Derefer.diff
// ignore-wasm32 compiled with panic=abort by default
StorageLive(_1); // scope 0 at $DIR/derefer_terminator_test.rs:+1:9: +1:10
_1 = foo() -> bb1; // scope 0 at $DIR/derefer_terminator_test.rs:+1:13: +1:18
// mir::Constant
- // + span: $DIR/derefer_terminator_test.rs:5:13: 5:16
+ // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16
// + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) }
}
StorageLive(_2); // scope 1 at $DIR/derefer_terminator_test.rs:+2:9: +2:10
_2 = foo() -> bb2; // scope 1 at $DIR/derefer_terminator_test.rs:+2:13: +2:18
// mir::Constant
- // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16
+ // + span: $DIR/derefer_terminator_test.rs:7:13: 7:16
// + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) }
}
StorageDead(_2); // scope 1 at $DIR/derefer_terminator_test.rs:+8:1: +8:2
StorageDead(_1); // scope 0 at $DIR/derefer_terminator_test.rs:+8:1: +8:2
return; // scope 0 at $DIR/derefer_terminator_test.rs:+8:2: +8:2
-+ }
-+
-+ bb6 (cleanup): {
-+ resume; // scope 0 at $DIR/derefer_terminator_test.rs:+0:1: +8:2
}
}
+// unit-test: Derefer
// EMIT_MIR derefer_terminator_test.main.Derefer.diff
// ignore-wasm32
StorageDead(_2); // scope 1 at $DIR/derefer_test.rs:+5:1: +5:2
StorageDead(_1); // scope 0 at $DIR/derefer_test.rs:+5:1: +5:2
return; // scope 0 at $DIR/derefer_test.rs:+5:2: +5:2
-+ }
-+
-+ bb1 (cleanup): {
-+ resume; // scope 0 at $DIR/derefer_test.rs:+0:1: +5:2
}
}
+// unit-test: Derefer
// EMIT_MIR derefer_test.main.Derefer.diff
fn main() {
let mut a = (42,43);
StorageDead(_2); // scope 1 at $DIR/derefer_test_multiple.rs:+7:1: +7:2
StorageDead(_1); // scope 0 at $DIR/derefer_test_multiple.rs:+7:1: +7:2
return; // scope 0 at $DIR/derefer_test_multiple.rs:+7:2: +7:2
-+ }
-+
-+ bb1 (cleanup): {
-+ resume; // scope 0 at $DIR/derefer_test_multiple.rs:+0:1: +7:2
}
}
+// unit-test: Derefer
// EMIT_MIR derefer_test_multiple.main.Derefer.diff
fn main () {
let mut a = (42, 43);
+// unit-test InstCombine
+
// EMIT_MIR equal_true.opt.InstCombine.diff
fn opt(x: bool) -> i32 {
StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:+2:24: +2:25
StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:+3:1: +3:2
return; // scope 0 at $DIR/dyn-trait.rs:+3:2: +3:2
-+ }
-+
-+ bb3 (cleanup): {
-+ resume; // scope 0 at $DIR/dyn-trait.rs:+0:1: +3:2
}
}
+ StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:+0:21: +0:22
StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:+1:15: +1:16
return; // scope 0 at $DIR/dyn-trait.rs:+2:2: +2:2
-+ }
-+
-+ bb2 (cleanup): {
-+ resume; // scope 0 at $DIR/dyn-trait.rs:+0:1: +2:2
}
}
StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:+3:1: +3:2
return; // scope 0 at $DIR/inline-any-operand.rs:+3:2: +3:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/inline-any-operand.rs:+0:1: +3:2
- }
}
StorageDead(_3); // scope 0 at $DIR/inline-closure.rs:+3:1: +3:2
return; // scope 0 at $DIR/inline-closure.rs:+3:2: +3:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/inline-closure.rs:+0:1: +3:2
- }
}
StorageDead(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:1: +6:2
return; // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:2: +6:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:1: +6:2
- }
}
StorageDead(_3); // scope 0 at $DIR/inline-closure-captures.rs:+3:1: +3:2
return; // scope 0 at $DIR/inline-closure-captures.rs:+3:2: +3:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/inline-closure-captures.rs:+0:1: +3:2
- }
}
StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:18: +1:19
_0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:37: +2:2
return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
-+ }
-+
-+ bb1 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-compatibility.rs:+0:1: +2:2
}
}
StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:21: +1:22
_0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:40: +2:2
return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
-+ }
-+
-+ bb1 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-compatibility.rs:+0:1: +2:2
}
}
StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:+1:24: +1:25
_0 = const (); // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2
return; // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2
-+ }
-+
-+ bb2 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-cycle.rs:+0:1: +2:2
}
}
StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:+1:12: +1:13
_0 = const (); // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2
return; // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2
-+ }
-+
-+ bb2 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-cycle.rs:+0:1: +2:2
}
}
StorageDead(_1); // scope 0 at $DIR/inline-cycle-generic.rs:+1:24: +1:25
_0 = const (); // scope 0 at $DIR/inline-cycle-generic.rs:+0:11: +2:2
return; // scope 0 at $DIR/inline-cycle-generic.rs:+2:2: +2:2
-+ }
-+
-+ bb2 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-cycle-generic.rs:+0:1: +2:2
}
}
+
+ bb1: {
+ goto -> bb1; // scope 1 at $DIR/inline-diverging.rs:+32:5: +32:12
-+ }
-+
-+ bb2 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-diverging.rs:+0:1: +2:2
}
}
+ // mir::Constant
+ // + span: $SRC_DIR/std/src/panic.rs:LL:COL
+ // + literal: Const { ty: &str, val: Value(Slice(..)) }
-+ }
-+
-+ bb3 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-diverging.rs:+0:1: +6:2
}
}
+
+ bb1: {
+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:+18:5: +18:12
-+ }
-+
-+ bb2 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-diverging.rs:+0:1: +2:2
}
}
StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:+3:30: +3:31
_0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:+0:18: +4:2
return; // scope 0 at $DIR/inline-instruction-set.rs:+4:2: +4:2
-+ }
-+
-+ bb3 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-instruction-set.rs:+0:1: +4:2
}
}
StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:+5:30: +5:31
_0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:+0:14: +6:2
return; // scope 0 at $DIR/inline-instruction-set.rs:+6:2: +6:2
-+ }
-+
-+ bb3 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-instruction-set.rs:+0:1: +6:2
}
}
let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _8: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+ let mut _9: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
scope 1 {
debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
}
scope 2 {
}
+ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ }
bb0: {
StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
_7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
- (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ StorageLive(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ _9 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ StorageLive(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ _10 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageLive(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ _8 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
// mir::Constant
- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
- // + user_ty: UserType(1)
+ // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+ Deinit((*_9)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_9).0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageDead(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
_1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _8: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+ let mut _9: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
scope 1 {
debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
}
scope 2 {
}
+ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+ let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ }
bb0: {
StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
_7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
- (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ StorageLive(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ _9 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ StorageLive(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ _10 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageLive(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ _8 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
// mir::Constant
- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
- // + user_ty: UserType(1)
+ // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+ Deinit((*_9)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_9).0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++ StorageDead(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
_1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
_0 = const (); // scope 0 at $DIR/inline-options.rs:+0:11: +3:2
return; // scope 0 at $DIR/inline-options.rs:+3:2: +3:2
}
-
- bb5 (cleanup): {
- resume; // scope 0 at $DIR/inline-options.rs:+0:1: +3:2
- }
}
StorageDead(_4); // scope 0 at $DIR/inline-retag.rs:+3:1: +3:2
return; // scope 0 at $DIR/inline-retag.rs:+3:2: +3:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/inline-retag.rs:+0:1: +3:2
- }
}
+ _0 = (*_2); // scope 1 at $SRC_DIR/core/src/clone.rs:LL:COL
StorageDead(_2); // scope 0 at $DIR/inline-shims.rs:+1:13: +1:14
return; // scope 0 at $DIR/inline-shims.rs:+2:2: +2:2
-+ }
-+
-+ bb1 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-shims.rs:+0:1: +2:2
}
}
+
+ bb3: {
+ drop((((*_5) as Some).0: B)) -> bb2; // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-+ }
-+
-+ bb4 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-shims.rs:+0:1: +3:2
}
}
_0 = const (); // scope 0 at $DIR/inline-specialization.rs:+0:11: +2:2
StorageDead(_1); // scope 0 at $DIR/inline-specialization.rs:+2:1: +2:2
return; // scope 0 at $DIR/inline-specialization.rs:+2:2: +2:2
-+ }
-+
-+ bb1 (cleanup): {
-+ resume; // scope 0 at $DIR/inline-specialization.rs:+0:1: +2:2
}
}
StorageDead(_2); // scope 0 at $DIR/inline-trait-method_2.rs:+1:11: +1:12
return; // scope 0 at $DIR/inline-trait-method_2.rs:+2:2: +2:2
}
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/inline-trait-method_2.rs:+0:1: +2:2
- }
}
StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
- }
}
StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
- }
}
StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
- }
}
StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
- }
}
StorageDead(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:1: +3:2
return; // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:2: +3:2
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+0:1: +3:2
- }
}
let mut _0: bool; // return place in scope 0 at /the/src/instrument_coverage.rs:+0:13: +0:17
bb0: {
-+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:19:1 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2
++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:20:1 - 22:2; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2
_0 = const true; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +1:9
return; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2
}
let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:+2:18: +4:10
bb0: {
-+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 10:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:11:1 - 11:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
}
bb1: {
-+ Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:11:5 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
++ Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:12:5 - 13:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
}
StorageLive(_2); // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17
_2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17
// mir::Constant
- // + span: /the/src/instrument_coverage.rs:12:12: 12:15
+ // + span: /the/src/instrument_coverage.rs:13:12: 13:15
// + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) }
}
}
bb4: {
-+ Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
-+ Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
++ Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:17:1 - 17:2; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
++ Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:14:13 - 14:18; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
_0 = const (); // scope 0 at /the/src/instrument_coverage.rs:+3:13: +3:18
StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10
return; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
}
bb5: {
-+ Coverage::Counter(2) for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
++ Coverage::Counter(2) for /the/src/instrument_coverage.rs:15:10 - 15:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
_1 = const (); // scope 0 at /the/src/instrument_coverage.rs:+4:10: +4:10
StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10
goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
// Test that `-C instrument-coverage` injects Coverage statements. The Coverage Counter statements
// are later converted into LLVM instrprof.increment intrinsics, during codegen.
+// unit-test: InstrumentCoverage
// needs-profiler-support
// ignore-windows
// compile-flags: -C instrument-coverage --remap-path-prefix={{src-base}}=/the/src
bb1: {
return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
}
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
- }
}
bb5: {
return; // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2
}
-
- bb6 (cleanup): {
- resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +5:2
- }
}
bb2: {
return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
}
-
- bb3 (cleanup): {
- resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
- }
}
StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+4:1: +4:2
return; // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
}
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +4:2
- }
}
bb1: {
return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
}
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
- }
}
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) }
+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
}
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
- }
}
StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:+4:1: +4:2
return; // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
}
-
- bb4 (cleanup): {
- resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +4:2
- }
}
+// unit-test: InstCombine
// EMIT_MIR not_equal_false.opt.InstCombine.diff
fn opt(x: bool) -> u32 {
scope 3 {
debug i => _12; // in scope 3 at $DIR/remove_storage_markers.rs:+2:9: +2:10
}
- scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
- debug self => _8; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
- let mut _14: &mut std::ops::Range<i32>; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
- }
- }
- scope 4 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
- debug self => _3; // in scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
}
}
Deinit(_3); // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
(_3.0: i32) = const 0_i32; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
(_3.1: i32) = const 10_i32; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
- _2 = move _3; // scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+ _2 = <std::ops::Range<i32> as IntoIterator>::into_iter(move _3) -> bb1; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+ // mir::Constant
+ // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
+ // + literal: Const { ty: fn(std::ops::Range<i32>) -> <std::ops::Range<i32> as IntoIterator>::IntoIter {<std::ops::Range<i32> as IntoIterator>::into_iter}, val: Value(<ZST>) }
+ }
+
+ bb1: {
- StorageDead(_3); // scope 1 at $DIR/remove_storage_markers.rs:+2:18: +2:19
- StorageLive(_4); // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
_4 = move _2; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
- goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
+ goto -> bb2; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
}
- bb1: {
+ bb2: {
- StorageLive(_6); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
- StorageLive(_7); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
- StorageLive(_8); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
- StorageLive(_9); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
_9 = &mut _4; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
_8 = &mut (*_9); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-- StorageLive(_14); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
- _14 = &mut (*_8); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
- _7 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
+ _7 = <std::ops::Range<i32> as Iterator>::next(move _8) -> bb3; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
// mir::Constant
- // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL
- // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(<ZST>) }
+ // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
+ // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as Iterator>::Item> {<std::ops::Range<i32> as Iterator>::next}, val: Value(<ZST>) }
}
- bb2: {
+ bb3: {
+- StorageDead(_8); // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19
+ _10 = discriminant(_7); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+ switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+ }
+
+ bb4: {
- StorageLive(_12); // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10
_12 = ((_7 as Some).0: i32); // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10
- StorageLive(_13); // scope 3 at $DIR/remove_storage_markers.rs:+3:16: +3:17
- StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
- StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
_5 = const (); // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
- goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
+ goto -> bb2; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
}
- bb3: {
+ bb5: {
+ unreachable; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+ }
+
+ bb6: {
_0 = const (); // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
- StorageDead(_9); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
- StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
- StorageDead(_1); // scope 0 at $DIR/remove_storage_markers.rs:+5:1: +5:2
return; // scope 0 at $DIR/remove_storage_markers.rs:+5:2: +5:2
}
-
- bb4: {
-- StorageDead(_14); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
-- StorageDead(_8); // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19
- _10 = discriminant(_7); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
- switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
- }
-
- bb5 (cleanup): {
- resume; // scope 0 at $DIR/remove_storage_markers.rs:+0:1: +5:2
- }
}
+// unit-test: RemoveStorageMarkers
+
// Checks that storage markers are removed at opt-level=0.
//
// compile-flags: -C opt-level=0 -Coverflow-checks=off
StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:17: +2:2
return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
-- }
--
-- bb2 (cleanup): {
-- resume; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2
}
}
StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
- nop; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:36: +2:2
return; // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
-- }
--
-- bb2 (cleanup): {
-- resume; // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2
}
}
-// compile-flags: -Zmir-opt-level=3
+// unit-test: RemoveZsts
// Ensure RemoveZsts doesn't remove ZST assignments to union fields,
// which causes problems in Miri.
_7 = _2; // scope 3 at $DIR/retag.rs:+3:15: +3:16
_6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> bb1; // scope 3 at $DIR/retag.rs:+3:15: +3:23
// mir::Constant
- // + span: $DIR/retag.rs:60:17: 60:20
+ // + span: $DIR/retag.rs:61:17: 61:20
// + literal: Const { ty: unsafe fn(*mut usize, usize) -> *mut usize {ptr::mut_ptr::<impl *mut usize>::add}, val: Value(<ZST>) }
}
_17 = _9; // scope 6 at $DIR/retag.rs:+7:26: +7:27
_16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> bb2; // scope 6 at $DIR/retag.rs:+7:26: +7:34
// mir::Constant
- // + span: $DIR/retag.rs:64:28: 64:31
+ // + span: $DIR/retag.rs:65:28: 65:31
// + literal: Const { ty: unsafe fn(*const usize, usize) -> *const usize {ptr::const_ptr::<impl *const usize>::add}, val: Value(<ZST>) }
}
Retag([2phase] _6); // scope 1 at $DIR/retag.rs:+3:29: +3:35
_3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:+3:17: +3:36
// mir::Constant
- // + span: $DIR/retag.rs:32:25: 32:28
+ // + span: $DIR/retag.rs:33:25: 33:28
// + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(<ZST>) }
}
StorageLive(_23); // scope 7 at $DIR/retag.rs:+18:21: +18:23
_28 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:+18:21: +18:23
// mir::Constant
- // + span: $DIR/retag.rs:47:21: 47:23
+ // + span: $DIR/retag.rs:48:21: 48:23
// + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
Retag(_28); // scope 7 at $DIR/retag.rs:+18:21: +18:23
_23 = &(*_28); // scope 7 at $DIR/retag.rs:+18:21: +18:23
Retag(_22); // scope 7 at $DIR/retag.rs:+18:21: +18:23
_19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:+18:5: +18:24
// mir::Constant
- // + span: $DIR/retag.rs:47:13: 47:20
+ // + span: $DIR/retag.rs:48:13: 48:20
// + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(<ZST>) }
}
StorageLive(_27); // scope 8 at $DIR/retag.rs:+23:5: +23:18
_27 = array_casts() -> bb6; // scope 8 at $DIR/retag.rs:+23:5: +23:18
// mir::Constant
- // + span: $DIR/retag.rs:52:5: 52:16
+ // + span: $DIR/retag.rs:53:5: 53:16
// + literal: Const { ty: fn() {array_casts}, val: Value(<ZST>) }
}
+// unit-test: AddRetag
// ignore-wasm32-bare compiled with panic=abort by default
// ignore-tidy-linelength
// compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats
-// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo` after SimplifyCfg-elaborate-drops
+// MIR for `<impl at $DIR/retag.rs:12:1: 12:10>::foo` after SimplifyCfg-elaborate-drops
-fn <impl at $DIR/retag.rs:11:1: 11:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32 {
+fn <impl at $DIR/retag.rs:12:1: 12:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32 {
debug self => _1; // in scope 0 at $DIR/retag.rs:+0:16: +0:21
debug x => _2; // in scope 0 at $DIR/retag.rs:+0:23: +0:24
let mut _0: &mut i32; // return place in scope 0 at $DIR/retag.rs:+0:42: +0:53
-// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo_shr` after SimplifyCfg-elaborate-drops
+// MIR for `<impl at $DIR/retag.rs:12:1: 12:10>::foo_shr` after SimplifyCfg-elaborate-drops
-fn <impl at $DIR/retag.rs:11:1: 11:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 {
+fn <impl at $DIR/retag.rs:12:1: 12:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 {
debug self => _1; // in scope 0 at $DIR/retag.rs:+0:20: +0:25
debug x => _2; // in scope 0 at $DIR/retag.rs:+0:27: +0:28
let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:+0:42: +0:49
+// unit-test: SimplifyLocals
// compile-flags: -C overflow-checks=no
fn use_zst(_: ((), ())) {}
// unit-test: SimplifyLocals
-#![feature(box_syntax)]
+
#![feature(thread_local)]
#[derive(Copy, Clone)]
bb4: {
return; // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2
}
-
- bb5 (cleanup): {
- resume; // scope 0 at $DIR/simplify-arm.rs:+0:1: +6:2
- }
}
bb4: {
return; // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2
}
-
- bb5 (cleanup): {
- resume; // scope 0 at $DIR/simplify-arm.rs:+0:1: +6:2
- }
}
- let mut _11: Temp; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+ let _1: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
+ let mut _2: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-+ let _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++ let mut _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
++ let mut _4: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
++ let _5: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++ let mut _6: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
++ let mut _7: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
++ let mut _8: Temp; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
scope 1 {
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
- StorageLive(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23
+- Deinit(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23
- StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27
+- Deinit(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27
+- Deinit(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
+- (_1.0: ()) = move _2; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
+- (_1.1: ()) = move _3; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
- StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28
- StorageDead(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28
- StorageDead(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:28: +1:29
- StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
- StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
- StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
+- Deinit(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
- StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
+- Deinit(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
+- Deinit(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
+- (_5.0: ()) = move _6; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
+- (_5.1: ()) = move _7; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
- StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
- StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
- _4 = use_zst(move _5) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
+ StorageLive(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
+ StorageLive(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++ StorageLive(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
++ Deinit(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
++ StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
++ Deinit(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
++ Deinit(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++ (_2.0: ()) = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++ (_2.1: ()) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++ StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
++ StorageDead(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
+ _1 = use_zst(move _2) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
// mir::Constant
- // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12
+ // + span: $DIR/simplify-locals-removes-unused-consts.rs:15:5: 15:12
// + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) }
}
- StorageLive(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
- StorageLive(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
- StorageLive(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+- Deinit(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+- (_11.0: u8) = const 40_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+- _10 = (_11.0: u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
+- _9 = Add(move _10, const 2_u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
- StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34
-- _8 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
+- _8 = use_u8(move _9) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
+ StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:21: +2:22
+ StorageDead(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:22: +2:23
-+ StorageLive(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
-+ _3 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++ StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++ StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
++ StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
++ StorageLive(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
++ Deinit(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
++ (_8.0: u8) = const 40_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
++ _7 = (_8.0: u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
++ _6 = Add(move _7, const 2_u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
++ StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34
++ _5 = use_u8(move _6) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
// mir::Constant
- // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:11
+ // + span: $DIR/simplify-locals-removes-unused-consts.rs:17:5: 17:11
// + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35
- StorageDead(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
-- StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
-+ StorageDead(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
++ StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35
+ StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
++ StorageDead(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
+ _0 = const (); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+0:11: +5:2
return; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+5:2: +5:2
}
}
// run-pass
-#![feature(backtrace)]
#[derive(Clone, Copy)]
struct Foo {
array: [u64; 10240],
#![crate_type = "lib"]
-pub struct V<S>(S);
+pub struct V<S>(#[allow(unused_tuple_struct_fields)] S);
pub trait An {
type U;
}
#![crate_name = "test"]
-#![feature(box_syntax)]
#![feature(rustc_private)]
extern crate rustc_graphviz;
let x = 32.0f32;
let _ = (x + ((x * x) + 1.0).sqrt()).ln();
- let s: Box<SomeTrait> = box some_fields { field1: 43 };
- let s2: Box<some_fields> = box some_fields { field1: 43 };
- let s3 = box nofields;
+ let s: Box<SomeTrait> = Box::new(some_fields { field1: 43 });
+ let s2: Box<some_fields> = Box::new(some_fields { field1: 43 });
+ let s3 = Box::new(nofields);
s.Method(43);
s3.Method(43);
fn main() {
// foo
- let s = box some_fields { field1: 43 };
+ let s = Box::new(some_fields { field1: 43 });
hello((43, "a".to_string()), *s);
sub::sub2::hello();
sub2::sub3::hello();
let s4: msalias::nested_struct = sub::sub2::nested_struct { field2: 55 };
let s4: msalias::nested_struct = sub2::nested_struct { field2: 55 };
println(&s2.field1.to_string());
- let s5: MyType = box some_fields { field1: 55 };
+ let s5: MyType = Box::new(some_fields { field1: 55 });
let s = SameDir::SameStruct { name: "Bob".to_string() };
let s = SubDir::SubStruct { name: "Bob".to_string() };
- let s6: SomeEnum = SomeEnum::MyTypes(box s2.clone(), s5);
+ let s6: SomeEnum = SomeEnum::MyTypes(Box::new(s2.clone()), s5);
let s7: SomeEnum = SomeEnum::Strings("one", "two", "three");
matchSomeEnum(s6);
matchSomeEnum(s7);
let s8: SomeOtherEnum = SomeOtherEnum::SomeConst2;
matchSomeOtherEnum(s8);
let s9: SomeStructEnum =
- SomeStructEnum::EnumStruct2 { f1: box some_fields { field1: 10 }, f2: box s2 };
+ SomeStructEnum::EnumStruct2 { f1: Box::new(some_fields { field1: 10 }), f2: Box::new(s2) };
matchSomeStructEnum(s9);
for x in &vec![1, 2, 3] {
#![crate_name = "test"]
-#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(associated_type_defaults)]
let x = 32.0f32;
let _ = (x + ((x * x) + 1.0).sqrt()).ln();
- let s: Box<SomeTrait> = box some_fields { field1: 43 };
- let s2: Box<some_fields> = box some_fields { field1: 43 };
- let s3 = box nofields;
+ let s: Box<SomeTrait> = Box::new(some_fields { field1: 43 });
+ let s2: Box<some_fields> = Box::new(some_fields { field1: 43 });
+ let s3 = Box::new(nofields);
s.Method(43);
s3.Method(43);
fn main() {
// foo
- let s = box some_fields { field1: 43 };
+ let s = Box::new(some_fields { field1: 43 });
hello((43, "a".to_string()), *s);
sub::sub2::hello();
sub2::sub3::hello();
let s4: msalias::nested_struct = sub::sub2::nested_struct { field2: 55 };
let s4: msalias::nested_struct = sub2::nested_struct { field2: 55 };
println(&s2.field1.to_string());
- let s5: MyType = box some_fields { field1: 55 };
+ let s5: MyType = Box::new(some_fields { field1: 55 });
let s = SameDir::SameStruct { name: "Bob".to_string() };
let s = SubDir::SubStruct { name: "Bob".to_string() };
- let s6: SomeEnum = SomeEnum::MyTypes(box s2.clone(), s5);
+ let s6: SomeEnum = SomeEnum::MyTypes(Box::new(s2.clone()), s5);
let s7: SomeEnum = SomeEnum::Strings("one", "two", "three");
matchSomeEnum(s6);
matchSomeEnum(s7);
let s8: SomeOtherEnum = SomeOtherEnum::SomeConst2;
matchSomeOtherEnum(s8);
let s9: SomeStructEnum =
- SomeStructEnum::EnumStruct2 { f1: box some_fields { field1: 10 }, f2: box s2 };
+ SomeStructEnum::EnumStruct2 { f1: Box::new(some_fields { field1: 10 }), f2: Box::new(s2) };
matchSomeStructEnum(s9);
for x in &vec![1, 2, 3] {
CHECK: @__llvm_coverage_mapping = private constant
CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8
-WINDOWS: @__llvm_profile_runtime = external global i32
+WINDOWS: @__llvm_profile_runtime = external{{.*}}global i32
CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
# ignore-cross-compile -- compiling C++ code does not work well when cross-compiling
-# This test case makes sure that native libraries are linked with --whole-archive semantics
-# when the `-bundle,+whole-archive` modifiers are applied to them.
+# This test case makes sure that native libraries are linked with appropriate semantics
+# when the `[+-]bundle,[+-]whole-archive` modifiers are applied to them.
#
# The test works by checking that the resulting executables produce the expected output,
# part of which is emitted by otherwise unreferenced C code. If +whole-archive didn't work
-include ../../run-make-fulldeps/tools.mk
-all: $(TMPDIR)/$(call BIN,directly_linked) $(TMPDIR)/$(call BIN,indirectly_linked) $(TMPDIR)/$(call BIN,indirectly_linked_via_attr)
+all: $(TMPDIR)/$(call BIN,directly_linked) \
+ $(TMPDIR)/$(call BIN,directly_linked_test_plus_whole_archive) \
+ $(TMPDIR)/$(call BIN,directly_linked_test_minus_whole_archive) \
+ $(TMPDIR)/$(call BIN,indirectly_linked) \
+ $(TMPDIR)/$(call BIN,indirectly_linked_via_attr)
$(call RUN,directly_linked) | $(CGREP) 'static-initializer.directly_linked.'
+ $(call RUN,directly_linked_test_plus_whole_archive) --nocapture | $(CGREP) 'static-initializer.'
+ $(call RUN,directly_linked_test_minus_whole_archive) --nocapture | $(CGREP) -v 'static-initializer.'
$(call RUN,indirectly_linked) | $(CGREP) 'static-initializer.indirectly_linked.'
$(call RUN,indirectly_linked_via_attr) | $(CGREP) 'static-initializer.native_lib_in_src.'
$(TMPDIR)/$(call BIN,directly_linked): $(call NATIVE_STATICLIB,c_static_lib_with_constructor)
$(RUSTC) directly_linked.rs -l static:+whole-archive=c_static_lib_with_constructor
+# Native lib linked into test executable, +whole-archive
+$(TMPDIR)/$(call BIN,directly_linked_test_plus_whole_archive): $(call NATIVE_STATICLIB,c_static_lib_with_constructor)
+ $(RUSTC) directly_linked_test_plus_whole_archive.rs --test -l static:+whole-archive=c_static_lib_with_constructor
+# Native lib linked into test executable, -whole-archive
+$(TMPDIR)/$(call BIN,directly_linked_test_minus_whole_archive): $(call NATIVE_STATICLIB,c_static_lib_with_constructor)
+ $(RUSTC) directly_linked_test_minus_whole_archive.rs --test -l static:-whole-archive=c_static_lib_with_constructor
+
# Native lib linked into RLIB via `-l static:-bundle,+whole-archive`, RLIB linked into executable
$(TMPDIR)/$(call BIN,indirectly_linked): $(TMPDIR)/librlib_with_cmdline_native_lib.rlib
$(RUSTC) indirectly_linked.rs
--- /dev/null
+use std::io::Write;
+
+#[test]
+fn test_thing() {
+ print!("ran the test");
+ std::io::stdout().flush().unwrap();
+}
--- /dev/null
+use std::io::Write;
+
+#[test]
+fn test_thing() {
+ print!("ran the test");
+ std::io::stdout().flush().unwrap();
+}
else
$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
endif
- "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
+ "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
ifdef RUSTC_BLESS_TEST
cp "$(TMPDIR)"/output.txt output.txt
else
$(DIFF) output.txt "$(TMPDIR)"/output.txt
endif
+
+ifdef IS_MSVC
+ "$(TMPDIR)"/driver true > "$(TMPDIR)"/output.msvc.txt
+ifdef RUSTC_BLESS_TEST
+ cp "$(TMPDIR)"/output.msvc.txt output.msvc.txt
+else
+ $(DIFF) output.msvc.txt "$(TMPDIR)"/output.msvc.txt
+endif
+endif
extern crate raw_dylib_alt_calling_convention_test;
fn main() {
- raw_dylib_alt_calling_convention_test::library_function();
+ raw_dylib_alt_calling_convention_test::library_function(
+ std::env::args().skip(1).next().map_or(
+ false,
+ |s| std::str::FromStr::from_str(&s).unwrap()));
}
printf("fastcall_fn_9(%d, %.1f)\n", x, y);
fflush(stdout);
}
+
+// GCC doesn't support vectorcall: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
+#ifdef _MSC_VER
+__declspec(dllexport) void __vectorcall vectorcall_fn_1(int i) {
+ printf("vectorcall_fn_1(%d)\n", i);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_2(uint8_t i, float f) {
+ printf("vectorcall_fn_2(%d, %.1f)\n", i, f);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_3(double d) {
+ printf("vectorcall_fn_3(%.1f)\n", d);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_4(uint8_t i, uint8_t j, float f) {
+ printf("vectorcall_fn_4(%d, %d, %.1f)\n", i, j, f);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_5(struct S s, int i) {
+ printf("vectorcall_fn_5(S { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_6(struct S* s) {
+ if (s) {
+ printf("vectorcall_fn_6(S { x: %d, y: %d })\n", s->x, s->y);
+ } else {
+ printf("vectorcall_fn_6(null)\n");
+ }
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_7(struct S2 s, int i) {
+ printf("vectorcall_fn_7(S2 { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_8(struct S3 s, struct S3 t) {
+ printf("vectorcall_fn_8(S3 { x: [%d, %d, %d, %d, %d] }, S3 { x: [%d, %d, %d, %d, %d] })\n",
+ s.x[0], s.x[1], s.x[2], s.x[3], s.x[4],
+ t.x[0], t.x[1], t.x[2], t.x[3], t.x[4]
+ );
+ fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_9(uint8_t x, double y) {
+ printf("vectorcall_fn_9(%d, %.1f)\n", x, y);
+ fflush(stdout);
+}
+#endif
#![feature(raw_dylib)]
+#![feature(abi_vectorcall)]
#[repr(C)]
#[derive(Clone)]
fn fastcall_fn_9(x: u8, y: f64);
}
-pub fn library_function() {
+#[cfg(target_env = "msvc")]
+#[link(name = "extern", kind = "raw-dylib")]
+extern "vectorcall" {
+ fn vectorcall_fn_1(i: i32);
+ fn vectorcall_fn_2(c: u8, f: f32);
+ fn vectorcall_fn_3(d: f64);
+ fn vectorcall_fn_4(i: u8, j: u8, f: f32);
+ fn vectorcall_fn_5(a: S, b: i32);
+ fn vectorcall_fn_6(a: Option<&S>);
+ fn vectorcall_fn_7(a: S2, b: i32);
+ fn vectorcall_fn_8(a: S3, b: S3);
+ fn vectorcall_fn_9(x: u8, y: f64);
+}
+
+pub fn library_function(run_msvc_only: bool) {
unsafe {
- stdcall_fn_1(14);
- stdcall_fn_2(16, 3.5);
- stdcall_fn_3(3.5);
- stdcall_fn_4(1, 2, 3.0);
- stdcall_fn_5(S { x: 1, y: 2 }, 16);
- stdcall_fn_6(Some(&S { x: 10, y: 12 }));
- stdcall_fn_7(S2 { x: 15, y: 16 }, 3);
- stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
- stdcall_fn_9(1, 3.0);
+ if !run_msvc_only {
+ stdcall_fn_1(14);
+ stdcall_fn_2(16, 3.5);
+ stdcall_fn_3(3.5);
+ stdcall_fn_4(1, 2, 3.0);
+ stdcall_fn_5(S { x: 1, y: 2 }, 16);
+ stdcall_fn_6(Some(&S { x: 10, y: 12 }));
+ stdcall_fn_7(S2 { x: 15, y: 16 }, 3);
+ stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+ stdcall_fn_9(1, 3.0);
+
+ fastcall_fn_1(14);
+ fastcall_fn_2(16, 3.5);
+ fastcall_fn_3(3.5);
+ fastcall_fn_4(1, 2, 3.0);
+ fastcall_fn_6(Some(&S { x: 10, y: 12 }));
+ fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+ fastcall_fn_9(1, 3.0);
+ } else {
+ // FIXME: 91167
+ // rustc generates incorrect code for the calls to fastcall_fn_5 and fastcall_fn_7
+ // on i686-pc-windows-gnu; disabling these until the indicated issue is fixed.
+ fastcall_fn_5(S { x: 1, y: 2 }, 16);
+ fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
- fastcall_fn_1(14);
- fastcall_fn_2(16, 3.5);
- fastcall_fn_3(3.5);
- fastcall_fn_4(1, 2, 3.0);
- // FIXME: 91167
- // rustc generates incorrect code for the calls to fastcall_fn_5 and fastcall_fn_7
- // on i686-pc-windows-gnu; commenting these out until the indicated issue is fixed.
- //fastcall_fn_5(S { x: 1, y: 2 }, 16);
- fastcall_fn_6(Some(&S { x: 10, y: 12 }));
- //fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
- fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
- fastcall_fn_9(1, 3.0);
+ // GCC doesn't support vectorcall: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
+ #[cfg(target_env = "msvc")]
+ {
+ vectorcall_fn_1(14);
+ vectorcall_fn_2(16, 3.5);
+ vectorcall_fn_3(3.5);
+ vectorcall_fn_4(1, 2, 3.0);
+ vectorcall_fn_5(S { x: 1, y: 2 }, 16);
+ vectorcall_fn_6(Some(&S { x: 10, y: 12 }));
+ vectorcall_fn_7(S2 { x: 15, y: 16 }, 3);
+ vectorcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+ vectorcall_fn_9(1, 3.0);
+ }
+ }
}
}
--- /dev/null
+fastcall_fn_5(S { x: 1, y: 2 }, 16)
+fastcall_fn_7(S2 { x: 15, y: 16 }, 3)
+vectorcall_fn_1(14)
+vectorcall_fn_2(16, 3.5)
+vectorcall_fn_3(3.5)
+vectorcall_fn_4(1, 2, 3.0)
+vectorcall_fn_5(S { x: 1, y: 2 }, 16)
+vectorcall_fn_6(S { x: 10, y: 12 })
+vectorcall_fn_7(S2 { x: 15, y: 16 }, 3)
+vectorcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
+vectorcall_fn_9(1, 3.0)
#include <stdio.h>
+__declspec(dllexport) int extern_variable = 0;
+
__declspec(dllexport) void extern_fn_1() {
printf("extern_fn_1\n");
fflush(stdout);
fflush(stdout);
}
+__declspec(dllexport) void print_extern_variable() {
+ printf("extern_variable value: %d\n", extern_variable);
+ fflush(stdout);
+}
+
__declspec(dllexport) void extern_fn_with_long_name() {
printf("extern_fn_with_long_name; got the rename\n");
fflush(stdout);
pub fn library_function() {
#[link(name = "extern_1", kind = "raw-dylib")]
- extern { fn extern_fn_2(); }
+ extern {
+ fn extern_fn_2();
+ fn print_extern_variable();
+ static mut extern_variable: i32;
+ }
unsafe {
extern_fn_1();
extern_fn_2();
extern_fn_3();
+ extern_variable = 42;
+ print_extern_variable();
+ extern_variable = -42;
+ print_extern_variable();
}
}
extern_fn_1
extern_fn_2; didn't get the rename
extern_fn_3
+extern_variable value: 42
+extern_variable value: -42
void exported_function() {
printf("exported_function\n");
}
+
+int exported_variable = 0;
+
+void print_exported_variable() {
+ printf("exported_variable value: %d\n", exported_variable);
+ fflush(stdout);
+}
LIBRARY exporter
EXPORTS
exported_function @13 NONAME
+ exported_variable @5 NONAME
+ print_exported_variable @9 NONAME
extern {
#[link_ordinal(13)]
fn imported_function();
+ #[link_ordinal(5)]
+ static mut imported_variable: i32;
+ #[link_ordinal(9)]
+ fn print_imported_variable();
}
pub fn library_function() {
unsafe {
imported_function();
+ imported_variable = 42;
+ print_imported_variable();
+ imported_variable = -42;
+ print_imported_variable();
}
}
exported_function
+exported_variable value: 42
+exported_variable value: -42
// schedule cleanups when auto borrowing trait objects.
// This program should be valgrind clean.
-#![feature(box_syntax)]
-
static mut DROP_RAN: bool = false;
struct Foo;
pub fn main() {
{
- let _x: &Trait = &*(box Foo as Box<Trait>);
+ let _x: &Trait = &*(Box::new(Foo) as Box<Trait>);
}
unsafe {
assert!(DROP_RAN);
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub fn main() {
- let _: Box<[isize]> =
- if true { let b: Box<_> = box [1, 2, 3]; b } else { let b: Box<_> = box [1]; b };
+ let _: Box<[isize]> = if true {
+ let b: Box<_> = Box::new([1, 2, 3]);
+ b
+ } else {
+ let b: Box<_> = Box::new([1]);
+ b
+ };
let _: Box<[isize]> = match true {
- true => { let b: Box<_> = box [1, 2, 3]; b }
- false => { let b: Box<_> = box [1]; b }
+ true => { let b: Box<_> = Box::new([1, 2, 3]); b }
+ false => { let b: Box<_> = Box::new([1]); b }
};
// Check we don't get over-keen at propagating coercions in the case of casts.
+++ /dev/null
-// This test ensures that the item information don't take 100% of the width if unnecessary.
-goto: file://|DOC_PATH|/lib2/struct.Foo.html
-// We set a fixed size so there is no chance of "random" resize.
-size: (1100, 800)
-// We check that ".item-info" is bigger than its content.
-assert-css: (".item-info", {"width": "790px"})
-assert-css: (".item-info .stab", {"width": "289px"})
-assert-position: (".item-info .stab", {"x": 295})
--- /dev/null
+// This test ensures a few things for item info elements.
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
+// Ensuring that the item information don't take 100% of the width if unnecessary.
+// We set a fixed size so there is no chance of "random" resize.
+size: (1100, 800)
+// We check that ".item-info" is bigger than its content.
+assert-css: (".item-info", {"width": "790px"})
+assert-css: (".item-info .stab", {"width": "289px"})
+assert-position: (".item-info .stab", {"x": 295})
+
+// Now we ensure that they're not rendered on the same line.
+goto: file://|DOC_PATH|/lib2/trait.Trait.html
+// We first ensure that there are two item info on the trait.
+assert-count: ("#main-content > .item-info .stab", 2)
+// They should not have the same `y` position!
+compare-elements-position-false: (
+ "#main-content > .item-info .stab:nth-of-type(1)",
+ "#main-content > .item-info .stab:nth-of-type(2)",
+ ("y"),
+)
+// But they should have the same `x` position.
+compare-elements-position: (
+ "#main-content > .item-info .stab:nth-of-type(1)",
+ "#main-content > .item-info .stab:nth-of-type(2)",
+ ("x"),
+)
+// They are supposed to have the same height too.
+compare-elements-css: (
+ "#main-content > .item-info .stab:nth-of-type(1)",
+ "#main-content > .item-info .stab:nth-of-type(2)",
+ ["height"],
+)
assert: (".stab.deprecated")
assert: (".stab.portability")
-// make sure that deprecated and portability are different colours
+// make sure that deprecated and portability have the right colors
assert-css: (
".item-table .item-left .stab.deprecated",
- { "background-color": "rgb(255, 196, 196)" },
+ { "background-color": "rgb(255, 245, 214)" },
)
assert-css: (
".item-table .item-left .stab.portability",
- { "background-color": "rgb(243, 223, 255)" },
+ { "background-color": "rgb(255, 245, 214)" },
)
// table like view
compare-elements-position-near: (
"//*[@class='item-left module-item']//a[text()='replaced_function']",
".item-left .stab.deprecated",
- {"y": 1},
+ {"y": 2},
)
compare-elements-position: (
".item-left .stab.deprecated",
click: "#help-button"
assert-css: (
"#help-button .popover",
- {"display": "block", "border-color": "rgb(221, 221, 221)"},
+ {"display": "block", "border-color": "rgb(224, 224, 224)"},
)
compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
press-key: "Enter"
// Waiting for the search results to appear...
wait-for: "#titles"
-assert-property: ("#crate-search", {"value": "All crates"})
+assert-property: ("#crate-search", {"value": "all crates"})
// Checking that the URL parameter is taken into account for crate filtering.
goto: file://|DOC_PATH|/test_docs/index.html?search=test&filter-crate=lib2
assert-property: ("#crate-search", {"value": "lib2"})
assert-false: "#results .externcrate"
-// Checking that the text for the "title" is correct (the "All" comes from the "<select>").
-assert-text: ("#search-settings", "Results for test in All", STARTS_WITH)
+// Checking that the text for the "title" is correct (the "all crates" comes from the "<select>").
+assert-text: (".search-results-title", "Results in all crates", STARTS_WITH)
// Checking the display of the crate filter.
// We start with the light theme.
wait-for: "#settings"
click: "#theme-dark"
wait-for-css: ("#crate-search", {
- "border": "1px solid rgb(240, 240, 240)",
- "color": "rgb(17, 17, 17)",
- "background-color": "rgb(240, 240, 240)",
+ "border": "1px solid rgb(210, 210, 210)",
+ "color": "rgb(221, 221, 221)",
+ "background-color": "rgb(53, 53, 53)",
})
// And finally we check the ayu theme.
click: "#theme-ayu"
wait-for-css: ("#crate-search", {
- "border": "1px solid rgb(66, 76, 87)",
- "color": "rgb(197, 197, 197)",
- "background-color": "rgb(20, 25, 32)",
+ "border": "1px solid rgb(92, 103, 115)",
+ "color": "rgb(255, 255, 255)",
+ "background-color": "rgb(15, 20, 25)",
})
write: (".search-input", "test")
// To be SURE that the search will be run.
press-key: 'Enter'
-wait-for: "#search-settings"
+wait-for: "#crate-search"
// The width is returned by "getComputedStyle" which returns the exact number instead of the
// CSS rule which is "50%"...
assert-css: (".search-results div.desc", {"width": "295px"})
// To do so we need to update the length of one of its `<option>`.
size: (900, 900)
-// First we check the current width and position.
-assert-css: ("#crate-search", {"width": "218px"})
-compare-elements-position-near: (
- "#crate-search",
- "#search-settings .search-results-title",
- {"y": 5},
-)
+// First we check the current width, height and position.
+assert-css: ("#crate-search", {"width": "223px"})
+assert-css: (".search-results-title", {"height": "44px", "width": "336px"})
// Then we update the text of one of the `<option>`.
text: (
"sdjfaksdjfaksjdbfkadsbfkjsadbfkdsbkfbsadkjfbkdsabfkadsfkjdsafa",
)
-// Then we compare again.
-assert-css: ("#crate-search", {"width": "640px"})
-compare-elements-position-near-false: (
- "#crate-search",
- "#search-settings .search-results-title",
- {"y": 5},
-)
-// And we check that the `<select>` isn't bigger than its container.
+// Then we compare again to confirm the height didn't change.
+assert-css: ("#crate-search", {"width": "527px"})
+assert-css: (".search-results-title", {"height": "44px", "width": "640px"})
+// And we check that the `<select>` isn't bigger than its container (".search-results-title").
assert-css: ("#search", {"width": "640px"})
--- /dev/null
+// This test ensures that the mobile sidebar preserves scroll position.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+// Switching to "mobile view" by reducing the width to 600px.
+size: (600, 600)
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+
+// Scroll down.
+scroll-to: "//h2[@id='blanket-implementations']"
+assert-window-property: {"pageYOffset": "702"}
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+wait-for-css: (".sidebar", {"left": "0px"})
+
+// We are no longer "scrolled". It's important that the user can't
+// scroll the body at all, but these test scripts are run only in Chrome,
+// and we need to use a more complicated solution to this problem because
+// of Mobile Safari...
+assert-window-property: {"pageYOffset": "0"}
+
+// Close the sidebar menu. Make sure the scroll position gets restored.
+click: ".sidebar-menu-toggle"
+wait-for-css: (".sidebar", {"left": "-1000px"})
+assert-window-property: {"pageYOffset": "702"}
+
+// Now test that scrollability returns when the browser window is just resized.
+click: ".sidebar-menu-toggle"
+wait-for-css: (".sidebar", {"left": "0px"})
+assert-window-property: {"pageYOffset": "0"}
+size: (900, 900)
+assert-window-property: {"pageYOffset": "702"}
// The "scrollTop" property should be the same.
assert-window-property: {"pageYOffset": "2519"}
+// We now check that the scroll position is restored if the window is resized.
+size: (500, 700)
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "visible"})
+assert-window-property: {"pageYOffset": "0"}
+size: (900, 900)
+assert-window-property: {"pageYOffset": "2519"}
+size: (500, 700)
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
+
// We now check that opening the sidebar and clicking a link will close it.
// The behavior here on mobile is different than the behavior on desktop,
// but common sense dictates that if you have a list of files that fills the entire screen, and
pub fn a_method(&self) {}
}
+#[doc(cfg(feature = "foo-method"))]
+#[deprecated = "Whatever [`Foo::a_method`](#method.a_method)"]
pub trait Trait {
type X;
const Y: u32;
+ #[deprecated = "Whatever [`Foo`](#tadam)"]
fn foo() {}
}
// @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=='ilog10')]"
+// @!is - "$.index[*][?(@.name=='ilog10')].crate_id" $local_crate_id
// @has - "$.index[*][?(@.name=='checked_add')]"
// @!is - "$.index[*][?(@.name=='checked_add')]" $local_crate_id
// @!has - "$.index[*][?(@.name=='is_ascii_uppercase')]"
+
+// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='my_i32')].inner.id" null
+pub use i32 as my_i32;
+
+// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='u32')].inner.id" null
+pub use u32;
// ignore-tidy-linelength
+use std::fmt::Debug;
-// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1
+// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 3
// @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id"
-// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen
+// @set ref_fn = - "$.index[*][?(@.name=='RefFn')].id"
+// @set weird_order = - "$.index[*][?(@.name=='WeirdOrder')].id"
+// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen
+// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $ref_fn
+// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $weird_order
// @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}'
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" []
// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1
-// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
-// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
-// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\"
-// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3
-// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\"
-// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\"
-// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}"
-// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"dyn_trait\"
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.lifetime" \"\'static\"
+// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[*]" 3
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].generic_params" []
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].generic_params" []
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].generic_params" []
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Fn"'
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Send"'
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].trait.inner.name" '"Sync"'
+// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>;
+
+// @is - "$.index[*][?(@.name=='RefFn')].kind" \"typedef\"
+// @is - "$.index[*][?(@.name=='RefFn')].inner.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.mutable" 'false'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.lifetime" "\"'a\""
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"dyn_trait"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.lifetime" null
+// @count - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[*]" 1
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.kind" '"resolved_path"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.name" '"Fn"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\""
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.inner.lifetime" "\"'b\""
+pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32;
+
+// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Send"'
+// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Debug"'
+pub type WeirdOrder = Box<dyn Send + Debug>;
--- /dev/null
+// ignore-tidy-linelength
+
+// @has hrtb.json
+
+// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F","kind": "generic"}'
+// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
+pub fn genfn<F>(f: F)
+where
+ for<'a, 'b> F: Fn(&'a i32, &'b i32),
+{
+ let zero = 0;
+ f(&zero, &zero);
+}
+
+// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"dyn_trait"'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.lifetime" null
+// @count - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[*]" 1
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
+// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].trait.inner.name" '"Fn"'
+pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) {
+ let zero = 0;
+ f(&zero, &zero);
+}
-error: `#[doc(alias = "...")]` isn't allowed on extern block
+error: `#[doc(alias = "...")]` isn't allowed on foreign module
--> $DIR/check-doc-alias-attr-location.rs:7:7
|
LL | #[doc(alias = "foo")]
-#![feature(box_syntax)]
-#![feature(box_syntax)] //~ ERROR
+#![feature(rustdoc_internals)]
+#![feature(rustdoc_internals)] //~ ERROR
pub fn foo() {}
-error[E0636]: the feature `box_syntax` has already been declared
+error[E0636]: the feature `rustdoc_internals` has already been declared
--> $DIR/rustc-check-passes.rs:2:12
|
-LL | #![feature(box_syntax)]
- | ^^^^^^^^^^
+LL | #![feature(rustdoc_internals)]
+ | ^^^^^^^^^^^^^^^^^
error: aborting due to previous error
--- /dev/null
+// check-fail
+// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar
+
+pub fn foo() {
+ INVALID_FUNC();
+ //~^ ERROR could not resolve path
+}
--- /dev/null
+error[E0433]: failed to resolve: could not resolve path `INVALID_FUNC`
+ --> $DIR/scrape-examples-fail-if-type-error.rs:5:3
+ |
+LL | INVALID_FUNC();
+ | ^^^^^^^^^^^^ could not resolve path `INVALID_FUNC`
+ |
+ = note: this error was originally ignored because you are running `rustdoc`
+ = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
--- /dev/null
+#![crate_name="first"]
+
+pub mod prelude {
+ pub use crate::Bot;
+}
+
+pub struct Bot;
+
+impl Bot {
+ pub fn new() -> Bot {
+ Bot
+ }
+}
--- /dev/null
+pub struct Option;
+impl Option {
+ pub fn unwrap(self) {}
+}
+
+/// [`Option::unwrap`]
+pub mod task {}
+
+extern "C" {
+ pub fn main() -> std::ffi::c_int;
+}
--- /dev/null
+// compile-flags: --document-private-items
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+pub struct Foo;
+
+// There are 3 impl blocks with public item and one that should not be displayed
+// by default because it only contains private items (but not in this case because
+// we used `--document-private-items`).
+// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4
+
+// Impl block only containing private items should not be displayed unless the
+// `--document-private-items` flag is used.
+/// Private
+impl Foo {
+ const BAR: u32 = 0;
+ type FOO = i32;
+ fn hello() {}
+}
+
+// But if any element of the impl block is public, it should be displayed.
+/// Not private
+impl Foo {
+ pub const BAR: u32 = 0;
+ type FOO = i32;
+ fn hello() {}
+}
+
+/// Not private
+impl Foo {
+ const BAR: u32 = 0;
+ pub type FOO = i32;
+ fn hello() {}
+}
+
+/// Not private
+impl Foo {
+ const BAR: u32 = 0;
+ type FOO = i32;
+ pub fn hello() {}
+}
--- /dev/null
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+pub struct Foo;
+
+// There are 3 impl blocks with public item and one that should not be displayed
+// because it only contains private items.
+// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3
+
+// Impl block only containing private items should not be displayed.
+/// Private
+impl Foo {
+ const BAR: u32 = 0;
+ type FOO = i32;
+ fn hello() {}
+}
+
+// But if any element of the impl block is public, it should be displayed.
+/// Not private
+impl Foo {
+ pub const BAR: u32 = 0;
+ type FOO = i32;
+ fn hello() {}
+}
+
+/// Not private
+impl Foo {
+ const BAR: u32 = 0;
+ pub type FOO = i32;
+ fn hello() {}
+}
+
+/// Not private
+impl Foo {
+ const BAR: u32 = 0;
+ type FOO = i32;
+ pub fn hello() {}
+}
--- /dev/null
+// Regression test for #100143
+
+use std::iter::Peekable;
+
+pub struct Span<F: Fn(&i32)> {
+ inner: Peekable<ConditionalIterator<F>>,
+}
+
+pub struct ConditionalIterator<F> {
+ f: F,
+}
+
+
+// @has 'fn_bound/struct.ConditionalIterator.html' '//h3[@class="code-header in-band"]' 'impl<F: Fn(&i32)> Iterator for ConditionalIterator<F>'
+impl<F: Fn(&i32)> Iterator for ConditionalIterator<F> {
+ type Item = ();
+
+ fn next(&mut self) -> Option<Self::Item> {
+ todo!()
+ }
+}
--- /dev/null
+#![crate_name = "foo"]
+
+// Check that default trait items that are impossible to satisfy
+
+pub trait Foo {
+ fn needs_sized(&self)
+ where
+ Self: Sized,
+ {}
+
+ fn no_needs_sized(&self) {}
+}
+
+// @!has foo/struct.Bar.html '//*[@id="method.needs_sized"]//h4[@class="code-header"]' \
+// "fn needs_sized"
+// @has foo/struct.Bar.html '//*[@id="method.no_needs_sized"]//h4[@class="code-header"]' \
+// "fn no_needs_sized"
+pub struct Bar([u8]);
+
+impl Foo for Bar {}
--- /dev/null
+// Regression test for #93205
+
+#![crate_name = "foo"]
+
+mod generated {
+ pub struct MyNewType;
+ impl MyNewType {
+ pub const FOO: Self = Self;
+ }
+}
+
+pub use generated::MyNewType;
+
+mod prelude {
+ impl super::MyNewType {
+ /// An alias for [`Self::FOO`].
+ // @has 'foo/struct.MyNewType.html' '//a[@href="struct.MyNewType.html#associatedconstant.FOO"]' 'Self::FOO'
+ pub const FOO2: Self = Self::FOO;
+ }
+}
--- /dev/null
+// aux-build:issue-100204-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name="second"]
+
+extern crate first;
+
+pub mod prelude {}
+
+// @has first/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
+// @has second/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
+#[doc(inline)]
+pub use first::*;
--- /dev/null
+// aux-build:issue-99734-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99734_aux;
+
+pub use issue_99734_aux::*;
+
+// @count foo/index.html '//a[@class="fn"][@title="foo::main fn"]' 1
+
+extern "C" {
+ pub fn main() -> std::ffi::c_int;
+}
--- /dev/null
+// aux-build:issue-99734-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99734_aux;
+
+pub use issue_99734_aux::*;
+
+// @count foo/index.html '//a[@class="mod"][@title="foo::task mod"]' 1
+
+pub mod task {}
2 => {
let seg = PathSegment::from_ident(Ident::from_str("x"));
iter_exprs(depth - 1, &mut |e| {
- g(ExprKind::MethodCall(seg.clone(), vec![e, make_x()], DUMMY_SP))
+ g(ExprKind::MethodCall(seg.clone(), e, vec![make_x()], DUMMY_SP))
});
iter_exprs(depth - 1, &mut |e| {
- g(ExprKind::MethodCall(seg.clone(), vec![make_x(), e], DUMMY_SP))
+ g(ExprKind::MethodCall(seg.clone(), make_x(), vec![e], DUMMY_SP))
});
}
3..=8 => {
#![feature(repr_align)]
#[repr(align(16))]
-pub struct A(i64);
+pub struct A(#[allow(unused_tuple_struct_fields)] i64);
#[allow(improper_ctypes_definitions)]
pub extern "C" fn foo(x: A) {}
extern fn rust_eh_personality() {}
#[derive(Debug)]
-struct Page([[u64; 32]; 16]);
+struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
#[start]
pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
extern fn rust_eh_personality() {}
#[derive(Debug)]
-struct Page([[u64; 32]; 16]);
+struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
#[start]
pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
--- /dev/null
+fn foo(i: impl std::fmt::Display) {}
+
+fn main() {
+ foo::<()>(());
+ //~^ ERROR this function takes 0 generic arguments but 1 generic argument was supplied
+ //~| ERROR `()` doesn't implement `std::fmt::Display`
+}
--- /dev/null
+error[E0107]: this function takes 0 generic arguments but 1 generic argument was supplied
+ --> $DIR/issue-100154.rs:4:5
+ |
+LL | foo::<()>(());
+ | ^^^------ help: remove these generics
+ | |
+ | expected 0 generic arguments
+ |
+note: function defined here, with 0 generic parameters
+ --> $DIR/issue-100154.rs:1:4
+ |
+LL | fn foo(i: impl std::fmt::Display) {}
+ | ^^^
+ = note: `impl Trait` cannot be explicitly specified as a generic argument
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+ --> $DIR/issue-100154.rs:4:15
+ |
+LL | foo::<()>(());
+ | --------- ^^ `()` cannot be formatted with the default formatter
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `()`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `foo`
+ --> $DIR/issue-100154.rs:1:16
+ |
+LL | fn foo(i: impl std::fmt::Display) {}
+ | ^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0107, E0277.
+For more information about an error, try `rustc --explain E0107`.
// run-pass
#[derive(Debug)]
-struct Foo(Box<[u8]>);
+struct Foo(#[allow(unused_tuple_struct_fields)] Box<[u8]>);
pub fn main() {
println!("{:?}", Foo(Box::new([0, 1, 2])));
| |
| generic outputs
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+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`, `may_unwind`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
+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`, `may_unwind`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
+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`, `may_unwind`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
+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`, `may_unwind`, or `raw`
+ | ^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
+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`, `may_unwind`, or `raw`
+ | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
+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`, `may_unwind`, or `raw`
+ | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: invalid ABI for `clobber_abi`
--> $DIR/bad-options.rs:20:18
LL | global_asm!("{}", const(reg) FOO);
| ^^^ expected one of `,`, `.`, `?`, or an operator
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
+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`, `may_unwind`, or `raw`
+ | ^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+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`, `may_unwind`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+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`, `may_unwind`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: arguments are not allowed after options
--> $DIR/parse-error.rs:108:30
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:33:1
|
-LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
-LL | |
-LL | | a + 1
- | | ----- non-asm is unsupported in naked functions
-LL | |
-LL | | }
- | |_^
+LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | a + 1
+ | ----- non-asm is unsupported in naked functions
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:42:31
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:48:1
|
-LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
-LL | |
-LL | | (|| a + 1)()
- | | ------------ non-asm is unsupported in naked functions
-LL | | }
- | |_^
+LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | (|| a + 1)()
+ | ------------ non-asm is unsupported in naked functions
error[E0787]: only `const` and `sym` operands are supported in naked functions
--> $DIR/naked-functions.rs:65:10
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:54:1
|
-LL | / pub unsafe extern "C" fn unsupported_operands() {
-LL | |
-LL | | let mut a = 0usize;
- | | ------------------- non-asm is unsupported in naked functions
-LL | | let mut b = 0usize;
- | | ------------------- non-asm is unsupported in naked functions
-LL | | let mut c = 0usize;
- | | ------------------- non-asm is unsupported in naked functions
-LL | | let mut d = 0usize;
- | | ------------------- non-asm is unsupported in naked functions
-LL | | let mut e = 0usize;
- | | ------------------- non-asm is unsupported in naked functions
-... |
-LL | | );
-LL | | }
- | |_^
+LL | pub unsafe extern "C" fn unsupported_operands() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | let mut a = 0usize;
+ | ------------------- non-asm is unsupported in naked functions
+LL | let mut b = 0usize;
+ | ------------------- non-asm is unsupported in naked functions
+LL | let mut c = 0usize;
+ | ------------------- non-asm is unsupported in naked functions
+LL | let mut d = 0usize;
+ | ------------------- non-asm is unsupported in naked functions
+LL | let mut e = 0usize;
+ | ------------------- non-asm is unsupported in naked functions
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:77:1
|
-LL | / pub extern "C" fn missing_assembly() {
-LL | |
-LL | | }
- | |_^
+LL | pub extern "C" fn missing_assembly() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0787]: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:84:5
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:82:1
|
-LL | / pub extern "C" fn too_many_asm_blocks() {
-LL | |
-LL | | asm!("");
-LL | |
-LL | | asm!("");
- | | -------- multiple asm blocks are unsupported in naked functions
-LL | |
-LL | | asm!("");
- | | -------- multiple asm blocks are unsupported in naked functions
-LL | |
-LL | | asm!("", options(noreturn));
- | | --------------------------- multiple asm blocks are unsupported in naked functions
-LL | | }
- | |_^
+LL | pub extern "C" fn too_many_asm_blocks() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | asm!("");
+ | -------- multiple asm blocks are unsupported in naked functions
+LL |
+LL | asm!("");
+ | -------- multiple asm blocks are unsupported in naked functions
+LL |
+LL | asm!("", options(noreturn));
+ | --------------------------- multiple asm blocks are unsupported in naked functions
error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:97:11
error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:95:5
|
-LL | / pub extern "C" fn inner(y: usize) -> usize {
-LL | |
-LL | | *&y
- | | --- non-asm is unsupported in naked functions
-LL | |
-LL | | }
- | |_____^
+LL | pub extern "C" fn inner(y: usize) -> usize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | *&y
+ | --- non-asm is unsupported in naked functions
error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
--> $DIR/naked-functions.rs:105:5
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:124:15
+ --> $DIR/naked-functions.rs:124:1
|
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:130:15
+ --> $DIR/naked-functions.rs:130:1
|
LL | pub unsafe fn rust_abi() {
- | ^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: naked functions cannot be inlined
--> $DIR/naked-functions.rs:170:1
| | clobber_abi
| generic outputs
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
--> $DIR/bad-options.rs:31:25
|
LL | global_asm!("", options(nomem));
- | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
--> $DIR/bad-options.rs:33:25
|
LL | global_asm!("", options(readonly));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
--> $DIR/bad-options.rs:35:25
|
LL | global_asm!("", options(noreturn));
- | ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+ | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
--> $DIR/bad-options.rs:37:25
|
LL | global_asm!("", options(pure));
- | ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+ | ^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
--> $DIR/bad-options.rs:39:25
|
LL | global_asm!("", options(nostack));
- | ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+ | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
--> $DIR/bad-options.rs:41:25
|
LL | global_asm!("", options(preserves_flags));
- | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+ | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: invalid ABI for `clobber_abi`
--> $DIR/bad-options.rs:20:18
LL | global_asm!("{}", const(reg) FOO);
| ^^^ expected one of `,`, `.`, `?`, or an operator
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
--> $DIR/parse-error.rs:104:25
|
LL | global_asm!("", options(FOO));
- | ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+ | ^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+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`, `may_unwind`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
--> $DIR/parse-error.rs:108:25
|
LL | global_asm!("", options(nomem, FOO));
- | ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+ | ^^^^^ expected one of `)`, `att_syntax`, or `raw`
error: arguments are not allowed after options
--> $DIR/parse-error.rs:110:30
const X: i32 = 97;
}
-struct Proxy<T>(T);
+struct Proxy<T>(#[allow(unused_tuple_struct_fields)] T);
impl<T: Foo> Foo for Proxy<T> {
const X: i32 = T::X;
// run-pass
#![feature(associated_type_bounds)]
+#![allow(dead_code)]
trait Tr1 { type As1; }
trait Tr2 { type As2; }
trait Device {
type Resources;
}
+#[allow(unused_tuple_struct_fields)]
struct Foo<D, R>(D, R);
trait Tr {
fn main() {
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
- //~^ ERROR type mismatch
+ //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
}
-error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == i32`
+error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
--> $DIR/associated-types-overridden-binding-2.rs:6:43
|
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
fn dummy(&self) { }
}
-pub struct Node<K:UnifyKey>(K, K::Value);
+pub struct Node<K:UnifyKey>(#[allow(unused_tuple_struct_fields)] K, K::Value);
fn foo<K : UnifyKey<Value=Option<V>>,V : Clone>(node: &Node<K>) -> Option<V> {
node.1.clone()
{
fn get_service(
//~^ ERROR the trait bound `Bug: Foo` is not satisfied
+ //~| ERROR the trait bound `Bug: Foo` is not satisfied
&self,
) -> Self::AssocType;
- //~^ the trait bound `Bug: Foo` is not satisfied
}
fn with_factory<H>(factory: dyn ThriftService<()>) {}
LL | |
LL | | Service<AssocType = <Bug as Foo>::OnlyFoo>
... |
-LL | |
+LL | | ) -> Self::AssocType;
LL | | }
| |_^ the trait `Foo` is not implemented for `Bug`
|
|
LL | / fn get_service(
LL | |
+LL | |
LL | | &self,
LL | | ) -> Self::AssocType;
| |_________________________^ the trait `Foo` is not implemented for `Bug`
| ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
error[E0277]: the trait bound `Bug: Foo` is not satisfied
- --> $DIR/issue-59324.rs:19:10
+ --> $DIR/issue-59324.rs:16:8
|
-LL | ) -> Self::AssocType;
- | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+LL | fn get_service(
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
|
help: consider further restricting this bound
|
return 0u8;
};
let _: &dyn Future<Output = ()> = █
- //~^ ERROR type mismatch
+ //~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
}
async fn return_targets_async_block_not_async_fn() -> u8 {
return 0u8;
};
let _: &dyn Future<Output = ()> = █
- //~^ ERROR type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
+ //~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
}
fn no_break_in_async_block() {
}
struct MyErr;
-fn err() -> Result<u8, MyErr> { Err(MyErr) }
+fn err() -> Result<u8, MyErr> {
+ Err(MyErr)
+}
fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
//~^ ERROR mismatched types
LL | | }
| |_^ expected `u8`, found `()`
-error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
+error[E0271]: expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
--> $DIR/async-block-control-flow-static-semantics.rs:26:39
|
LL | let _: &dyn Future<Output = ()> = █
| |
| implicitly returns `()` as its body has no tail or `return` expression
-error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()`
+error[E0271]: expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
--> $DIR/async-block-control-flow-static-semantics.rs:17:39
|
LL | let _: &dyn Future<Output = ()> = █
= note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
error[E0308]: mismatched types
- --> $DIR/async-block-control-flow-static-semantics.rs:47:44
+ --> $DIR/async-block-control-flow-static-semantics.rs:49:44
|
LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
| ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
found unit type `()`
error[E0308]: mismatched types
- --> $DIR/async-block-control-flow-static-semantics.rs:56:50
+ --> $DIR/async-block-control-flow-static-semantics.rs:58:50
|
LL | fn rethrow_targets_async_block_not_async_fn() -> Result<u8, MyErr> {
| ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
use std::task::{Context, Poll};
const BIG_FUT_SIZE: usize = 1024;
-struct BigFut([u8; BIG_FUT_SIZE]);
+struct BigFut(#[allow(unused_tuple_struct_fields)] [u8; BIG_FUT_SIZE]);
impl BigFut {
fn new() -> Self {
use std::task::{Context, Poll};
const BIG_FUT_SIZE: usize = 1024;
-struct Big([u8; BIG_FUT_SIZE]);
+struct Big(#[allow(unused_tuple_struct_fields)] [u8; BIG_FUT_SIZE]);
impl Big {
fn new() -> Self {
--> $DIR/no-const-async.rs:4:1
|
LL | pub const async fn x() {}
- | ^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
| ^ consider adding a `main` function to `$DIR/issue-90873.rs`
error: missing type for `static` item
- --> $DIR/issue-90873.rs:1:16
+ --> $DIR/issue-90873.rs:1:17
|
LL | #![u=||{static d=||1;}]
- | ^ help: provide a type for the item: `d: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: aborting due to 6 previous errors
impl !Auto for bool {}
impl !AutoUnsafe for bool {}
-struct AutoBool(bool);
+struct AutoBool(#[allow(unused_tuple_struct_fields)] bool);
impl Auto for AutoBool {}
unsafe impl AutoUnsafe for AutoBool {}
// compile-flags:-g -Csplit-debuginfo=unpacked
// only-macos
-#![feature(backtrace)]
-
use std::process::Command;
use std::str;
}
}
-struct Token<T>(T::Item) where T: Iterator;
+struct Token<T>(#[allow(unused_tuple_struct_fields)] T::Item) where T: Iterator;
impl<T> Parser for Token<T> where T: Iterator {
type Input = T;
}
}
-struct Chain<L, R>(L, R);
+struct Chain<L, R>(#[allow(unused_tuple_struct_fields)] L, #[allow(unused_tuple_struct_fields)] R);
impl<L, R> Parser for Chain<L, R> where L: Parser, R: Parser<Input = L::Input> {
type Input = L::Input;
#![allow(non_camel_case_types)]
-
+#[allow(unused_tuple_struct_fields)]
enum color {
rgb(isize, isize, isize),
rgba(isize, isize, isize, isize),
// run-pass
#![allow(non_camel_case_types)]
-enum blah { a(isize, isize, usize), b(isize, isize), c, }
+enum blah { a(isize, isize, #[allow(unused_tuple_struct_fields)] usize), b(isize, isize), c, }
fn or_alt(q: blah) -> isize {
match q { blah::a(x, y, _) | blah::b(x, y) => { return x + y; } blah::c => { return 0; } }
// pretty-expanded FIXME #23616
-enum clam<T> { a(T), }
+enum clam<T> { a(#[allow(unused_tuple_struct_fields)] T), }
pub fn main() { let c = clam::a(2); match c { clam::a::<isize>(_) => { } } }
-error[E0507]: cannot move out of `s.0` which is behind a shared reference
+error[E0507]: cannot move out of `s` which is behind a shared reference
--> $DIR/access-mode-in-closures.rs:8:15
|
LL | match *s { S(v) => v }
LL | let mut x: isize;
| ----- binding declared here but left uninitialized
LL | for _ in 0..0 { x = 10; }
- | ---- if the `for` loop runs 0 times, `x` is not initialized
+ | ---- if the `for` loop runs 0 times, `x` is not initialized
LL | return x;
| ^ `x` used here but it is possibly-uninitialized
-error[E0507]: cannot move out of `f.0` which is behind a shared reference
+error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference
--> $DIR/borrowck-move-error-with-note.rs:11:11
|
LL | match *f {
use std::marker;
#[derive(Copy, Clone)]
-struct X<T>(T);
+struct X<T>(#[allow(unused_tuple_struct_fields)] T);
impl<T:Sync> RequiresShare for X<T> { }
--- /dev/null
+macro_rules! cbor_map {
+ ($key:expr) => {
+ $key.signum();
+ //~^ ERROR can't call method `signum` on ambiguous numeric type `{integer}` [E0689]
+ };
+}
+
+fn main() {
+ cbor_map! { #[cfg(test)] 4};
+ //~^ ERROR attributes on expressions are experimental
+ //~| ERROR removing an expression is not supported in this position
+}
--- /dev/null
+error[E0658]: attributes on expressions are experimental
+ --> $DIR/cfg-method-receiver.rs:9:17
+ |
+LL | cbor_map! { #[cfg(test)] 4};
+ | ^^^^^^^^^^^^
+ |
+ = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+ = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error: removing an expression is not supported in this position
+ --> $DIR/cfg-method-receiver.rs:9:17
+ |
+LL | cbor_map! { #[cfg(test)] 4};
+ | ^^^^^^^^^^^^
+
+error[E0689]: can't call method `signum` on ambiguous numeric type `{integer}`
+ --> $DIR/cfg-method-receiver.rs:3:14
+ |
+LL | $key.signum();
+ | ^^^^^^
+...
+LL | cbor_map! { #[cfg(test)] 4};
+ | --------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `cbor_map` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you must specify a concrete type for this numeric value, like `i32`
+ |
+LL | cbor_map! { #[cfg(test)] 4_i32};
+ | ~~~~~
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0658, E0689.
+For more information about an error, try `rustc --explain E0658`.
// Test that `Clone` is correctly implemented for builtin types.
#[derive(Copy, Clone)]
-struct S(i32);
+struct S(#[allow(unused_tuple_struct_fields)] i32);
fn test_clone<T: Clone>(arg: T) {
let _ = arg.clone();
}
}
-struct S(Foo);
+struct S(#[allow(unused_tuple_struct_fields)] Foo);
#[derive(Clone)]
-struct T(i32);
+struct T(#[allow(unused_tuple_struct_fields)] i32);
struct U(S, T);
}
}
-struct S(Foo);
+struct S(#[allow(unused_tuple_struct_fields)] Foo);
#[derive(Clone)]
-struct T(i32);
+struct T(#[allow(unused_tuple_struct_fields)] i32);
struct U(S, T);
}
#[derive(Debug)]
-struct ConstainsDropField(Foo, Foo);
+struct ConstainsDropField(Foo, #[allow(unused_tuple_struct_fields)] Foo);
// `t` needs Drop because one of its elements needs drop,
// therefore precise capture might affect drop ordering
}
#[derive(Debug)]
-struct ConstainsDropField(Foo, Foo);
+struct ConstainsDropField(Foo, #[allow(unused_tuple_struct_fields)] Foo);
// `t` needs Drop because one of its elements needs drop,
// therefore precise capture might affect drop ordering
-#![feature(box_syntax)]
-
fn main() {
- let x: Box<_> = box 1;
+ let x: Box<_> = Box::new(1);
let f = move|| {
let _a = x;
drop(x);
error[E0382]: use of moved value: `x`
- --> $DIR/issue-10398.rs:7:14
+ --> $DIR/issue-10398.rs:5:14
|
LL | let _a = x;
| - value moved here
// transferring ownership of the box before invoking the stack
// closure results in a crash.
-#![feature(box_syntax)]
+
fn twice(x: Box<usize>) -> usize {
*x * 2
}
fn main() {
- let x : Box<usize> = box 9;
+ let x : Box<usize> = Box::new(9);
let sq = || { *x * *x };
twice(x); //~ ERROR: cannot move out of
| |
| arguments to this struct are incorrect
|
-note: return type inferred to be `{integer}` here
- --> $DIR/issue-84128.rs:10:20
- |
-LL | return Foo(0);
- | ^^^^^^
note: tuple struct defined here
--> $DIR/issue-84128.rs:5:8
|
--- /dev/null
+fn main() {
+ 2: n([u8; || 1])
+ //~^ ERROR cannot find type `n` in this scope
+ //~| ERROR mismatched types
+}
--- /dev/null
+error[E0412]: cannot find type `n` in this scope
+ --> $DIR/issue-90871.rs:2:8
+ |
+LL | 2: n([u8; || 1])
+ | ^ expecting a type here because of type ascription
+
+error[E0308]: mismatched types
+ --> $DIR/issue-90871.rs:2:15
+ |
+LL | 2: n([u8; || 1])
+ | ^^^^ expected `usize`, found closure
+ |
+ = note: expected type `usize`
+ found closure `[closure@$DIR/issue-90871.rs:2:15: 2:17]`
+help: use parentheses to call this closure
+ |
+LL | 2: n([u8; (|| 1)()])
+ | + +++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0412.
+For more information about an error, try `rustc --explain E0308`.
#![allow(unused_variables)]
#![allow(unused_assignments)]
#[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
enum Foo {
Bar(u32, u32),
Baz(&'static u32, &'static u32)
}
trait Foo { fn dummy(&self) { }}
-struct Output(isize);
+struct Output(#[allow(unused_tuple_struct_fields)] isize);
impl Foo for Output {}
const ASSOC: usize = 1;
}
+#[allow(unused_tuple_struct_fields)]
struct Iced<T: Foo>(T, [(); T::ASSOC])
where
[(); T::ASSOC]: ;
const ASSOC: usize = 1;
}
+#[allow(unused_tuple_struct_fields)]
struct Iced<T: Foo>(T, [(); T::ASSOC])
where
[(); T::ASSOC]: ;
extern crate const_generic_lib;
-struct Container(const_generic_lib::Alias);
+struct Container(#[allow(unused_tuple_struct_fields)] const_generic_lib::Alias);
fn main() {
let res = const_generic_lib::function(const_generic_lib::Struct([14u8, 1u8, 2u8]));
const BLOCK_SIZE: usize = 32;
}
-pub struct Block<C>(C);
+pub struct Block<C>(#[allow(unused_tuple_struct_fields)] C);
pub fn test<C: BlockCipher, const M: usize>()
where
--- /dev/null
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait TraitOne {
+ const MY_NUM: usize;
+ type MyErr: std::fmt::Debug;
+
+ fn do_one_stuff(arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr>;
+}
+
+trait TraitTwo {
+ fn do_two_stuff();
+}
+
+impl<O: TraitOne> TraitTwo for O
+where
+ [(); Self::MY_NUM]:,
+{
+ fn do_two_stuff() {
+ O::do_one_stuff([5; Self::MY_NUM]).unwrap()
+ }
+}
+
+struct Blargotron;
+
+#[derive(Debug)]
+struct ErrTy<const N: usize>([(); N]);
+
+impl TraitOne for Blargotron {
+ const MY_NUM: usize = 3;
+ type MyErr = ErrTy<{ Self::MY_NUM }>;
+
+ fn do_one_stuff(_arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr> {
+ Ok(())
+ }
+}
+
+fn main() {
+ Blargotron::do_two_stuff();
+}
--- /dev/null
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::convert::AsMut;
+use std::default::Default;
+
+trait Foo: Sized {
+ type Baz: Default + AsMut<[u8]>;
+ fn bar() {
+ Self::Baz::default().as_mut();
+ }
+}
+
+impl Foo for () {
+ type Baz = [u8; 1 * 1];
+ //type Baz = [u8; 1];
+}
+
+fn main() {
+ <() as Foo>::bar();
+}
--- /dev/null
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Collate<Op> {
+ type Pass;
+ type Fail;
+
+ fn collate(self) -> (Self::Pass, Self::Fail);
+}
+
+impl<Op> Collate<Op> for () {
+ type Pass = ();
+ type Fail = ();
+
+ fn collate(self) -> ((), ()) {
+ ((), ())
+ }
+}
+
+trait CollateStep<X, Prev> {
+ type Pass;
+ type Fail;
+ fn collate_step(x: X, prev: Prev) -> (Self::Pass, Self::Fail);
+}
+
+impl<X, P, F> CollateStep<X, (P, F)> for () {
+ type Pass = (X, P);
+ type Fail = F;
+
+ fn collate_step(x: X, (p, f): (P, F)) -> ((X, P), F) {
+ ((x, p), f)
+ }
+}
+
+struct CollateOpImpl<const MASK: u32>;
+trait CollateOpStep {
+ type NextOp;
+ type Apply;
+}
+
+impl<const MASK: u32> CollateOpStep for CollateOpImpl<MASK>
+where
+ CollateOpImpl<{ MASK >> 1 }>: Sized,
+{
+ type NextOp = CollateOpImpl<{ MASK >> 1 }>;
+ type Apply = ();
+}
+
+impl<H, T, Op: CollateOpStep> Collate<Op> for (H, T)
+where
+ T: Collate<Op::NextOp>,
+ Op::Apply: CollateStep<H, (T::Pass, T::Fail)>,
+{
+ type Pass = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Pass;
+ type Fail = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Fail;
+
+ fn collate(self) -> (Self::Pass, Self::Fail) {
+ <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::collate_step(self.0, self.1.collate())
+ }
+}
+
+fn collate<X, const MASK: u32>(x: X) -> (X::Pass, X::Fail)
+where
+ X: Collate<CollateOpImpl<MASK>>,
+{
+ x.collate()
+}
+
+fn main() {
+ dbg!(collate::<_, 5>(("Hello", (42, ('!', ())))));
+}
--- /dev/null
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+pub trait Foo {
+ fn foo(&self);
+}
+
+pub struct FooImpl<const N: usize>;
+impl<const N: usize> Foo for FooImpl<N> {
+ fn foo(&self) {}
+}
+
+pub trait Bar: 'static {
+ type Foo: Foo;
+ fn get() -> &'static Self::Foo;
+}
+
+struct BarImpl;
+impl Bar for BarImpl {
+ type Foo = FooImpl<
+ {
+ { 4 }
+ },
+ >;
+ fn get() -> &'static Self::Foo {
+ &FooImpl
+ }
+}
+
+pub fn boom<B: Bar>() {
+ B::get().foo();
+}
+
+fn main() {
+ boom::<BarImpl>();
+}
--- /dev/null
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Foo {
+ type Output;
+
+ fn foo() -> Self::Output;
+}
+
+impl Foo for [u8; 3] {
+ type Output = [u8; 1 + 2];
+
+ fn foo() -> [u8; 3] {
+ [1u8; 3]
+ }
+}
+
+fn bug<const N: usize>()
+where
+ [u8; N]: Foo,
+ <[u8; N] as Foo>::Output: AsRef<[u8]>,
+{
+ <[u8; N]>::foo().as_ref();
+}
+
+fn main() {
+ bug::<3>();
+}
--- /dev/null
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::marker::PhantomData;
+
+fn main() {
+ let x = FooImpl::<BarImpl<1>> { phantom: PhantomData };
+ let _ = x.foo::<BarImpl<1>>();
+}
+
+trait Foo<T>
+where
+ T: Bar,
+{
+ fn foo<U>(&self)
+ where
+ T: Operation<U>,
+ <T as Operation<U>>::Output: Bar;
+}
+
+struct FooImpl<T>
+where
+ T: Bar,
+{
+ phantom: PhantomData<T>,
+}
+
+impl<T> Foo<T> for FooImpl<T>
+where
+ T: Bar,
+{
+ fn foo<U>(&self)
+ where
+ T: Operation<U>,
+ <T as Operation<U>>::Output: Bar,
+ {
+ <<T as Operation<U>>::Output as Bar>::error_occurs_here();
+ }
+}
+
+trait Bar {
+ fn error_occurs_here();
+}
+
+struct BarImpl<const N: usize>;
+
+impl<const N: usize> Bar for BarImpl<N> {
+ fn error_occurs_here() {}
+}
+
+trait Operation<Rhs> {
+ type Output;
+}
+
+//// Part-A: This causes error.
+impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N>
+where
+ BarImpl<{ N + M }>: Sized,
+{
+ type Output = BarImpl<{ N + M }>;
+}
+
+//// Part-B: This doesn't cause error.
+// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
+// type Output = BarImpl<M>;
+// }
+
+//// Part-C: This also doesn't cause error.
+// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
+// type Output = BarImpl<{ M }>;
+// }
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(adt_const_params)]
+
+struct T<const B: &'static bool>;
+
+impl <const B: &'static bool> T<B> {
+ const fn set_false(&self) {
+ unsafe {
+ *(B as *const bool as *mut bool) = false;
+ //~^ ERROR evaluation of constant value failed [E0080]
+ }
+ }
+}
+
+const _: () = {
+ let x = T::<{&true}>;
+ x.set_false();
+};
+
+fn main() {}
--- /dev/null
+error[E0080]: evaluation of constant value failed
+ --> $DIR/issue-100313.rs:10:13
+ |
+LL | *(B as *const bool as *mut bool) = false;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | writing to alloc7 which is read-only
+ | inside `T::<&true>::set_false` at $DIR/issue-100313.rs:10:13
+...
+LL | x.set_false();
+ | ------------- inside `_` at $DIR/issue-100313.rs:18:5
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
}
struct Zero;
-struct Succ<N>(N);
+struct Succ<N>(#[allow(unused_tuple_struct_fields)] N);
impl Nat for Zero {
const VALUE: usize = 0;
use std::mem;
+#[allow(unused_tuple_struct_fields)]
struct Trivial(u8, f32);
+#[allow(unused_tuple_struct_fields)]
struct NonTrivial(u8, String);
const CONST_U8: bool = mem::needs_drop::<u8>();
use std::{mem, ptr};
-struct Foo(u32);
+struct Foo(#[allow(unused_tuple_struct_fields)] u32);
#[derive(Clone, Copy)]
struct Bar {
--- /dev/null
+#[derive(PartialEq)]
+enum E {
+ A,
+}
+
+const E_SL: &[E] = &[E::A];
+
+fn main() {
+ match &[][..] {
+ //~^ ERROR non-exhaustive patterns: `&_` not covered [E0004]
+ E_SL => {}
+ //~^ WARN to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
+ //~| WARN this was previously accepted by the compiler but is being phased out
+ }
+}
--- /dev/null
+warning: to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
+ --> $DIR/incomplete-slice.rs:11:9
+ |
+LL | E_SL => {}
+ | ^^^^
+ |
+ = note: `#[warn(indirect_structural_match)]` 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 #62411 <https://github.com/rust-lang/rust/issues/62411>
+
+error[E0004]: non-exhaustive patterns: `&_` not covered
+ --> $DIR/incomplete-slice.rs:9:11
+ |
+LL | match &[][..] {
+ | ^^^^^^^ pattern `&_` not covered
+ |
+ = note: the matched value is of type `&[E]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ E_SL => {}
+LL + &_ => todo!()
+ |
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0004`.
#![warn(indirect_structural_match)]
#[derive(Copy, Clone, Debug)]
-struct NoDerive(u32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] u32);
// This impl makes `NoDerive` irreflexive.
impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
--> $DIR/issue-44415.rs:6:17
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- | ^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
--> $DIR/issue-44415.rs:6:17
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- | ^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
--> $DIR/issue-44415.rs:6:17
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- | ^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Foo`...
= note: ...which requires computing layout of `[u8; _]`...
= note: ...which requires normalizing `[u8; _]`...
// run-pass
const HASH_LEN: usize = 20;
-struct Hash([u8; HASH_LEN]);
+struct Hash(#[allow(unused_tuple_struct_fields)] [u8; HASH_LEN]);
fn init_hash(_: &mut [u8; HASH_LEN]) {}
fn foo<'a>() -> &'a () {
const NONE_CELL_STRING: Option<Cell<String>> = None;
-struct Foo<T>(T);
+struct Foo<T>(#[allow(unused_tuple_struct_fields)] T);
impl<T> Foo<T> {
const FOO: Option<Box<T>> = None;
}
use std::mem;
#[repr(transparent)]
-struct Foo(u32);
+struct Foo(#[allow(unused_tuple_struct_fields)] u32);
const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) };
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `Clone`
+help: one of the expressions' fields has a method of the same name
+ |
+LL | let _y = x.i.clone();
+ | ++
error: aborting due to previous error
note: cycle used when collecting item types in top-level module
--> $DIR/cycle-trait-default-type-trait.rs:4:1
|
-LL | trait Foo<X = Box<dyn Foo>> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<X = Box<dyn Foo>> {
+LL | |
+LL | |
+LL | | }
+LL | |
+LL | | fn main() { }
+ | |_____________^
error[E0391]: cycle detected when computing type of `Foo::X`
--> $DIR/cycle-trait-default-type-trait.rs:4:23
note: cycle used when collecting item types in top-level module
--> $DIR/cycle-trait-default-type-trait.rs:4:1
|
-LL | trait Foo<X = Box<dyn Foo>> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<X = Box<dyn Foo>> {
+LL | |
+LL | |
+LL | | }
+LL | |
+LL | | fn main() { }
+ | |_____________^
error: aborting due to 2 previous errors
note: cycle used when collecting item types in top-level module
--> $DIR/cycle-trait-supertrait-direct.rs:3:1
|
-LL | trait Chromosome: Chromosome {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Chromosome: Chromosome {
+LL | |
+LL | | }
+ | |_^
error: aborting due to previous error
// pretty-expanded FIXME #23616
#[derive(Clone)]
+#[allow(unused_tuple_struct_fields)]
struct S<T>(T, ());
pub fn main() {
/// This struct is actually Copy... at least, it thinks it is!
#[derive(Copy, Clone)]
-struct Innocent(Liar);
+struct Innocent(#[allow(unused_tuple_struct_fields)] Liar);
impl Innocent {
fn new() -> Self {
#[derive(Clone)]
pub struct Little;
#[derive(Clone)]
+#[allow(unused_tuple_struct_fields)]
pub struct Big(
Little,
Little,
rc::Rc,
};
+use std::time::Duration;
+//~^ ERROR expected item, found `require`
+
+use std::time::Instant;
+//~^ ERROR expected item, found `include`
+
pub use std::io;
//~^ ERROR expected item, found `using`
fn main() {
let x = Rc::new(1);
let _ = write!(io::stdout(), "{:?}", x);
+ let _ = Duration::new(5, 0);
+ let _ = Instant::now();
}
rc::Rc,
};
+require std::time::Duration;
+//~^ ERROR expected item, found `require`
+
+include std::time::Instant;
+//~^ ERROR expected item, found `include`
+
pub using std::io;
//~^ ERROR expected item, found `using`
fn main() {
let x = Rc::new(1);
let _ = write!(io::stdout(), "{:?}", x);
+ let _ = Duration::new(5, 0);
+ let _ = Instant::now();
}
LL | import std::{
| ^^^^^^ help: items are imported using the `use` keyword
+error: expected item, found `require`
+ --> $DIR/use_instead_of_import.rs:9:1
+ |
+LL | require std::time::Duration;
+ | ^^^^^^^ help: items are imported using the `use` keyword
+
+error: expected item, found `include`
+ --> $DIR/use_instead_of_import.rs:12:1
+ |
+LL | include std::time::Instant;
+ | ^^^^^^^ help: items are imported using the `use` keyword
+
error: expected item, found `using`
- --> $DIR/use_instead_of_import.rs:9:5
+ --> $DIR/use_instead_of_import.rs:15:5
|
LL | pub using std::io;
| ^^^^^ help: items are imported using the `use` keyword
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
struct Dt<A: Foo>(&'static str, A);
struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
-struct Pt<A: Foo, B: Foo>(&'static str, A, B);
-struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
-struct St<A: Foo>(&'static str, A);
-struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
+struct Pt<A: Foo, B: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A, B);
+struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B, &'b B);
+struct St<A: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A);
+struct Sr<'a, B:'a+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B);
impl<A: Foo> Drop for Dt<A> {
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
struct Dt<A: Foo>(&'static str, A);
struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
-struct Pt<A,B: Foo>(&'static str, A, B);
-struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
-struct St<A: Foo>(&'static str, A);
-struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
+struct Pt<A,B: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A, B);
+struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B, &'b B);
+struct St<A: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A);
+struct Sr<'a, B:'a+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B);
impl<A: Foo> Drop for Dt<A> {
fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
};
}
-struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
+struct TwoPtrs<'a>(Ptr<'a>, #[allow(unused_tuple_struct_fields)] Ptr<'a>);
fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) {
for i in 0..2 {
let x;
}
}
-struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
+struct Foo<T>(u32, T, #[allow(unused_tuple_struct_fields)] Box<for <'r> fn(&'r T) -> String>);
unsafe impl<#[may_dangle] T> Drop for Foo<T> {
fn drop(&mut self) {
// Check that dynamically sized rvalues are forbidden
-#![feature(box_syntax)]
-
pub fn main() {
- let _x: Box<str> = box *"hello world";
+ let _x: Box<str> = Box::new(*"hello world");
//~^ ERROR E0277
let array: &[isize] = &[1, 2, 3];
- let _x: Box<[isize]> = box *array;
+ let _x: Box<[isize]> = Box::new(*array);
//~^ ERROR E0277
}
error[E0277]: the size for values of type `str` cannot be known at compilation time
- --> $DIR/dst-rvalue.rs:6:28
+ --> $DIR/dst-rvalue.rs:4:33
|
-LL | let _x: Box<str> = box *"hello world";
- | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+LL | let _x: Box<str> = Box::new(*"hello world");
+ | -------- ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ | |
+ | required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `str`
- = note: the type of a box expression must have a statically known size
+note: required by a bound in `Box::<T>::new`
+ --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+ |
+LL | impl<T> Box<T> {
+ | ^ required by this bound in `Box::<T>::new`
error[E0277]: the size for values of type `[isize]` cannot be known at compilation time
- --> $DIR/dst-rvalue.rs:10:32
+ --> $DIR/dst-rvalue.rs:8:37
|
-LL | let _x: Box<[isize]> = box *array;
- | ^^^^^^ doesn't have a size known at compile-time
+LL | let _x: Box<[isize]> = Box::new(*array);
+ | -------- ^^^^^^ doesn't have a size known at compile-time
+ | |
+ | required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `[isize]`
- = note: the type of a box expression must have a statically known size
+note: required by a bound in `Box::<T>::new`
+ --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+ |
+LL | impl<T> Box<T> {
+ | ^ required by this bound in `Box::<T>::new`
error: aborting due to 2 previous errors
// run-pass
-#![feature(box_syntax)]
struct Fat<T: ?Sized> {
f1: isize,
assert_eq!((*f2)[1], 2);
// Nested Box.
- let f1 : Box<Fat<[isize; 3]>> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
+ let f1 : Box<Fat<[isize; 3]>> = Box::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] });
foo(&*f1);
let f2 : Box<Fat<[isize]>> = f1;
foo(&*f2);
// run-pass
-#![feature(box_syntax)]
struct Fat<T: ?Sized> {
f1: isize,
use std::mem;
+#[allow(unused_tuple_struct_fields)]
enum ADT {
First(u32, u32),
Second(u64)
D
}
+#[allow(unused_tuple_struct_fields)]
enum ADT {
First(u32, u32),
Second(u64)
}
enum NullablePointer {
- Something(&'static u32),
+ Something(#[allow(unused_tuple_struct_fields)] &'static u32),
Nothing
}
enum Eu64 {
//~^ ERROR discriminant value `0` assigned more than once
Au64 = 0,
- //~^NOTE first assignment of `0`
+ //~^NOTE `0` assigned here
Bu64 = 0x8000_0000_0000_0000
- //~^NOTE second assignment of `0` (overflowed from `9223372036854775808`)
+ //~^NOTE `0` (overflowed from `9223372036854775808`) assigned here
}
fn main() {}
| ^^^^^^^^^
LL |
LL | Au64 = 0,
- | - first assignment of `0`
+ | - `0` assigned here
LL |
LL | Bu64 = 0x8000_0000_0000_0000
- | --------------------- second assignment of `0` (overflowed from `9223372036854775808`)
+ | --------------------- `0` (overflowed from `9223372036854775808`) assigned here
error: aborting due to previous error
enum Enum {
//~^ ERROR discriminant value `3` assigned more than once
P = 3,
- //~^ NOTE first assignment of `3`
+ //~^ NOTE `3` assigned here
X = 3,
- //~^ NOTE second assignment of `3`
+ //~^ NOTE `3` assigned here
Y = 5
}
enum EnumOverflowRepr {
//~^ ERROR discriminant value `1` assigned more than once
P = 257,
- //~^ NOTE first assignment of `1` (overflowed from `257`)
+ //~^ NOTE `1` (overflowed from `257`) assigned here
X = 513,
- //~^ NOTE second assignment of `1` (overflowed from `513`)
+ //~^ NOTE `1` (overflowed from `513`) assigned here
}
#[repr(i8)]
enum NegDisEnum {
//~^ ERROR discriminant value `-1` assigned more than once
First = -1,
- //~^ NOTE first assignment of `-1`
+ //~^ NOTE `-1` assigned here
Second = -2,
- //~^ NOTE assigned discriminant for `Last` was incremented from this discriminant
+ //~^ NOTE discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
Last,
- //~^ NOTE second assignment of `-1`
+ //~^ NOTE `-1` assigned here
+}
+
+enum MultipleDuplicates {
+ //~^ ERROR discriminant value `0` assigned more than once
+ //~^^ ERROR discriminant value `-2` assigned more than once
+ V0,
+ //~^ NOTE `0` assigned here
+ V1 = 0,
+ //~^ NOTE `0` assigned here
+ V2,
+ V3,
+ V4 = 0,
+ //~^ NOTE `0` assigned here
+ V5 = -2,
+ //~^ NOTE discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
+ //~^^ NOTE `-2` assigned here
+ V6,
+ V7,
+ //~^ NOTE `0` assigned here
+ V8 = -3,
+ //~^ NOTE discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
+ V9,
+ //~^ NOTE `-2` assigned here
}
fn main() {
| ^^^^^^^^^
LL |
LL | P = 3,
- | - first assignment of `3`
+ | - `3` assigned here
LL |
LL | X = 3,
- | - second assignment of `3`
+ | - `3` assigned here
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/E0081.rs:11:1
| ^^^^^^^^^^^^^^^^^^^^^
LL |
LL | P = 257,
- | --- first assignment of `1` (overflowed from `257`)
+ | --- `1` (overflowed from `257`) assigned here
LL |
LL | X = 513,
- | --- second assignment of `1` (overflowed from `513`)
+ | --- `1` (overflowed from `513`) assigned here
error[E0081]: discriminant value `-1` assigned more than once
--> $DIR/E0081.rs:20:1
| ^^^^^^^^^^^^^^^
LL |
LL | First = -1,
- | -- first assignment of `-1`
+ | -- `-1` assigned here
LL |
LL | Second = -2,
- | ----------- assigned discriminant for `Last` was incremented from this discriminant
+ | ----------- discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
LL |
LL | Last,
- | ---- second assignment of `-1`
+ | ---- `-1` assigned here
-error: aborting due to 3 previous errors
+error[E0081]: discriminant value `0` assigned more than once
+ --> $DIR/E0081.rs:30:1
+ |
+LL | enum MultipleDuplicates {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | V0,
+ | -- `0` assigned here
+LL |
+LL | V1 = 0,
+ | - `0` assigned here
+...
+LL | V4 = 0,
+ | - `0` assigned here
+LL |
+LL | V5 = -2,
+ | ------- discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
+...
+LL | V7,
+ | -- `0` assigned here
+
+error[E0081]: discriminant value `-2` assigned more than once
+ --> $DIR/E0081.rs:30:1
+ |
+LL | enum MultipleDuplicates {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | V5 = -2,
+ | -- `-2` assigned here
+...
+LL | V8 = -3,
+ | ------- discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
+LL |
+LL | V9,
+ | -- `-2` assigned here
+
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0081`.
| ----- ^^^^^ expected `i32`, found `u32`
| |
| expected because of this
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | let x = if true { 10i32 } else { 10i32 };
+ | ~~~
error: aborting due to previous error
| | ^^^^ expected `i32`, found `u32`
LL | | };
| |_____- `if` and `else` have incompatible types
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | 2i32
+ | ~~~
error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-else-type-mismatch.rs:8:38
| ----- ^^^^^ expected `i32`, found `u32`
| |
| expected because of this
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | let _ = if true { 42i32 } else { 42i32 };
+ | ~~~
error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-else-type-mismatch.rs:13:9
#[link_ordinal(42)]
//~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
fn foo();
+ #[link_ordinal(5)]
+ //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
+ static mut imported_variable: i32;
}
fn main() {}
= note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
= help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-error: aborting due to previous error
+error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
+ --> $DIR/feature-gate-raw-dylib-2.rs:6:5
+ |
+LL | #[link_ordinal(5)]
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+ = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.
LL | #![warn(unused_attributes, unknown_lints)]
| ^^^^^^^^^^^^^^^^^
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:1
|
LL | #[automatically_derived]
LL | #[path = "3800"] impl S { }
| ^^^^^^^^^^^^^^^^
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:17
|
LL | mod inner { #![automatically_derived] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5
|
LL | #[automatically_derived] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5
|
LL | #[automatically_derived] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:278:5
|
LL | #[automatically_derived] type T = S;
LL | #[must_use] type T = S;
| ^^^^^^^^^^^
-warning: `#[must_use]` has no effect when applied to an item
+warning: `#[must_use]` has no effect when applied to an implementation block
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5
|
LL | #[must_use] impl S { }
--- /dev/null
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+ field: usize,
+}
+
+fn main() {
+ let foo = Foo { field: 0 };
+ let bar = 3;
+ format!("{0}", foo.field); //~ ERROR invalid format string: field access isn't supported
+ format!("{1} {} {bar}", "aa", foo.field); //~ ERROR invalid format string: field access isn't supported
+ format!("{2} {} {1} {bar}", "aa", "bb", foo.field); //~ ERROR invalid format string: field access isn't supported
+ format!("{1} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+ format!("{1:?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+ format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+ format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+}
--- /dev/null
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+ field: usize,
+}
+
+fn main() {
+ let foo = Foo { field: 0 };
+ let bar = 3;
+ format!("{foo.field}"); //~ ERROR invalid format string: field access isn't supported
+ format!("{foo.field} {} {bar}", "aa"); //~ ERROR invalid format string: field access isn't supported
+ format!("{foo.field} {} {1} {bar}", "aa", "bb"); //~ ERROR invalid format string: field access isn't supported
+ format!("{foo.field} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+ format!("{foo.field:?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+ format!("{foo.field:#?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+ format!("{foo.field:.3} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+}
--- /dev/null
+error: invalid format string: field access isn't supported
+ --> $DIR/struct-field-as-captured-argument.rs:11:15
+ |
+LL | format!("{foo.field}");
+ | ^^^^^^^^^ not supported in format string
+ |
+help: consider using a positional formatting argument instead
+ |
+LL | format!("{0}", foo.field);
+ | ~ +++++++++++
+
+error: invalid format string: field access isn't supported
+ --> $DIR/struct-field-as-captured-argument.rs:12:15
+ |
+LL | format!("{foo.field} {} {bar}", "aa");
+ | ^^^^^^^^^ not supported in format string
+ |
+help: consider using a positional formatting argument instead
+ |
+LL | format!("{1} {} {bar}", "aa", foo.field);
+ | ~ +++++++++++
+
+error: invalid format string: field access isn't supported
+ --> $DIR/struct-field-as-captured-argument.rs:13:15
+ |
+LL | format!("{foo.field} {} {1} {bar}", "aa", "bb");
+ | ^^^^^^^^^ not supported in format string
+ |
+help: consider using a positional formatting argument instead
+ |
+LL | format!("{2} {} {1} {bar}", "aa", "bb", foo.field);
+ | ~ +++++++++++
+
+error: invalid format string: field access isn't supported
+ --> $DIR/struct-field-as-captured-argument.rs:14:15
+ |
+LL | format!("{foo.field} {} {baz}", "aa", baz = 3);
+ | ^^^^^^^^^ not supported in format string
+ |
+help: consider using a positional formatting argument instead
+ |
+LL | format!("{1} {} {baz}", "aa", foo.field, baz = 3);
+ | ~ +++++++++++
+
+error: invalid format string: field access isn't supported
+ --> $DIR/struct-field-as-captured-argument.rs:15:15
+ |
+LL | format!("{foo.field:?} {} {baz}", "aa", baz = 3);
+ | ^^^^^^^^^ not supported in format string
+ |
+help: consider using a positional formatting argument instead
+ |
+LL | format!("{1:?} {} {baz}", "aa", foo.field, baz = 3);
+ | ~ +++++++++++
+
+error: invalid format string: field access isn't supported
+ --> $DIR/struct-field-as-captured-argument.rs:16:15
+ |
+LL | format!("{foo.field:#?} {} {baz}", "aa", baz = 3);
+ | ^^^^^^^^^ not supported in format string
+ |
+help: consider using a positional formatting argument instead
+ |
+LL | format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3);
+ | ~ +++++++++++
+
+error: invalid format string: field access isn't supported
+ --> $DIR/struct-field-as-captured-argument.rs:17:15
+ |
+LL | format!("{foo.field:.3} {} {baz}", "aa", baz = 3);
+ | ^^^^^^^^^ not supported in format string
+ |
+help: consider using a positional formatting argument instead
+ |
+LL | format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3);
+ | ~ +++++++++++
+
+error: aborting due to 7 previous errors
+
-// check-pass
+// check-fail
trait Trait {
type Type;
fn g<'a, 'b>() {
f::<'a, 'b>(());
+ //~^ ERROR lifetime may not live long enough
}
fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/implied-bounds-unnorm-associated-type-2.rs:19:5
+ |
+LL | fn g<'a, 'b>() {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | f::<'a, 'b>(());
+ | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of a function pointer to `f`
+ = note: the function `f` is invariant over the parameter `'a`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
-// check-fail
-// See issue #91899. If we treat unnormalized args as WF, `Self` can also be a
-// source of unsoundness.
+// check-pass
pub trait Yokeable<'a>: 'static {
type Output: 'a;
impl<T> ZeroCopyFrom<[T]> for &'static [T] {
fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
- //~^ the parameter
cart
}
}
+++ /dev/null
-error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/implied-bounds-unnorm-associated-type-3.rs:19:5
- |
-LL | fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `[T]` will meet its required lifetime bounds
- |
-help: consider adding an explicit lifetime bound...
- |
-LL | impl<T: 'static> ZeroCopyFrom<[T]> for &'static [T] {
- | +++++++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0310`.
--- /dev/null
+// A regression test for #98543
+
+trait Trait {
+ type Type;
+}
+
+impl<T> Trait for T {
+ type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str
+where
+ &'a &'b (): Trait, // <- adding this bound is the change from #91068
+{
+ s
+}
+
+fn main() {
+ let x = String::from("Hello World!");
+ let y = f(&x, ());
+ drop(x);
+ //~^ ERROR cannot move out of `x` because it is borrowed
+ println!("{}", y);
+}
--- /dev/null
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/implied-bounds-unnorm-associated-type-4.rs:21:10
+ |
+LL | let y = f(&x, ());
+ | -- borrow of `x` occurs here
+LL | drop(x);
+ | ^ move out of `x` occurs here
+LL |
+LL | println!("{}", y);
+ | - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
--- /dev/null
+trait Trait<'a>: 'a {
+ type Type;
+}
+
+// if the `T: 'a` bound gets implied we would probably get ub here again
+impl<'a, T> Trait<'a> for T {
+ //~^ ERROR the parameter type `T` may not live long enough
+ type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'b () as Trait<'a>>::Type) -> &'a str
+where
+ &'b (): Trait<'a>,
+{
+ s
+}
+
+fn main() {
+ let x = String::from("Hello World!");
+ let y = f(&x, ());
+ drop(x);
+ println!("{}", y);
+}
--- /dev/null
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:13
+ |
+LL | impl<'a, T> Trait<'a> for T {
+ | ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+ |
+note: ...that is required by this bound
+ --> $DIR/implied-bounds-unnorm-associated-type-5.rs:1:18
+ |
+LL | trait Trait<'a>: 'a {
+ | ^^
+help: consider adding an explicit lifetime bound...
+ |
+LL | impl<'a, T: 'a> Trait<'a> for T {
+ | ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
// check-fail
-// See issue #91068. Types in the substs of an associated type can't be implied
-// to be WF, since they don't actually have to be constructed.
+// See issue #91068. We check that the unnormalized associated types in
+// function signatures are implied
trait Trait {
type Type;
fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
s
- //~^ ERROR lifetime may not live long enough
}
fn main() {
let x = String::from("Hello World!");
let y = f(&x, ());
drop(x);
+ //~^ ERROR cannot move out of `x` because it is borrowed
println!("{}", y);
}
-error: lifetime may not live long enough
- --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+error[E0505]: cannot move out of `x` because it is borrowed
+ --> $DIR/implied-bounds-unnorm-associated-type.rs:20:10
|
-LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
- | -- -- lifetime `'b` defined here
- | |
- | lifetime `'a` defined here
-LL | s
- | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
- |
- = help: consider adding the following bound: `'b: 'a`
+LL | let y = f(&x, ());
+ | -- borrow of `x` occurs here
+LL | drop(x);
+ | ^ move out of `x` occurs here
+LL |
+LL | println!("{}", y);
+ | - borrow later used here
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0505`.
|
= note: expected type `!`
found unit type `()`
+note: the function expects a value to always be returned, but loops might run zero times
+ --> $DIR/break-while-condition.rs:24:13
+ |
+LL | while false {
+ | ^^^^^^^^^^^ this might have zero elements to iterate on
+LL | return
+ | ------ if the loop doesn't execute, this value would never get returned
+ = help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
error: aborting due to 3 previous errors
use std::ops::Generator;
const FOO_SIZE: usize = 1024;
-struct Foo([u8; FOO_SIZE]);
+struct Foo(#[allow(unused_tuple_struct_fields)] [u8; FOO_SIZE]);
impl Drop for Foo {
fn drop(&mut self) {}
|
LL | return Ok(6);
| ^^^^^
+help: try wrapping the expression in a variant of `Result`
+ |
+LL | Ok(5)
+ | +++ +
+LL | Err(5)
+ | ++++ +
error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7] as Generator>::Return == i32`
--> $DIR/type-mismatch-signature-deduction.rs:5:13
+++ /dev/null
-// check-fail
-// known-bug: #87748
-
-// This should pass, but unnormalized input args aren't treated as implied.
-
-#![feature(generic_associated_types)]
-
-trait MyTrait {
- type Assoc<'a, 'b> where 'b: 'a;
- fn do_sth(arg: Self::Assoc<'_, '_>);
-}
-
-struct Foo;
-
-impl MyTrait for Foo {
- type Assoc<'a, 'b> = u32 where 'b: 'a;
-
- fn do_sth(_: u32) {}
- // fn do_sth(_: Self::Assoc<'static, 'static>) {}
- // fn do_sth(_: Self::Assoc<'_, '_>) {}
-}
-
-fn main() {}
+++ /dev/null
-error[E0478]: lifetime bound not satisfied
- --> $DIR/issue-87748.rs:18:5
- |
-LL | fn do_sth(_: u32) {}
- | ^^^^^^^^^^^^^^^^^
- |
-note: lifetime parameter instantiated with the anonymous lifetime as defined here
- --> $DIR/issue-87748.rs:18:5
- |
-LL | fn do_sth(_: u32) {}
- | ^^^^^^^^^^^^^^^^^
-note: but lifetime parameter must outlive the anonymous lifetime as defined here
- --> $DIR/issue-87748.rs:18:5
- |
-LL | fn do_sth(_: u32) {}
- | ^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0478`.
--- /dev/null
+// Checks that we properly add implied bounds from unnormalized projections in
+// inputs when typechecking functions.
+
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait MyTrait {
+ type Assoc<'a, 'b> where 'b: 'a;
+ fn do_sth(arg: Self::Assoc<'_, '_>);
+ fn do_sth2(arg: Self::Assoc<'_, '_>) {}
+}
+
+struct Foo;
+
+impl MyTrait for Foo {
+ type Assoc<'a, 'b> = u32 where 'b: 'a;
+
+ fn do_sth(_: u32) {}
+ fn do_sth2(_: Self::Assoc<'static, 'static>) {}
+}
+
+fn main() {}
extern crate default_type_params_xc;
-struct Vec<T, A = default_type_params_xc::Heap>(Option<(T,A)>);
+struct Vec<T, A = default_type_params_xc::Heap>(#[allow(unused_tuple_struct_fields)] Option<(T,A)>);
struct Foo;
// run-pass
#![allow(non_camel_case_types)]
-enum wrapper<T> { wrapped(T), }
+enum wrapper<T> { wrapped(#[allow(unused_tuple_struct_fields)] T), }
pub fn main() { let _w = wrapper::wrapped(vec![1, 2, 3, 4, 5]); }
// run-pass
// pretty-expanded FIXME #23616
-struct S<T>(T);
+struct S<T>(#[allow(unused_tuple_struct_fields)] T);
pub fn main() {
let _s = S(2);
fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
}
-pub struct Bar<T>(T);
+pub struct Bar<T>(#[allow(unused_tuple_struct_fields)] T);
impl<T> Bar<T> {
fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
}
-pub struct Baz<'a>(&'a i32);
+pub struct Baz<'a>(#[allow(unused_tuple_struct_fields)] &'a i32);
impl<'a> Baz<'a> {
#[no_mangle]
fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
}
-pub struct Bar<T>(T);
+pub struct Bar<T>(#[allow(unused_tuple_struct_fields)] T);
impl<T> Bar<T> {
#[no_mangle]
fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
}
-pub struct Baz<'a>(&'a i32);
+pub struct Baz<'a>(#[allow(unused_tuple_struct_fields)] &'a i32);
impl<'a> Baz<'a> {
#[no_mangle]
// run-pass
#![allow(non_camel_case_types)]
-enum list<T> { cons(Box<T>, Box<list<T>>), nil, }
+enum list<T> { #[allow(unused_tuple_struct_fields)] cons(Box<T>, Box<list<T>>), nil, }
pub fn main() {
let _a: list<isize> =
// This used to cause memory corruption in stage 0.
// pretty-expanded FIXME #23616
-enum thing<K> { some(K), }
+enum thing<K> { some(#[allow(unused_tuple_struct_fields)] K), }
pub fn main() { let _x = thing::some("hi".to_string()); }
// pretty-expanded FIXME #23616
-enum clam<T> { a(T), }
+enum clam<T> { a(#[allow(unused_tuple_struct_fields)] T), }
pub fn main() { let _c = clam::a(3); }
#![allow(unused_variables)]
-enum option<T> { some(Box<T>), none, }
+enum option<T> { some(#[allow(unused_tuple_struct_fields)] Box<T>), none, }
pub fn main() {
let mut a: option<isize> = option::some::<isize>(Box::new(10));
fn give_me_ice<T>() {
callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
//~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
- //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
}
fn callee<T: Fn<(&'static (),)>>() {
LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
| +++++++++++++++++++++++
-error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied
- --> $DIR/issue-85455.rs:8:14
- |
-LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T`
- |
-help: consider restricting type parameter `T`
- |
-LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
- | +++++++++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
LL | / fn no_hrtb<'b, T>(mut t: T)
LL | | where
LL | | T: Bar<&'b isize>,
-LL | | {
-... |
-LL | | no_hrtb(&mut t);
- | | --------------- recursive call site
-LL | | }
- | |_^ cannot return without recursing
+ | |______________________^ cannot return without recursing
+...
+LL | no_hrtb(&mut t);
+ | --------------- recursive call site
|
= note: `#[warn(unconditional_recursion)]` on by default
= help: a `loop` may express intention better if this is on purpose
LL | / fn bar_hrtb<T>(mut t: T)
LL | | where
LL | | T: for<'b> Bar<&'b isize>,
-LL | | {
-... |
-LL | | bar_hrtb(&mut t);
- | | ---------------- recursive call site
-LL | | }
- | |_^ cannot return without recursing
+ | |______________________________^ cannot return without recursing
+...
+LL | bar_hrtb(&mut t);
+ | ---------------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
LL | / fn foo_hrtb_bar_not<'b, T>(mut t: T)
LL | | where
LL | | T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
-LL | | {
-... |
-LL | | foo_hrtb_bar_not(&mut t);
- | | ------------------------ recursive call site
-LL | |
-LL | |
-LL | | }
- | |_^ cannot return without recursing
+ | |_______________________________________________^ cannot return without recursing
+...
+LL | foo_hrtb_bar_not(&mut t);
+ | ------------------------ recursive call site
|
= help: a `loop` may express intention better if this is on purpose
LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
LL | | where
LL | | T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
-LL | | {
-LL | | // OK -- now we have `T : for<'b> Bar<&'b isize>`.
-LL | | foo_hrtb_bar_hrtb(&mut t);
- | | ------------------------- recursive call site
-LL | | }
- | |_^ cannot return without recursing
+ | |_______________________________________________________^ cannot return without recursing
+...
+LL | foo_hrtb_bar_hrtb(&mut t);
+ | ------------------------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| --------- - ^^^^^^ unsatisfied trait bound introduced here
-help: one of the expressions' fields has a method of the same name
- |
-LL | let filter = map.stream.filterx(|x: &_| true);
- | +++++++
error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
--> $DIR/issue-30786.rs:130:24
|
LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
| --------- - ^^^^^^ unsatisfied trait bound introduced here
-help: one of the expressions' fields has a method of the same name
- |
-LL | let count = filter.stream.countx();
- | +++++++
error: aborting due to 2 previous errors
let v = Unit2.m(
//~^ ERROR type mismatch
L {
- //~^ ERROR type mismatch
- f : |x| { drop(x); Unit4 }
- });
+ //~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
+ f: |x| {
+ drop(x);
+ Unit4
+ },
+ },
+ );
}
impl<'a> Ty<'a> for Unit2 {
-error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
--> $DIR/issue-62203-hrtb-ice.rs:38:19
|
LL | let v = Unit2.m(
- | ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+ | ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
|
note: expected this to be `<_ as Ty<'_>>::V`
--> $DIR/issue-62203-hrtb-ice.rs:21:14
LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20] as FnOnce<((&'r u8,),)>>::Output == Unit3`
+error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4`
--> $DIR/issue-62203-hrtb-ice.rs:40:9
|
LL | let v = Unit2.m(
LL |
LL | / L {
LL | |
-LL | | f : |x| { drop(x); Unit4 }
-LL | | });
+LL | | f: |x| {
+LL | | drop(x);
+LL | | Unit4
+LL | | },
+LL | | },
| |_________^ expected struct `Unit3`, found struct `Unit4`
|
-note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]>`
+note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]>`
--> $DIR/issue-62203-hrtb-ice.rs:17:16
|
LL | impl<'a, A, T> T0<'a, A> for L<T>
GenFuture(x)
}
-struct GenFuture<T: FakeGenerator<Yield = ()>>(T);
+struct GenFuture<T: FakeGenerator<Yield = ()>>(#[allow(unused_tuple_struct_fields)] T);
impl<T: FakeGenerator<Yield = ()>> FakeFuture for GenFuture<T> {
type Output = T::Return;
--> $DIR/equality.rs:15:5
|
LL | fn two(x: bool) -> impl Foo {
- | -------- expected `_` because of return type
+ | -------- expected `i32` because of return type
...
LL | 0_u32
| ^^^^^ expected `i32`, found `u32`
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | 0_i32
+ | ~~~
error[E0277]: cannot add `impl Foo` to `u32`
--> $DIR/equality.rs:24:11
--- /dev/null
+// check-pass
+
+trait Trait<T> {
+ type Ty;
+}
+impl Trait<&u8> for () {
+ type Ty = ();
+}
+
+fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}
+
+fn main() {}
struct Bug {
V1: [(); {
fn concrete_use() -> F {
- //~^ ERROR type mismatch
+ //~^ ERROR expected `impl Future<Output = ()>` to be a future that resolves to `u8`, but it resolves to `()`
async {}
}
let f: F = async { 1 };
LL | }],
| - value is dropped here
-error[E0271]: type mismatch resolving `<impl Future<Output = ()> as Future>::Output == u8`
+error[E0271]: expected `impl Future<Output = ()>` to be a future that resolves to `u8`, but it resolves to `()`
--> $DIR/issue-78722.rs:9:30
|
LL | fn concrete_use() -> F {
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5
|
LL | fn can() -> impl NotObjectSafe {
- | ------------------ expected `_` because of return type
+ | ------------------ expected `A` because of return type
...
LL | B
| ^ expected struct `A`, found struct `B`
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
|
LL | fn cat() -> impl ObjectSafe {
- | --------------- expected `_` because of return type
+ | --------------- expected `A` because of return type
...
LL | B
| ^ expected struct `A`, found struct `B`
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
|
LL | fn foo() -> impl std::fmt::Display {
- | ---------------------- expected `_` because of return type
+ | ---------------------- expected `i32` because of return type
...
LL | 1u32
| ^^^^ expected `i32`, found `u32`
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | 1i32
+ | ~~~
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
|
LL | fn bar() -> impl std::fmt::Display {
- | ---------------------- expected `_` because of return type
+ | ---------------------- expected `i32` because of return type
...
LL | return 1u32;
| ^^^^ expected `i32`, found `u32`
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | return 1i32;
+ | ~~~
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
|
LL | fn baz() -> impl std::fmt::Display {
- | ---------------------- expected `_` because of return type
+ | ---------------------- expected `i32` because of return type
...
LL | 1u32
| ^^^^ expected `i32`, found `u32`
+ |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+ |
+LL | }.try_into().unwrap()
+ | ++++++++++++++++++++
error[E0308]: `if` and `else` have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
| | ^^^^ expected `i32`, found `u32`
LL | | }
| |_____- `if` and `else` have incompatible types
+ |
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn qux() -> Box<dyn std::fmt::Display> {
+ | ~~~~~~~ +
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL ~ Box::new(0i32)
+LL | } else {
+LL ~ Box::new(1u32)
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | 1i32
+ | ~~~
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
|
LL | fn bat() -> impl std::fmt::Display {
- | ---------------------- expected `_` because of return type
+ | ---------------------- expected `i32` because of return type
...
LL | _ => 1u32,
| ^^^^ expected `i32`, found `u32`
+ |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+ |
+LL | }.try_into().unwrap()
+ | ++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
|
LL | fn can() -> impl std::fmt::Display {
- | ---------------------- expected `_` because of return type
+ | ---------------------- expected `i32` because of return type
LL | / match 13 {
LL | | 0 => return 0i32,
LL | | 1 => 1u32,
LL | | _ => 2u32,
LL | | }
| |_____^ expected `i32`, found `u32`
+ |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+ |
+LL | }.try_into().unwrap()
+ | ++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
|
LL | fn cat() -> impl std::fmt::Display {
- | ---------------------- expected `_` because of return type
+ | ---------------------- expected `i32` because of return type
...
LL | 1u32
| ^^^^ expected `i32`, found `u32`
+ |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+ |
+LL | }.try_into().unwrap()
+ | ++++++++++++++++++++
error[E0308]: `match` arms have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14
LL | | _ => 2u32,
LL | | }
| |_____- `match` arms have incompatible types
+ |
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn dog() -> Box<dyn std::fmt::Display> {
+ | ~~~~~~~ +
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL ~ 0 => Box::new(0i32),
+LL ~ 1 => Box::new(1u32),
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | 1 => 1i32,
+ | ~~~
error[E0308]: `if` and `else` have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
| | ^^^^ expected `i32`, found `u32`
LL | | }
| |_____- `if` and `else` have incompatible types
+ |
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn apt() -> Box<dyn std::fmt::Display> {
+ | ~~~~~~~ +
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL ~ Box::new(0i32)
+LL | } else {
+LL ~ Box::new(1u32)
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | 1i32
+ | ~~~
error[E0746]: return type cannot have an unboxed trait object
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
LL | | _ => 2u32,
LL | | }
| |_____- `match` arms have incompatible types
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | 1 => 1i32,
+ | ~~~
error[E0746]: return type cannot have an unboxed trait object
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
| | ^^^^ expected `i32`, found `u32`
LL | | }
| |_____- `if` and `else` have incompatible types
+ |
+help: change the type of the numeric literal from `u32` to `i32`
+ |
+LL | 1i32
+ | ~~~
error[E0746]: return type cannot have an unboxed trait object
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13
--- /dev/null
+// check-pass
+
+pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
+ v.into_iter()
+}
+
+fn main() {}
--- /dev/null
+// Test for a less than ideal interaction of implied bounds and normalization.
+trait Tr {
+ type Ty;
+}
+
+impl<T: 'static> Tr for T {
+ type Ty = &'static T;
+}
+
+// `<&'a u8 as Tr>::Ty` should cause an error because `&'a u8: Tr` doesn't hold for
+// all possible 'a. However, we consider normalized types for implied bounds.
+//
+// We normalize this projection to `&'static &'a u8` and add a nested `&'a u8: 'static`
+// bound. This bound is then proven using the implied bounds for `&'static &'a u8` which
+// we only get by normalizing in the first place.
+fn test<'a>(x: &'a u8, _wf: <&'a u8 as Tr>::Ty) -> &'static u8 { x }
+
+fn main() {
+ // This works as we have 'static references due to promotion.
+ let _: &'static u8 = test(&3, &&3);
+ // This causes an error because the projection requires 'a to be 'static.
+ // It would be unsound if this compiled.
+ let x: u8 = 3;
+ let _: &'static u8 = test(&x, &&3);
+ //~^ ERROR `x` does not live long enough
+
+}
--- /dev/null
+error[E0597]: `x` does not live long enough
+ --> $DIR/assoc-ty-wf-used-to-get-assoc-ty.rs:24:31
+ |
+LL | let _: &'static u8 = test(&x, &&3);
+ | -----^^------
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `x` is borrowed for `'static`
+...
+LL | }
+ | - `x` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
const fn return_ty_mismatch() {
const_eval_select((1,), foo, bar);
- //~^ ERROR type mismatch
+ //~^ ERROR expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
}
const fn args_ty_mismatch() {
LL | G: FnOnce<ARG, Output = RET> + ~const Destruct,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
-error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32`
+error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
--> $DIR/const-eval-select-bad.rs:29:5
|
LL | const_eval_select((1,), foo, bar);
#![crate_name="a"]
#![crate_type = "lib"]
-#![feature(box_syntax)]
-
pub trait i<T>
{
fn dummy(&self, t: T) -> T { panic!() }
pub fn f<T>() -> Box<i<T>+'static> {
impl<T> i<T> for () { }
- box () as Box<i<T>+'static>
+ Box::new(()) as Box<i<T>+'static>
}
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
fn work(_: Box<isize>) {}
fn foo<F:FnOnce()>(_: F) {}
pub fn main() {
- let a = box 1;
+ let a = Box::new(1);
foo(move|| { foo(move|| { work(a) }) })
}
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub fn main() {
fn f() {
}
- let _: Box<fn()> = box (f as fn());
+ let _: Box<fn()> = Box::new(f as fn());
}
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
struct DroppableStruct;
enum DroppableEnum {
fn main() {
{
- let f: Box<_> = box DroppableStruct;
- let _a = Whatever::new(box f as Box<dyn MyTrait>);
+ let f: Box<_> = Box::new(DroppableStruct);
+ let _a = Whatever::new(Box::new(f) as Box<dyn MyTrait>);
}
assert!(unsafe { DROPPED });
unsafe { DROPPED = false; }
{
- let f: Box<_> = box DroppableEnum::DroppableVariant1;
- let _a = Whatever::new(box f as Box<dyn MyTrait>);
+ let f: Box<_> = Box::new(DroppableEnum::DroppableVariant1);
+ let _a = Whatever::new(Box::new(f) as Box<dyn MyTrait>);
}
assert!(unsafe { DROPPED });
}
-#![feature(box_syntax)]
-
struct Foo {
x: isize
}
+
impl Drop for Foo {
fn drop(&mut self) {
println!("drop {}", self.x);
}
}
+
fn main() {
- let mut ptr: Box<_> = box Foo { x: 0 };
+ let mut ptr: Box<_> = Box::new(Foo { x: 0 });
let mut test = |foo: &Foo| {
println!("access {}", foo.x);
- ptr = box Foo { x: ptr.x + 1 };
+ ptr = Box::new(Foo { x: ptr.x + 1 });
println!("access {}", foo.x);
};
test(&*ptr);
LL | let mut test = |foo: &Foo| {
| ----------- mutable borrow occurs here
LL | println!("access {}", foo.x);
-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 | test(&*ptr);
-#![feature(box_syntax)]
-
struct Test {
func: Box<dyn FnMut() + 'static>,
}
+
+
fn main() {
let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
- let test = box Test { func: closure }; //~ ERROR trait upcasting coercion is experimental [E0658]
+ let test = Box::new(Test { func: closure }); //~ ERROR trait upcasting coercion is experimental [E0658]
}
error[E0658]: cannot cast `dyn Fn()` to `dyn FnMut()`, trait upcasting coercion is experimental
- --> $DIR/issue-11515.rs:9:33
+ --> $DIR/issue-11515.rs:9:38
|
-LL | let test = box Test { func: closure };
- | ^^^^^^^
+LL | let test = Box::new(Test { func: closure });
+ | ^^^^^^^
|
= note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
= help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
// run-pass
#![feature(box_patterns)]
-#![feature(box_syntax)]
#[derive(Clone)]
enum Noun
}
pub fn main() {
- fas(&Noun::Cell(box Noun::Atom(2), box Noun::Cell(box Noun::Atom(2), box Noun::Atom(3))));
+ fas(
+ &Noun::Cell(Box::new(Noun::Atom(2)),
+ Box::new(Noun::Cell(Box::new(Noun::Atom(2)), Box::new(Noun::Atom(3)))))
+ );
}
-#![feature(box_syntax)]
-
fn main() {
- let a = Some(box 1);
+ let a = Some(Box::new(1));
match a {
Ok(a) => //~ ERROR: mismatched types
println!("{}",a),
error[E0308]: mismatched types
- --> $DIR/issue-11844.rs:6:9
+ --> $DIR/issue-11844.rs:4:9
|
LL | match a {
| - this expression has type `Option<Box<{integer}>>`
-#![feature(box_syntax, unboxed_closures)]
+#![feature(unboxed_closures)]
fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
fn do_it(x: &isize) { }
fn main() {
- let x: Box<_> = box 22;
+ let x: Box<_> = Box::new(22);
let f = to_fn_once(move|| do_it(&*x));
to_fn_once(move|| {
f();
note: cycle used when collecting item types in top-level module
--> $DIR/issue-12511.rs:1:1
|
-LL | trait T1 : T2 {
- | ^^^^^^^^^^^^^
+LL | / trait T1 : T2 {
+LL | |
+LL | | }
+ | |_^
error: aborting due to previous error
fn misc() {
enum Foo {
- Bar(usize, bool)
+ Bar(#[allow(unused_tuple_struct_fields)] usize, bool)
}
// This test basically mimics how trace_macros! macro is implemented,
// which is a rare combination of vector patterns, multiple wild-card
// run-pass
-#![feature(box_syntax)]
struct StrWrap {
s: String
}
fn equal_to<T: Eq>(expected: T) -> Box<EqualTo<T>> {
- box EqualTo { expected: expected }
+ Box::new(EqualTo { expected: expected })
}
pub fn main() {
// run-pass
#[derive(Debug)]
-struct Matrix4<S>(S);
+struct Matrix4<S>(#[allow(unused_tuple_struct_fields)] S);
trait POrd<S> {}
fn translate<S: POrd<S>>(s: S) -> Matrix4<S> { Matrix4(s) }
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
#[derive(Clone)]
struct B1;
impl A for B1 {}
fn main() {
- let v: Box<_> = box B1;
+ let v: Box<_> = Box::new(B1);
let _c: Box<dyn A> = v.clone();
}
-#![feature(box_syntax)]
-
fn main() {
- let x: Box<isize> = box 0;
+ let x: Box<isize> = Box::new(0);
println!("{}", x + 1);
//~^ ERROR cannot add `{integer}` to `Box<isize>`
error[E0369]: cannot add `{integer}` to `Box<isize>`
- --> $DIR/issue-14915.rs:6:22
+ --> $DIR/issue-14915.rs:4:22
|
LL | println!("{}", x + 1);
| - ^ - {integer}
+++ /dev/null
-const N: isize = 1;
-
-enum Foo {
- //~^ ERROR discriminant value `1` assigned more than once
- //~| ERROR discriminant value `1` assigned more than once
- //~| ERROR discriminant value `1` assigned more than once
- A = 1,
- B = 1,
- C = 0,
- D,
-
- E = N,
-
-}
-
-fn main() {}
+++ /dev/null
-error[E0081]: discriminant value `1` assigned more than once
- --> $DIR/issue-15524.rs:3:1
- |
-LL | enum Foo {
- | ^^^^^^^^
-...
-LL | A = 1,
- | - first assignment of `1`
-LL | B = 1,
- | - second assignment of `1`
-
-error[E0081]: discriminant value `1` assigned more than once
- --> $DIR/issue-15524.rs:3:1
- |
-LL | enum Foo {
- | ^^^^^^^^
-...
-LL | A = 1,
- | - first assignment of `1`
-LL | B = 1,
-LL | C = 0,
- | ----- assigned discriminant for `D` was incremented from this discriminant
-LL | D,
- | - second assignment of `1`
-
-error[E0081]: discriminant value `1` assigned more than once
- --> $DIR/issue-15524.rs:3:1
- |
-LL | enum Foo {
- | ^^^^^^^^
-...
-LL | A = 1,
- | - first assignment of `1`
-...
-LL | E = N,
- | - second assignment of `1`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0081`.
// run-pass
-#![feature(box_syntax)]
fn match_on_local() {
- let mut foo: Option<Box<_>> = Some(box 5);
+ let mut foo: Option<Box<_>> = Some(Box::new(5));
match foo {
None => {},
Some(x) => {
}
fn match_on_upvar() {
- let mut foo: Option<Box<_>> = Some(box 8);
+ let mut foo: Option<Box<_>> = Some(Box::new(8));
let f = move|| {
match foo {
None => {},
fn main() {
match_on_local();
- match_on_arg(Some(box 6));
+ match_on_arg(Some(Box::new(6)));
match_on_binding();
match_on_upvar();
}
// run-pass
#![allow(unreachable_code)]
-#![feature(box_syntax)]
#[derive(PartialEq, Debug)]
struct Bar {
assert_eq!(cc().unwrap(), 3);
assert_eq!(dd().unwrap(), 3);
- let i = box 32isize as Box<dyn A>;
+ let i = Box::new(32isize) as Box<dyn A>;
assert_eq!(i.aaa(), 3);
- let i = box 32isize as Box<dyn A>;
+ let i = Box::new(32isize) as Box<dyn A>;
assert_eq!(i.bbb(), 3);
- let i = box 32isize as Box<dyn A>;
+ let i = Box::new(32isize) as Box<dyn A>;
assert_eq!(i.ccc().unwrap(), 3);
- let i = box 32isize as Box<dyn A>;
+ let i = Box::new(32isize) as Box<dyn A>;
assert_eq!(i.ddd().unwrap(), 3);
}
}
-struct Foo<B: Bar>(B);
+struct Foo<B: Bar>(#[allow(unused_tuple_struct_fields)] B);
impl<B: Bar> Drop for Foo<B> {
fn drop(&mut self) {
// run-pass
-#![feature(box_syntax)]
#![feature(unboxed_closures, fn_traits)]
// Test that unboxing shim for calling rust-call ABI methods through a
}
fn main() {
- let mut f = box Foo { foo: 42 } as Box<dyn FnMut() -> u32>;
+ let mut f = Box::new(Foo { foo: 42 }) as Box<dyn FnMut() -> u32>;
assert_eq!(f.call_mut(()), 42);
- let mut f = box Foo { foo: 40 } as Box<dyn FnMut(u32) -> u32>;
+ let mut f = Box::new(Foo { foo: 40 }) as Box<dyn FnMut(u32) -> u32>;
assert_eq!(f.call_mut((2,)), 42);
- let mut f = box Foo { foo: 40 } as Box<dyn FnMut(u32, u32) -> u32>;
+ let mut f = Box::new(Foo { foo: 40 }) as Box<dyn FnMut(u32, u32) -> u32>;
assert_eq!(f.call_mut((1, 1)), 42);
}
// run-pass
-#![feature(box_syntax)]
#![feature(box_patterns)]
use std::ops::{Deref, DerefMut};
fn main() {
{
- let mut test = X(box 5);
+ let mut test = X(Box::new(5));
{
let mut change = || { *test = 10 };
change();
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
use std::io::{self, Write};
fn f(wr: &mut dyn Write) {
}
fn main() {
- let mut wr = box io::stdout() as Box<dyn Write>;
+ let mut wr = Box::new(io::stdout()) as Box<dyn Write>;
f(&mut wr);
}
// run-pass
#[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
struct Pair<T, V> (T, V);
impl Pair<
// cause compiler to loop. Note that no instances
// of such a type could ever be constructed.
-struct T(Box<T>);
+struct T(#[allow(unused_tuple_struct_fields)] Box<T>);
trait ToStr2 {
fn my_to_string(&self) -> String;
// pretty-expanded FIXME #23616
#![feature(box_patterns)]
-#![feature(box_syntax)]
enum E {
StructVar { boxed: Box<i32> }
fn main() {
// Test matching each shorthand notation for field patterns.
- let mut a = E::StructVar { boxed: box 3 };
+ let mut a = E::StructVar { boxed: Box::new(3) };
match a {
E::StructVar { box boxed } => { }
}
// Test matching non shorthand notation. Recreate a since last test
// moved `boxed`
- let mut a = E::StructVar { boxed: box 3 };
+ let mut a = E::StructVar { boxed: Box::new(3) };
match a {
E::StructVar { boxed: box ref mut num } => { }
}
// run-pass
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
-
trait clam<A> {
fn chowder(&self, y: A);
}
pub fn main() {
let c = foo(42);
- let d: Box<dyn clam<isize>> = box c as Box<dyn clam<isize>>;
+ let d: Box<dyn clam<isize>> = Box::new(c) as Box<dyn clam<isize>>;
f(d, c.x);
}
-#![feature(box_syntax)]
use std::any::Any;
fn main()
{
fn h(x:i32) -> i32 {3*x}
let mut vfnfer:Vec<Box<dyn Any>> = vec![];
- vfnfer.push(box h);
+ vfnfer.push(Box::new(h));
println!("{:?}",(vfnfer[0] as dyn Fn)(3));
//~^ ERROR the precise format of `Fn`-family traits'
//~| ERROR missing generics for trait `Fn`
error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
- --> $DIR/issue-23024.rs:9:39
+ --> $DIR/issue-23024.rs:8:39
|
LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3));
| ^^ help: use parenthetical notation instead: `Fn() -> ()`
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
error[E0107]: missing generics for trait `Fn`
- --> $DIR/issue-23024.rs:9:39
+ --> $DIR/issue-23024.rs:8:39
|
LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3));
| ^^ expected 1 generic argument
| ~~~~~~~~
error[E0191]: the value of the associated type `Output` (from trait `FnOnce`) must be specified
- --> $DIR/issue-23024.rs:9:39
+ --> $DIR/issue-23024.rs:8:39
|
LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3));
| ^^ help: specify the associated type: `Fn<Output = Type>`
// run-pass
#![allow(unused_variables)]
-#![feature(box_syntax)]
-struct Node<T: ?Sized>(T);
+struct Node<T: ?Sized>(#[allow(unused_tuple_struct_fields)] T);
fn main() {
- let x: Box<Node<[isize]>> = box Node([]);
+ let x: Box<Node<[isize]>> = Box::new(Node([]));
}
fn method2();
}
-struct Slice<'a, T: 'a>(&'a [T]);
+struct Slice<'a, T: 'a>(#[allow(unused_tuple_struct_fields)] &'a [T]);
impl<'a, T: 'a> Foo for Slice<'a, T> {
fn method2() {
// ```
macro_rules! impl_drop {
($Bound:ident, $Id:ident) => {
- struct $Id<T: $Bound>(T);
+ struct $Id<T: $Bound>(#[allow(unused_tuple_struct_fields)] T);
unsafe impl <#[may_dangle] T: $Bound> Drop for $Id<T> {
fn drop(&mut self) { }
}
use std::thread;
-struct Foo(i32);
+struct Foo(#[allow(unused_tuple_struct_fields)] i32);
impl Drop for Foo {
fn drop(&mut self) {
trait Device {
type Resources;
}
+#[allow(unused_tuple_struct_fields)]
struct Foo<D, R>(D, R);
impl<D: Device> Foo<D, D::Resources> {
// run-pass
-struct S<T: 'static>(Option<&'static T>);
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
trait Tr { type Out; }
impl<T> Tr for T { type Out = T; }
type Input;
}
-pub struct Iter<P: Parser>(P, P::Input);
+pub struct Iter<P: Parser>(#[allow(unused_tuple_struct_fields)] P, P::Input);
+#[allow(unused_tuple_struct_fields)]
pub struct Map<P, F>(P, F);
impl<P, F> Parser for Map<P, F> where F: FnMut(P) {
type Input = u8;
-struct S<T: 'static>(Option<&'static T>);
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
trait Tr { type Out; }
impl<T> Tr for T { type Out = T; }
// run-pass
trait Tr { type T; }
impl Tr for u8 { type T=(); }
-struct S<I: Tr>(I::T);
+struct S<I: Tr>(#[allow(unused_tuple_struct_fields)] I::T);
fn foo<I: Tr>(i: I::T) {
S::<I>(i);
// run-pass
-struct Parser<'a>(Box<dyn FnMut(Parser) + 'a>);
+struct Parser<'a>(#[allow(unused_tuple_struct_fields)] Box<dyn FnMut(Parser) + 'a>);
fn main() {
let _x = Parser(Box::new(|_|{}));
// run-pass
-struct Wrapper<'a, T: ?Sized>(&'a mut i32, T);
+struct Wrapper<'a, T: ?Sized>(&'a mut i32, #[allow(unused_tuple_struct_fields)] T);
impl<'a, T: ?Sized> Drop for Wrapper<'a, T> {
fn drop(&mut self) {
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
+
struct Font {
fontbuf: usize,
}
pub fn main() {
- let _f: Box<_> = box Font();
+ let _f: Box<_> = Box::new(Font());
}
#![allow(unused_assignments)]
#![allow(unused_variables)]
use std::fmt;
-struct NoisyDrop<T: fmt::Debug>(T);
+struct NoisyDrop<T: fmt::Debug>(#[allow(unused_tuple_struct_fields)] T);
impl<T: fmt::Debug> Drop for NoisyDrop<T> {
fn drop(&mut self) {}
}
-struct Bar<T: fmt::Debug>([*const NoisyDrop<T>; 2]);
+struct Bar<T: fmt::Debug>(#[allow(unused_tuple_struct_fields)] [*const NoisyDrop<T>; 2]);
fn fine() {
let (u,b);
b = Bar([&NoisyDrop(&u), &NoisyDrop(&u)]);
}
+#[allow(unused_tuple_struct_fields)]
struct Bar2<T: fmt::Debug>(*const NoisyDrop<T>, *const NoisyDrop<T>);
fn lolwut() {
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
trait hax {
fn dummy(&self) { }
}
impl<A> hax for A { }
fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> {
- box x as Box<dyn hax+'static>
+ Box::new(x) as Box<dyn hax+'static>
}
fn deadcode() {
- perform_hax(box "deadcode".to_string());
+ perform_hax(Box::new("deadcode".to_string()));
}
pub fn main() {
- let _ = perform_hax(box 42);
+ let _ = perform_hax(Box::new(42));
}
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
trait hax {
fn dummy(&self) { }
}
impl<A> hax for A { }
fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> {
- box x as Box<dyn hax+'static>
+ Box::new(x) as Box<dyn hax+'static>
}
fn deadcode() {
- perform_hax(box "deadcode".to_string());
+ perform_hax(Box::new("deadcode".to_string()));
}
pub fn main() {
- perform_hax(box 42);
+ perform_hax(Box::new(42));
}
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `Clone`
+help: one of the expressions' fields has a method of the same name
+ |
+LL | let _d = c.x.clone();
+ | ++
error: aborting due to previous error
use std::cell::Cell;
-struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+struct Concrete<'a>(#[allow(unused_tuple_struct_fields)] u32, Cell<Option<&'a Concrete<'a>>>);
fn main() {
let mut data = Vec::new();
use std::cell::Cell;
-struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+struct Concrete<'a>(#[allow(unused_tuple_struct_fields)] u32, Cell<Option<&'a Concrete<'a>>>);
struct Foo<T> { data: Vec<T> }
#![feature(dropck_eyepatch)]
use std::cell::Cell;
-struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+struct Concrete<'a>(#[allow(unused_tuple_struct_fields)] u32, Cell<Option<&'a Concrete<'a>>>);
struct Foo<T> { data: Vec<T> }
// run-pass
#![recursion_limit="1024"]
+#![allow(dead_code)]
use std::mem;
#![recursion_limit="1024"]
+#![allow(dead_code)]
pub struct S0<T>(T,T);
pub struct S1<T>(Option<Box<S0<S0<T>>>>,Option<Box<S0<S0<T>>>>);
error[E0283]: type annotations needed
- --> $DIR/issue-29147.rs:21:13
+ --> $DIR/issue-29147.rs:22:13
|
LL | let _ = <S5<_>>::xxx;
| ^^^^^^^^^^^^ cannot infer type for struct `S5<_>`
|
note: multiple `impl`s satisfying `S5<_>: Foo` found
- --> $DIR/issue-29147.rs:17:1
+ --> $DIR/issue-29147.rs:18:1
|
LL | impl Foo for S5<u32> { fn xxx(&self) {} }
| ^^^^^^^^^^^^^^^^^^^^
// run-pass
#![allow(dead_code)]
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
//type t = { a: isize };
// type t = { a: bool };
// let y = box ({a: 4});
// let z = box ({a: 4} as it);
// let z = box ({a: true} as it);
- let z: Box<_> = box (box true as Box<dyn it>);
+ let z: Box<_> = Box::new(Box::new(true) as Box<dyn it>);
// x.f();
// y.f();
// (*z).f();
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
use std::collections::HashMap;
pub fn main() {
let x: Box<_>;
let mut buggy_map: HashMap<usize, &usize> = HashMap::new();
- x = box 1;
+ x = Box::new(1);
buggy_map.insert(42, &*x);
}
pub fn get_tok(it: &mut IntoIter<u8>) {
let mut found_e = false;
- let temp: Vec<u8> = it.take_while(|&x| {
- found_e = true;
- false
- })
+ let temp: Vec<u8> = it
+ .take_while(|&x| {
+ found_e = true;
+ false
+ })
.cloned()
- //~^ ERROR type mismatch resolving
+ //~^ ERROR to be an iterator that yields `&_`, but it yields `u8`
.collect(); //~ ERROR the method
}
-error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_`
- --> $DIR/issue-31173.rs:10:10
+error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>` to be an iterator that yields `&_`, but it yields `u8`
+ --> $DIR/issue-31173.rs:11:10
|
LL | .cloned()
| ^^^^^^ expected reference, found `u8`
LL | Self: Sized + Iterator<Item = &'a T>,
| ^^^^^^^^^^^^ required by this bound in `cloned`
-error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>`, but its trait bounds were not satisfied
- --> $DIR/issue-31173.rs:12:10
+error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>`, but its trait bounds were not satisfied
+ --> $DIR/issue-31173.rs:13:10
|
LL | .collect();
- | ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>` due to unsatisfied trait bounds
+ | ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>` due to unsatisfied trait bounds
|
::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
|
| -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
|
= note: the following trait bounds were not satisfied:
- `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item = &_`
- which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
- `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
- which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
+ `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
+ which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+ `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
+ which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
error: aborting due to 2 previous errors
// run-pass
#![allow(dead_code)]
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
#[derive(Copy, Clone)]
enum side { mayo, catsup, vinegar }
}
pub fn main() {
- foo(box meal::for_here(order::hamburger), true)
+ foo(Box::new(meal::for_here(order::hamburger)), true)
}
const BAZ: Bar = Bar;
#[derive(Debug)]
-struct Foo([Bar; 1]);
+struct Foo(#[allow(unused_tuple_struct_fields)] [Bar; 1]);
struct Biz;
type Back = Vec<T>;
}
-struct PtrBack<T: Front>(Vec<T::Back>);
+struct PtrBack<T: Front>(#[allow(unused_tuple_struct_fields)] Vec<T::Back>);
-struct M(PtrBack<Vec<M>>);
+struct M(#[allow(unused_tuple_struct_fields)] PtrBack<Vec<M>>);
#[allow(unused_must_use)]
fn main() {
// run-pass
-#![feature(box_syntax)]
#![allow(dead_code)]
pub fn main() {
- let mut x: Box<_> = box 3;
+ let mut x: Box<_> = Box::new(3);
x = x;
assert_eq!(*x, 3);
}
use std::collections::HashMap;
fn main() {
- for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
- //~^ ERROR type mismatch
- //~| ERROR type mismatch
+ for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+ //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
+ //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
}
-error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
+error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:36
|
LL | for _ in HashMap::new().iter().cloned() {}
LL | Self: Sized + Iterator<Item = &'a T>,
| ^^^^^^^^^^^^ required by this bound in `cloned`
-error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
+error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
= note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
= note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
-error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_`
+error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14
|
LL | for _ in HashMap::new().iter().cloned() {}
#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
-#![feature(box_syntax)]
use std::cell::RefCell;
next: None
};
- self.next = Some(box RefCell::new(newList));
+ self.next = Some(Box::new(RefCell::new(newList)));
}
}
// run-pass
#[repr(u8)]
enum Foo {
- Foo(u8),
+ Foo(#[allow(unused_tuple_struct_fields)] u8),
}
fn main() {
use std::iter::FusedIterator;
-struct Thing<'a>(&'a str);
+struct Thing<'a>(#[allow(unused_tuple_struct_fields)] &'a str);
impl<'a> Iterator for Thing<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
use std::mem;
const SZ: usize = 100;
+#[allow(unused_tuple_struct_fields)]
struct P<T: ?Sized>([u8; SZ], T);
type Ack<T> = P<P<T>>;
// run-pass
-#![feature(box_syntax)]
#![allow(dead_code)]
trait T {
}
pub fn main() {
- let s: Box<S> = box S { s: 5 };
+ let s: Box<S> = Box::new(S { s: 5 });
print_s(&*s);
let t: Box<dyn T> = s as Box<dyn T>;
print_t(&*t);
// pretty-expanded FIXME #23616
#![allow(path_statements)]
-#![feature(box_syntax)]
pub fn main() {
- let y: Box<_> = box 1;
+ let y: Box<_> = Box::new(1);
y;
}
}
enum Slot<T> {
- Next(usize),
+ Next(#[allow(unused_tuple_struct_fields)] usize),
_Data { _a: T },
}
}
#[derive(Debug)]
-struct Y(isize);
+struct Y(#[allow(unused_tuple_struct_fields)] isize);
#[derive(Debug)]
struct Z<T: X+std::fmt::Debug> {
use std::iter::{Fuse, Cloned};
use std::slice::Iter;
-struct Foo<'a, T: 'a>(&'a T);
+struct Foo<'a, T: 'a>(#[allow(unused_tuple_struct_fields)] &'a T);
impl<'a, T: 'a> Copy for Foo<'a, T> {}
impl<'a, T: 'a> Clone for Foo<'a, T> {
fn clone(&self) -> Self { *self }
// pretty-expanded FIXME #23616
#![allow(non_shorthand_field_patterns)]
-#![feature(box_syntax)]
-
struct T { a: Box<isize> }
trait U {
}
pub fn main() {
- let T { a: a } = T { a: box 0 };
+ let T { a: a } = T { a: Box::new(0) };
a.f();
}
#![feature(box_patterns)]
-#![feature(box_syntax)]
trait MyTrait {
fn dummy(&self) {}
error[E0033]: type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced
- --> $DIR/issue-4972.rs:14:25
+ --> $DIR/issue-4972.rs:13:25
|
LL | TraitWrapper::A(box ref map) => map,
| ^^^^^^^^^^^ type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced
#![feature(box_patterns)]
-#![feature(box_syntax)]
+
enum A { B, C }
#![allow(dead_code)]
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub trait EventLoop {
fn dummy(&self) { }
}
}
pub fn main() {
- let _sched = Scheduler::new(box UvEventLoop::new() as Box<dyn EventLoop>);
+ let _sched = Scheduler::new(Box::new(UvEventLoop::new()) as Box<dyn EventLoop>);
}
// run-pass
// pretty-expanded FIXME #23616
-struct A(bool);
+struct A(#[allow(unused_tuple_struct_fields)] bool);
pub fn main() {
let f = A;
-#![feature(box_syntax)]
-
struct Foo {
foo: isize,
}
impl Bar {
fn make_foo (&self, i: isize) -> Box<Foo> {
- return box Foo { nonexistent: self, foo: i }; //~ ERROR: no field named
+ return Box::new(Foo { nonexistent: self, foo: i }); //~ ERROR: no field named
}
}
error[E0560]: struct `Foo` has no field named `nonexistent`
- --> $DIR/issue-5439.rs:13:26
+ --> $DIR/issue-5439.rs:11:31
|
-LL | return box Foo { nonexistent: self, foo: i };
- | ^^^^^^^^^^^ `Foo` does not have this field
+LL | return Box::new(Foo { nonexistent: self, foo: i });
+ | ^^^^^^^^^^^ `Foo` does not have this field
|
= note: available fields are: `foo`
// run-pass
-#![feature(box_syntax)]
struct Dog {
name : String
pub fn main() {
- let snoopy = box Dog{name: "snoopy".to_string()};
- let bubbles = box Dog{name: "bubbles".to_string()};
+ let snoopy = Box::new(Dog{name: "snoopy".to_string()});
+ let bubbles = Box::new(Dog{name: "bubbles".to_string()});
let barker = [snoopy as Box<dyn Barks>, bubbles as Box<dyn Barks>];
for pup in &barker {
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
struct Element;
macro_rules! foo {
($tag: expr, $string: expr) => {
if $tag == $string {
- let element: Box<_> = box Element;
+ let element: Box<_> = Box::new(Element);
unsafe {
return std::mem::transmute::<_, usize>(element);
}
#![allow(dead_code)]
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub struct Foo {
a: isize,
}
}
fn check(a: Box<Foo>) {
- let _ic = Bar{ b: &*a, a: box None };
+ let _ic = Bar{ b: &*a, a: Box::new(None) };
}
pub fn main(){}
use std::any::type_name;
-struct Bar<M>(M);
+struct Bar<M>(#[allow(unused_tuple_struct_fields)] M);
impl<M> Bar<M> {
fn foo(&self) -> &'static str {
// run-pass
// pretty-expanded FIXME #23616
-#![feature(box_syntax)]
-
pub enum Thing {
A(Box<dyn Foo+'static>)
}
impl Foo for Struct {}
pub fn main() {
- match Thing::A(box Struct as Box<dyn Foo + 'static>) {
+ match Thing::A(Box::new(Struct) as Box<dyn Foo + 'static>) {
Thing::A(_a) => 0,
};
}
// pretty-expanded FIXME #23616
#![feature(box_patterns)]
-#![feature(box_syntax)]
fn foo(box (_x, _y): Box<(isize, isize)>) {}
= note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info)
error: missing type for `const` item
- --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
+ --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20
|
LL | const A = "A".$fn();
- | ^ help: provide a type for the constant: `A: usize`
+ | ^ help: provide a type for the constant: `: usize`
...
LL | / suite! {
LL | | len;
= note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
- --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
+ --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20
|
LL | const A = "A".$fn();
- | ^
- | |
- | not allowed in type signatures
- | help: replace with the correct type: `bool`
+ | ^
+ | |
+ | not allowed in type signatures
+ | help: replace with the correct type: `bool`
...
LL | / suite! {
LL | | len;
-#![feature(box_syntax)]
-
use std::cell::RefCell;
use std::rc::Rc;
}
fn main() {
- let a = A {v: box B{v: None} as Box<dyn Foo + Send>};
+ let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>};
//~^ ERROR `Rc<RefCell<A>>` cannot be sent between threads safely
}
error[E0277]: `Rc<RefCell<A>>` cannot be sent between threads safely
- --> $DIR/issue-7013.rs:26:19
+ --> $DIR/issue-7013.rs:24:19
|
-LL | let a = A {v: box B{v: None} as Box<dyn Foo + Send>};
- | ^^^^^^^^^^^^^^ `Rc<RefCell<A>>` cannot be sent between threads safely
+LL | let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>};
+ | ^^^^^^^^^^^^^^^^^^^^ `Rc<RefCell<A>>` cannot be sent between threads safely
|
= help: within `B`, the trait `Send` is not implemented for `Rc<RefCell<A>>`
= note: required because it appears within the type `Option<Rc<RefCell<A>>>`
note: required because it appears within the type `B`
- --> $DIR/issue-7013.rs:10:8
+ --> $DIR/issue-7013.rs:8:8
|
LL | struct B {
| ^
-#![feature(box_syntax)]
-
use std::cell::RefCell;
// Regression test for issue 7364
-static boxed: Box<RefCell<isize>> = box RefCell::new(0);
+static boxed: Box<RefCell<isize>> = Box::new(RefCell::new(0));
//~^ ERROR `RefCell<isize>` cannot be shared between threads safely [E0277]
fn main() { }
error[E0277]: `RefCell<isize>` cannot be shared between threads safely
- --> $DIR/issue-7364.rs:6:15
+ --> $DIR/issue-7364.rs:4:15
|
-LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0);
+LL | static boxed: Box<RefCell<isize>> = Box::new(RefCell::new(0));
| ^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `RefCell<isize>`
*/
-#![feature(box_syntax)]
-
pub fn main() {}
trait A {
impl<T: 'static> A for T {}
fn owned2<T: 'static>(a: Box<T>) { a as Box<dyn A>; }
-fn owned3<T: 'static>(a: Box<T>) { box a as Box<dyn A>; }
+fn owned3<T: 'static>(a: Box<T>) { Box::new(a) as Box<dyn A>; }
trait FooBar {
fn dummy(&self) { }
}
-struct Bar(i32);
+struct Bar(#[allow(unused_tuple_struct_fields)] i32);
struct Foo { bar: Bar }
impl FooBar for Bar {}
#![allow(non_snake_case)]
// ignore-pretty unreported
-#![feature(box_syntax)]
-
pub trait bomb { fn boom(&self, _: Ident); }
pub struct S;
impl bomb for S { fn boom(&self, _: Ident) { } }
}
pub fn main() {
- let b = box S as Box<dyn bomb>;
+ let b = Box::new(S) as Box<dyn bomb>;
light_fuse(b);
}
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
// Tests for a previous bug that occurred due to an interaction
// between struct field initialization and the auto-coercion
pub fn main() {
let _t1_fixed = Thing1 {
baz: &[],
- bar: box 32,
+ bar: Box::new(32),
};
Thing1 {
baz: &Vec::new(),
- bar: box 32,
+ bar: Box::new(32),
};
let _t2_fixed = Thing2 {
baz: &[],
--- /dev/null
+// run-pass
+#![feature(bench_black_box)]
+use std::hint;
+
+struct U16(u16);
+
+impl Drop for U16 {
+ fn drop(&mut self) {
+ // Prevent LLVM from optimizing away our alignment check.
+ assert!(hint::black_box(self as *mut U16 as usize) % 2 == 0);
+ }
+}
+
+struct HasDrop;
+
+impl Drop for HasDrop {
+ fn drop(&mut self) {}
+}
+
+struct Wrapper {
+ _a: U16,
+ b: HasDrop,
+}
+
+#[repr(packed)]
+struct Misalign(u8, Wrapper);
+
+fn main() {
+ let m = Misalign(
+ 0,
+ Wrapper {
+ _a: U16(10),
+ b: HasDrop,
+ },
+ );
+ // Put it somewhere definitely even (so the `a` field is definitely at an odd address).
+ let m: ([u16; 0], Misalign) = ([], m);
+ // Move out one field, so we run custom per-field drop logic below.
+ let _x = m.1.1.b;
+}
+++ /dev/null
-// compile-flags: --json=artifacts --error-format=json --color never
-
-fn main() {}
+++ /dev/null
-error: cannot specify the `--color` option with `--json`
-
+++ /dev/null
-// compile-flags: --json=artifacts --error-format=short
-
-fn main() {}
+++ /dev/null
-error: using `--json` requires also using `--error-format=json`
-
+++ /dev/null
-// (This line has BOM so it's ignored by compiletest for directives)\r
-//\r
-// ignore-test Not a test. Used by other tests\r
-// ignore-tidy-cr\r
-\r
-// For easier verifying, the byte offsets in this file should match those\r
-// in the json-bom-plus-crlf.rs - given the actual fn is identical (just with\r
-// a different, but equally sized name), the easiest way to do this is to\r
-// ensure the two files are of equal size on disk.\r
-// Padding............................\r
-\r
-// N.B., this file needs CRLF line endings. The .gitattributes file in\r
-// this directory should enforce it.\r
-\r
-pub fn test() {\r
-\r
- let s : String = 1; // Error in the middle of line.\r
-\r
- let s : String = 1\r
- ; // Error before the newline.\r
-\r
- let s : String =\r
-1; // Error after the newline.\r
-\r
- let s : String = (\r
- ); // Error spanning the newline.\r
-}\r
+++ /dev/null
-// (This line has BOM so it's ignored by compiletest for directives)\r
-//\r
-// compile-flags: --json=diagnostic-short --error-format=json\r
-// ignore-tidy-cr\r
-\r
-#[path = "json-bom-plus-crlf-multifile-aux.rs"]\r
-mod json_bom_plus_crlf_multifile_aux;\r
-\r
-fn main() {\r
- json_bom_plus_crlf_multifile_aux::test();\r
-}\r
+++ /dev/null
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
- x + 1
-}
-
-plus_one(\"Not a number\");
-// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
-// |
-// expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":622,"byte_end":622,"line_start":17,"line_end":17,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
- x + 1
-}
-
-plus_one(\"Not a number\");
-// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
-// |
-// expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":682,"byte_end":682,"line_start":19,"line_end":19,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
- x + 1
-}
-
-plus_one(\"Not a number\");
-// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
-// |
-// expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":746,"byte_end":746,"line_start":23,"line_end":23,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
- x + 1
-}
-
-plus_one(\"Not a number\");
-// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
-// |
-// expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types
-"}
-{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
-"}
+++ /dev/null
-// (This line has BOM so it's ignored by compiletest for directives)\r
-//\r
-// compile-flags: --json=diagnostic-short --error-format=json\r
-// ignore-tidy-cr\r
-\r
-// For easier verifying, the byte offsets in this file should match those\r
-// in the json_bom_plus_crlf_multifile_aux.rs - given the actual fn is\r
-// identical (just with a different, but equally sized name), the easiest way\r
-// to do this is to ensure the two files are of equal size on disk.\r
-\r
-// N.B., this file needs CRLF line endings. The .gitattributes file in\r
-// this directory should enforce it.\r
-\r
-fn main() {\r
-\r
- let s : String = 1; // Error in the middle of line.\r
-\r
- let s : String = 1\r
- ; // Error before the newline.\r
-\r
- let s : String =\r
-1; // Error after the newline.\r
-\r
- let s : String = (\r
- ); // Error spanning the newline.\r
-}\r
+++ /dev/null
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
- x + 1
-}
-
-plus_one(\"Not a number\");
-// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
-// |
-// expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":607,"byte_end":607,"line_start":16,"line_end":16,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
- x + 1
-}
-
-plus_one(\"Not a number\");
-// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
-// |
-// expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":667,"byte_end":667,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
- x + 1
-}
-
-plus_one(\"Not a number\");
-// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
-// |
-// expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":731,"byte_end":731,"line_start":22,"line_end":22,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types
-"}
-{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
-
-Erroneous code examples:
-
-```compile_fail,E0308
-fn plus_one(x: i32) -> i32 {
- x + 1
-}
-
-plus_one(\"Not a number\");
-// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
-
-if \"Not a bool\" {
-// ^^^^^^^^^^^^ expected `bool`, found `&str`
-}
-
-let x: f32 = \"Not a float\";
-// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
-// |
-// expected due to this
-```
-
-This error occurs when an expression was used in a place where the compiler
-expected an expression of a different type. It can occur in several cases, the
-most common being when calling a function and passing an argument which has a
-different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types
-"}
-{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
-"}
+++ /dev/null
-// compile-flags: --json=foo --error-format=json
-
-fn main() {}
+++ /dev/null
-error: unknown `--json` option `foo`
-
+++ /dev/null
-{"artifact":"$TEST_BUILD_DIR/json-multiple.polonius/libjson_multiple.rlib","emit":"link"}
+++ /dev/null
-// build-pass
-// ignore-pass (different metadata emitted in different modes)
-// compile-flags: --json=diagnostic-short --json artifacts --error-format=json
-
-#![crate_type = "lib"]
+++ /dev/null
-{"artifact":"$TEST_BUILD_DIR/json-multiple/libjson_multiple.rlib","emit":"link"}
+++ /dev/null
-{"artifact":"$TEST_BUILD_DIR/json-options.polonius/libjson_options.rlib","emit":"link"}
+++ /dev/null
-// build-pass
-// ignore-pass (different metadata emitted in different modes)
-// compile-flags: --json=diagnostic-short,artifacts --error-format=json
-
-#![crate_type = "lib"]
+++ /dev/null
-{"artifact":"$TEST_BUILD_DIR/json-options/libjson_options.rlib","emit":"link"}
+++ /dev/null
-// compile-flags: --json=diagnostic-short --error-format=json
+++ /dev/null
-{"message":"`main` function not found in crate `json_short`","code":{"code":"E0601","explanation":"No `main` function was found in a binary crate.
-
-To fix this error, add a `main` function:
-
-```
-fn main() {
- // Your program will start here.
- println!(\"Hello world!\");
-}
-```
-
-If you don't know the basics of Rust, you can look at the
-[Rust Book][rust-book] to get started.
-
-[rust-book]: https://doc.rust-lang.org/book/
-"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":62,"byte_end":62,"line_start":1,"line_end":1,"column_start":63,"column_end":63,"is_primary":true,"text":[{"text":"// compile-flags: --json=diagnostic-short --error-format=json","highlight_start":63,"highlight_end":63}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:1:63: error[E0601]: `main` function not found in crate `json_short`
-"}
-{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
-"}
--- /dev/null
+// compile-flags: --json=artifacts --error-format=json --color never
+
+fn main() {}
--- /dev/null
+error: cannot specify the `--color` option with `--json`
+
--- /dev/null
+// compile-flags: --json=artifacts --error-format=short
+
+fn main() {}
--- /dev/null
+error: using `--json` requires also using `--error-format=json`
+
--- /dev/null
+// (This line has BOM so it's ignored by compiletest for directives)\r
+//\r
+// ignore-test Not a test. Used by other tests\r
+// ignore-tidy-cr\r
+\r
+// For easier verifying, the byte offsets in this file should match those\r
+// in the json-bom-plus-crlf.rs - given the actual fn is identical (just with\r
+// a different, but equally sized name), the easiest way to do this is to\r
+// ensure the two files are of equal size on disk.\r
+// Padding............................\r
+\r
+// N.B., this file needs CRLF line endings. The .gitattributes file in\r
+// this directory should enforce it.\r
+\r
+pub fn test() {\r
+\r
+ let s : String = 1; // Error in the middle of line.\r
+\r
+ let s : String = 1\r
+ ; // Error before the newline.\r
+\r
+ let s : String =\r
+1; // Error after the newline.\r
+\r
+ let s : String = (\r
+ ); // Error spanning the newline.\r
+}\r
--- /dev/null
+// (This line has BOM so it's ignored by compiletest for directives)\r
+//\r
+// compile-flags: --json=diagnostic-short --error-format=json\r
+// ignore-tidy-cr\r
+\r
+#[path = "json-bom-plus-crlf-multifile-aux.rs"]\r
+mod json_bom_plus_crlf_multifile_aux;\r
+\r
+fn main() {\r
+ json_bom_plus_crlf_multifile_aux::test();\r
+}\r
--- /dev/null
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+ x + 1
+}
+
+plus_one(\"Not a number\");
+// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
+// |
+// expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":622,"byte_end":622,"line_start":17,"line_end":17,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+ x + 1
+}
+
+plus_one(\"Not a number\");
+// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
+// |
+// expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":682,"byte_end":682,"line_start":19,"line_end":19,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+ x + 1
+}
+
+plus_one(\"Not a number\");
+// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
+// |
+// expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":746,"byte_end":746,"line_start":23,"line_end":23,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+ x + 1
+}
+
+plus_one(\"Not a number\");
+// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
+// |
+// expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types
+"}
+{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
+"}
--- /dev/null
+// (This line has BOM so it's ignored by compiletest for directives)\r
+//\r
+// compile-flags: --json=diagnostic-short --error-format=json\r
+// ignore-tidy-cr\r
+\r
+// For easier verifying, the byte offsets in this file should match those\r
+// in the json_bom_plus_crlf_multifile_aux.rs - given the actual fn is\r
+// identical (just with a different, but equally sized name), the easiest way\r
+// to do this is to ensure the two files are of equal size on disk.\r
+\r
+// N.B., this file needs CRLF line endings. The .gitattributes file in\r
+// this directory should enforce it.\r
+\r
+fn main() {\r
+\r
+ let s : String = 1; // Error in the middle of line.\r
+\r
+ let s : String = 1\r
+ ; // Error before the newline.\r
+\r
+ let s : String =\r
+1; // Error after the newline.\r
+\r
+ let s : String = (\r
+ ); // Error spanning the newline.\r
+}\r
--- /dev/null
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+ x + 1
+}
+
+plus_one(\"Not a number\");
+// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
+// |
+// expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":607,"byte_end":607,"line_start":16,"line_end":16,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+ x + 1
+}
+
+plus_one(\"Not a number\");
+// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
+// |
+// expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":667,"byte_end":667,"line_start":18,"line_end":18,"column_start":23,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":23,"highlight_end":23}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+ x + 1
+}
+
+plus_one(\"Not a number\");
+// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
+// |
+// expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":731,"byte_end":731,"line_start":22,"line_end":22,"column_start":2,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":2,"highlight_end":2}],"label":null,"suggested_replacement":".to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types
+"}
+{"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type.
+
+Erroneous code examples:
+
+```compile_fail,E0308
+fn plus_one(x: i32) -> i32 {
+ x + 1
+}
+
+plus_one(\"Not a number\");
+// ^^^^^^^^^^^^^^ expected `i32`, found `&str`
+
+if \"Not a bool\" {
+// ^^^^^^^^^^^^ expected `bool`, found `&str`
+}
+
+let x: f32 = \"Not a float\";
+// --- ^^^^^^^^^^^^^ expected `f32`, found `&str`
+// |
+// expected due to this
+```
+
+This error occurs when an expression was used in a place where the compiler
+expected an expression of a different type. It can occur in several cases, the
+most common being when calling a function and passing an argument which has a
+different type than the matching type in the function declaration.
+"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types
+"}
+{"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors
+"}
--- /dev/null
+// compile-flags: --json=foo --error-format=json
+
+fn main() {}
--- /dev/null
+error: unknown `--json` option `foo`
+
--- /dev/null
+{"artifact":"$TEST_BUILD_DIR/json-multiple.polonius/libjson_multiple.rlib","emit":"link"}
--- /dev/null
+// build-pass
+// ignore-pass (different metadata emitted in different modes)
+// compile-flags: --json=diagnostic-short --json artifacts --error-format=json
+
+#![crate_type = "lib"]
--- /dev/null
+{"artifact":"$TEST_BUILD_DIR/json/json-multiple/libjson_multiple.rlib","emit":"link"}
--- /dev/null
+{"artifact":"$TEST_BUILD_DIR/json-options.polonius/libjson_options.rlib","emit":"link"}
--- /dev/null
+// build-pass
+// ignore-pass (different metadata emitted in different modes)
+// compile-flags: --json=diagnostic-short,artifacts --error-format=json
+
+#![crate_type = "lib"]
--- /dev/null
+{"artifact":"$TEST_BUILD_DIR/json/json-options/libjson_options.rlib","emit":"link"}
--- /dev/null
+// compile-flags: --json=diagnostic-short --error-format=json
--- /dev/null
+{"message":"`main` function not found in crate `json_short`","code":{"code":"E0601","explanation":"No `main` function was found in a binary crate.
+
+To fix this error, add a `main` function:
+
+```
+fn main() {
+ // Your program will start here.
+ println!(\"Hello world!\");
+}
+```
+
+If you don't know the basics of Rust, you can look at the
+[Rust Book][rust-book] to get started.
+
+[rust-book]: https://doc.rust-lang.org/book/
+"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":62,"byte_end":62,"line_start":1,"line_end":1,"column_start":63,"column_end":63,"is_primary":true,"text":[{"text":"// compile-flags: --json=diagnostic-short --error-format=json","highlight_start":63,"highlight_end":63}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:1:63: error[E0601]: `main` function not found in crate `json_short`
+"}
+{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
+"}
use std::num::NonZeroU32 as N32;
use std::sync::{Mutex, RwLock};
-struct Wrapper<T>(T);
+struct Wrapper<T>(#[allow(unused_tuple_struct_fields)] T);
#[repr(transparent)]
-struct Transparent<T>(T);
+struct Transparent<T>(#[allow(unused_tuple_struct_fields)] T);
struct NoNiche<T>(UnsafeCell<T>);
--- /dev/null
+// edition:2021
+// check-pass
+
+#![feature(try_blocks)]
+#![feature(let_else)]
+
+fn main() {
+ let _: Result<i32, i32> = try {
+ let Some(x) = Some(0) else {
+ Err(1)?
+ };
+
+ x
+ };
+}
--- /dev/null
+// check-pass
+
+struct Sqlite {}
+
+trait HasArguments<'q> {
+ type Arguments;
+}
+
+impl<'q> HasArguments<'q> for Sqlite {
+ type Arguments = std::marker::PhantomData<&'q ()>;
+}
+
+fn foo() {
+ let _ = <Sqlite as HasArguments>::Arguments::default();
+}
+
+fn main() {}
--- /dev/null
+// Verify that we do not ICE when the user uses a multubyte ampersand.
+
+fn f(_: &&()) -> &() { todo!() }
+//~^ ERROR unknown start of token: \u{ff06}
+//~| ERROR missing lifetime specifier [E0106]
+
+fn main() {}
--- /dev/null
+error: unknown start of token: \u{ff06}
+ --> $DIR/fullwidth-ampersand.rs:3:10
+ |
+LL | fn f(_: &&()) -> &() { todo!() }
+ | ^^
+ |
+help: Unicode character '&' (Fullwidth Ampersand) looks like '&' (Ampersand), but it is not
+ |
+LL | fn f(_: &&()) -> &() { todo!() }
+ | ~
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/fullwidth-ampersand.rs:3:18
+ |
+LL | fn f(_: &&()) -> &() { todo!() }
+ | ----- ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+ |
+LL | fn f<'a>(_: &'a &'a ()) -> &'a () { todo!() }
+ | ++++ ++ ++ ++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> ""
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
-#![feature(box_syntax)]
-
#[cfg(target_pointer_width = "64")]
fn main() {
let n = 0_usize;
- let a: Box<_> = box [&n; 0xF000000000000000_usize];
+ let a: Box<_> = Box::new([&n; 0xF000000000000000_usize]);
println!("{}", a[0xFFFFFF_usize]);
}
#[cfg(target_pointer_width = "32")]
fn main() {
let n = 0_usize;
- let a: Box<_> = box [&n; 0xFFFFFFFF_usize];
+ let a: Box<_> = Box::new([&n; 0xFFFFFFFF_usize]);
println!("{}", a[0xFFFFFF_usize]);
}
-// check-pass
+#![deny(unused_tuple_struct_fields)]
+//~^ NOTE: the lint level is defined here
-#![deny(dead_code)]
+use std::marker::PhantomData;
const LEN: usize = 4;
-#[derive(Debug)]
-struct Wrapper([u8; LEN]);
+struct SingleUnused(i32, [u8; LEN], String);
+//~^ ERROR: field `1` is never read
+//~| NOTE: field in this struct
+//~| HELP: consider changing the field to be of unit type
+
+struct MultipleUnused(i32, f32, String, u8);
+//~^ ERROR: fields `0`, `1`, `2` and `3` are never read
+//~| NOTE: fields in this struct
+//~| HELP: consider changing the fields to be of unit type
+
+struct GoodUnit(());
+
+struct GoodPhantom(PhantomData<i32>);
+
+struct Void;
+struct GoodVoid(Void);
fn main() {
- println!("{:?}", Wrapper([0, 1, 2, 3]));
+ let w = SingleUnused(42, [0, 1, 2, 3], "abc".to_string());
+ let _ = w.0;
+ let _ = w.2;
+
+ let m = MultipleUnused(42, 3.14, "def".to_string(), 4u8);
+
+ let gu = GoodUnit(());
+ let gp = GoodPhantom(PhantomData);
+ let gv = GoodVoid(Void);
+
+ let _ = (gu, gp, gv, m);
}
--- /dev/null
+error: field `1` is never read
+ --> $DIR/tuple-struct-field.rs:8:26
+ |
+LL | struct SingleUnused(i32, [u8; LEN], String);
+ | ------------ ^^^^^^^^^
+ | |
+ | field in this struct
+ |
+note: the lint level is defined here
+ --> $DIR/tuple-struct-field.rs:1:9
+ |
+LL | #![deny(unused_tuple_struct_fields)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
+ |
+LL | struct SingleUnused(i32, (), String);
+ | ~~
+
+error: fields `0`, `1`, `2` and `3` are never read
+ --> $DIR/tuple-struct-field.rs:13:23
+ |
+LL | struct MultipleUnused(i32, f32, String, u8);
+ | -------------- ^^^ ^^^ ^^^^^^ ^^
+ | |
+ | fields in this struct
+ |
+help: consider changing the fields to be of unit type to suppress this warning while preserving the field numbering, or remove the fields
+ |
+LL | struct MultipleUnused((), (), (), ());
+ | ~~ ~~ ~~ ~~
+
+error: aborting due to 2 previous errors
+
#![deny(dead_code)]
-pub struct GenericFoo<T>(T);
+pub struct GenericFoo<T>(#[allow(unused_tuple_struct_fields)] T);
type Foo = GenericFoo<u32>;
--- /dev/null
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![allow(private_in_public)]
+
+pub type Successors<'a> = impl Iterator<Item = &'a ()>;
+
+pub fn f<'a>() -> Successors<'a> {
+ None.into_iter()
+}
+
+trait Tr {
+ type Item;
+}
+
+impl<'a> Tr for &'a () {
+ type Item = Successors<'a>;
+}
+
+pub fn ohno<'a>() -> <&'a () as Tr>::Item {
+ None.into_iter()
+}
+
+fn main() {}
let _ = &packed2.y; // ok, has align 2 in packed(2) struct
let _ = &packed2.z; // ok, has align 1
}
+
+ unsafe {
+ struct U16(u16);
+
+ impl Drop for U16 {
+ fn drop(&mut self) {
+ println!("{:p}", self);
+ }
+ }
+
+ struct HasDrop;
+
+ impl Drop for HasDrop {
+ fn drop(&mut self) {}
+ }
+
+ #[allow(unused)]
+ struct Wrapper {
+ a: U16,
+ b: HasDrop,
+ }
+ #[allow(unused)]
+ #[repr(packed(2))]
+ struct Wrapper2 {
+ a: U16,
+ b: HasDrop,
+ }
+
+ // An outer struct with more restrictive packing than the inner struct -- make sure we
+ // notice that!
+ #[repr(packed)]
+ struct Misalign<T>(u8, T);
+
+ let m1 = Misalign(
+ 0,
+ Wrapper {
+ a: U16(10),
+ b: HasDrop,
+ },
+ );
+ let _ref = &m1.1.a; //~ ERROR reference to packed field
+ //~^ previously accepted
+
+ let m2 = Misalign(
+ 0,
+ Wrapper2 {
+ a: U16(10),
+ b: HasDrop,
+ },
+ );
+ let _ref = &m2.1.a; //~ ERROR reference to packed field
+ //~^ previously accepted
+ }
}
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
-error: aborting due to 7 previous errors
+error: reference to packed field is unaligned
+ --> $DIR/unaligned_references.rs:90:20
+ |
+LL | let _ref = &m1.1.a;
+ | ^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+ = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error: reference to packed field is unaligned
+ --> $DIR/unaligned_references.rs:100:20
+ |
+LL | let _ref = &m2.1.a;
+ | ^^^^^^^
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+ = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error: aborting due to 9 previous errors
Future incompatibility report: Future breakage diagnostic:
error: reference to packed field is unaligned
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+Future breakage diagnostic:
+error: reference to packed field is unaligned
+ --> $DIR/unaligned_references.rs:90:20
+ |
+LL | let _ref = &m1.1.a;
+ | ^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/unaligned_references.rs:1:9
+ |
+LL | #![deny(unaligned_references)]
+ | ^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+ = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+Future breakage diagnostic:
+error: reference to packed field is unaligned
+ --> $DIR/unaligned_references.rs:100:20
+ |
+LL | let _ref = &m2.1.a;
+ | ^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/unaligned_references.rs:1:9
+ |
+LL | #![deny(unaligned_references)]
+ | ^^^^^^^^^^^^^^^^^^^^
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+ = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:8:5
+ --> $DIR/unreachable_pub.rs:8:13
|
LL | pub use std::fmt;
- | ---^^^^^^^^^^^^^^
+ | --- ^^^^^^^^
| |
| help: consider restricting its visibility: `pub(crate)`
|
--> $DIR/unreachable_pub.rs:33:5
|
LL | pub const CARBON: usize = 1;
- | ---^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ---^^^^^^^^^^^^^^^^^^^^
| |
| help: consider restricting its visibility: `pub(crate)`
|
--> $DIR/unreachable_pub.rs:34:5
|
LL | pub static NITROGEN: usize = 2;
- | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ---^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: consider restricting its visibility: `pub(crate)`
|
--> $DIR/unreachable_pub.rs:35:5
|
LL | pub type Oxygen = bool;
- | ---^^^^^^^^^^^^^^^^^^^^
+ | ---^^^^^^^^^^^^
| |
| help: consider restricting its visibility: `pub(crate)`
|
--> $DIR/unreachable_pub.rs:38:47
|
LL | ($visibility: vis, $name: ident) => { $visibility struct $name {} }
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | define_empty_struct_with_visibility!(pub, Fluorine);
| ---------------------------------------------------
--> $DIR/unreachable_pub.rs:44:9
|
LL | pub fn catalyze() -> bool;
- | ---^^^^^^^^^^^^^^^^^^^^^^^
+ | ---^^^^^^^^^^^^^^^^^^^^^^
| |
| help: consider restricting its visibility: `pub(crate)`
|
--- /dev/null
+#[deny(unused)]
+pub fn broken(x: Option<()>) -> i32 {
+ match x {
+ Some(()) => (1), //~ ERROR unnecessary parentheses around match arm expression
+ None => (2), //~ ERROR unnecessary parentheses around match arm expression
+ }
+}
+
+fn main() { }
--- /dev/null
+error: unnecessary parentheses around match arm expression
+ --> $DIR/issue-92751.rs:4:21
+ |
+LL | Some(()) => (1),
+ | ^ ^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-92751.rs:1:8
+ |
+LL | #[deny(unused)]
+ | ^^^^^^
+ = note: `#[deny(unused_parens)]` implied by `#[deny(unused)]`
+help: remove these parentheses
+ |
+LL - Some(()) => (1),
+LL + Some(()) => 1,
+ |
+
+error: unnecessary parentheses around match arm expression
+ --> $DIR/issue-92751.rs:5:17
+ |
+LL | None => (2),
+ | ^ ^
+ |
+help: remove these parentheses
+ |
+LL - None => (2),
+LL + None => 2,
+ |
+
+error: aborting due to 2 previous errors
+
LL | #[must_use]
| ^^^^^^^^^^^
-error: `#[must_use]` has no effect when applied to an item
+error: `#[must_use]` has no effect when applied to an implementation block
--> $DIR/unused_attributes-must_use.rs:33:1
|
LL | #[must_use]
LL | fn qux<#[must_use] T>(_: T) {}
| ^^^^^^^^^^^
-error: `#[must_use]` has no effect when applied to an item
+error: `#[must_use]` has no effect when applied to an implementation block
--> $DIR/unused_attributes-must_use.rs:79:1
|
LL | #[must_use]
--- /dev/null
+// ignore-tidy-trailing-newlines
+//
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: format argument must be a string literal
+//
+// Verify that unused parens lint does not try to create a span
+// which points in the middle of a multibyte character.
+
+fn f(){(print!(á
\ No newline at end of file
--- /dev/null
+error: this file contains an unclosed delimiter
+ --> $DIR/unused_parens_multibyte_recovery.rs:11:17
+ |
+LL | fn f(){(print!(á
+ | -- - ^
+ | || |
+ | || unclosed delimiter
+ | |unclosed delimiter
+ | unclosed delimiter
+
+error: this file contains an unclosed delimiter
+ --> $DIR/unused_parens_multibyte_recovery.rs:11:17
+ |
+LL | fn f(){(print!(á
+ | -- - ^
+ | || |
+ | || unclosed delimiter
+ | |unclosed delimiter
+ | unclosed delimiter
+
+error: this file contains an unclosed delimiter
+ --> $DIR/unused_parens_multibyte_recovery.rs:11:17
+ |
+LL | fn f(){(print!(á
+ | -- - ^
+ | || |
+ | || unclosed delimiter
+ | |unclosed delimiter
+ | unclosed delimiter
+
+error: format argument must be a string literal
+ --> $DIR/unused_parens_multibyte_recovery.rs:11:16
+ |
+LL | fn f(){(print!(á
+ | ^
+ |
+help: you might be missing a string literal to format with
+ |
+LL | fn f(){(print!("{}", á
+ | +++++
+
+error: aborting due to 4 previous errors
+
#![allow(non_camel_case_types)]
// pretty-expanded FIXME #23616
-enum list { cons(isize, Box<list>), nil, }
+enum list { #[allow(unused_tuple_struct_fields)] cons(isize, Box<list>), nil, }
pub fn main() {
list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil))))));
--- /dev/null
+// run-pass
+
+// Test that this doesn't abort during AST lowering. In #96847 it did abort
+// because the attribute was being lowered twice.
+
+#![feature(stmt_expr_attributes)]
+#![feature(lang_items)]
+
+fn main() {
+ for _ in [1,2,3] {
+ #![lang="foo"]
+ println!("foo");
+ }
+}
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, Ident, Span, TokenStream, TokenTree};
+
+#[proc_macro_attribute]
+pub fn struct_with_bound(_: TokenStream, _: TokenStream) -> TokenStream {
+ let crate_ident = TokenTree::Ident(Ident::new("crate", Span::call_site()));
+ let trait_ident = TokenTree::Ident(Ident::new("MyTrait", Span::call_site()));
+ quote!(
+ struct Foo<T: $crate_ident::$trait_ident> {}
+ )
+}
);
}
+#[allow(unused_tuple_struct_fields)]
enum HTMLFragment {
tag(String, Vec<HTMLFragment> ),
text(String),
--- /dev/null
+#[issue_100199::struct_with_bound] //~ ERROR cannot find trait `MyTrait` in the crate root
+struct Foo {}
+// The above must be on the first line so that it's span points to pos 0.
+// This used to trigger an ICE because the diagnostic emitter would get
+// an unexpected dummy span (lo == 0 == hi) while attempting to print a
+// suggestion.
+
+// aux-build: issue-100199.rs
+
+extern crate issue_100199;
+
+mod traits {
+ pub trait MyTrait {}
+}
+
+fn main() {}
--- /dev/null
+error[E0405]: cannot find trait `MyTrait` in the crate root
+ --> $DIR/issue-100199.rs:1:1
+ |
+LL | #[issue_100199::struct_with_bound]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in the crate root
+ |
+ = note: this error originates in the attribute macro `issue_100199::struct_with_bound` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider importing this trait
+ |
+LL | use traits::MyTrait;
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0405`.
--> $DIR/issue-98466.rs:7:26
|
LL | println!("_x is {}", _x = 5);
- | - ^^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `_x` by position
+ | -- ^^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `_x` by position
|
= note: `#[warn(named_arguments_used_positionally)]` on by default
help: use the named argument by name to avoid ambiguity
--> $DIR/issue-98466.rs:10:26
|
LL | println!("_x is {}", y = _x);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `y` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `y` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-98466.rs:13:83
|
LL | println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `y` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `y` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-98466.rs:19:34
|
LL | let _f = format!("_x is {}", _x = 5);
- | - ^^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `_x` by position
+ | -- ^^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `_x` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-98466.rs:22:34
|
LL | let _f = format!("_x is {}", y = _x);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `y` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `y` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-98466.rs:25:91
|
LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `y` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `y` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:5:24
|
LL | println!("{b} {}", a=1, b=2);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `a` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `a` by position
|
= note: `#[warn(named_arguments_used_positionally)]` on by default
help: use the named argument by name to avoid ambiguity
--> $DIR/issue-99265.rs:9:35
|
LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `a` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `a` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:9:40
|
LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `b` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `b` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:9:45
|
LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `c` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `c` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:9:50
|
LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `d` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `d` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:19:35
|
LL | println!("Hello {:1$}!", "x", width = 5);
- | -- ^^^^^ this named argument is only referred to by position in formatting string
+ | -- ^^^^^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `width$` by position
+ | this formatting argument uses named argument `width` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:23:46
|
LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
- | -- ^^^^^ this named argument is only referred to by position in formatting string
+ | -- ^^^^^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `width$` by position
+ | this formatting argument uses named argument `width` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:23:57
|
LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
- | -- ^^^^^^^^^ this named argument is only referred to by position in formatting string
+ | -- ^^^^^^^^^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `precision$` by position
+ | this formatting argument uses named argument `precision` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:23:33
|
LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `f` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `f` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:31:47
|
LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
- | -- ^^^^^ this named argument is only referred to by position in formatting string
+ | -- ^^^^^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `width$` by position
+ | this formatting argument uses named argument `width` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:31:58
|
LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
- | -- ^^^^^^^^^ this named argument is only referred to by position in formatting string
+ | -- ^^^^^^^^^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `precision$` by position
+ | this formatting argument uses named argument `precision` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:31:34
|
LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
- | - ^ this named argument is only referred to by position in formatting string
+ | - ^ this named argument is referred to by position in formatting string
| |
| this formatting argument uses named argument `f` by position
|
--> $DIR/issue-99265.rs:52:9
|
LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
- | -- this formatting argument uses named argument `width$` by position
+ | -- this formatting argument uses named argument `width` by position
...
LL | width = 5,
- | ^^^^^ this named argument is only referred to by position in formatting string
+ | ^^^^^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:54:9
|
LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
- | -- this formatting argument uses named argument `precision$` by position
+ | -- this formatting argument uses named argument `precision` by position
...
LL | precision = 2,
- | ^^^^^^^^^ this named argument is only referred to by position in formatting string
+ | ^^^^^^^^^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
| - this formatting argument uses named argument `f` by position
...
LL | f = 0.02f32,
- | ^ this named argument is only referred to by position in formatting string
+ | ^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:58:9
|
LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
- | -- this formatting argument uses named argument `width2$` by position
+ | -- this formatting argument uses named argument `width2` by position
...
LL | width2 = 5,
- | ^^^^^^ this named argument is only referred to by position in formatting string
+ | ^^^^^^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:60:9
|
LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
- | -- this formatting argument uses named argument `precision2$` by position
+ | -- this formatting argument uses named argument `precision2` by position
...
LL | precision2 = 2
- | ^^^^^^^^^^ this named argument is only referred to by position in formatting string
+ | ^^^^^^^^^^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
| - this formatting argument uses named argument `g` by position
...
LL | g = 0.02f32,
- | ^ this named argument is only referred to by position in formatting string
+ | ^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
| - this formatting argument uses named argument `f` by position
...
LL | f = 0.02f32,
- | ^ this named argument is only referred to by position in formatting string
+ | ^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:64:31
|
LL | println!("Hello {:0.1}!", f = 0.02f32);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `f` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `f` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:68:32
|
LL | println!("Hello {0:0.1}!", f = 0.02f32);
- | - ^ this named argument is only referred to by position in formatting string
+ | - ^ this named argument is referred to by position in formatting string
| |
| this formatting argument uses named argument `f` by position
|
--> $DIR/issue-99265.rs:79:23
|
LL | println!("{:0$}", v = val);
- | -- ^ this named argument is only referred to by position in formatting string
+ | -- ^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `v$` by position
+ | this formatting argument uses named argument `v` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:79:23
|
LL | println!("{:0$}", v = val);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `v` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `v` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:84:24
|
LL | println!("{0:0$}", v = val);
- | -- ^ this named argument is only referred to by position in formatting string
+ | -- ^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `v$` by position
+ | this formatting argument uses named argument `v` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:84:24
|
LL | println!("{0:0$}", v = val);
- | - ^ this named argument is only referred to by position in formatting string
+ | - ^ this named argument is referred to by position in formatting string
| |
| this formatting argument uses named argument `v` by position
|
--> $DIR/issue-99265.rs:89:26
|
LL | println!("{:0$.0$}", v = val);
- | -- ^ this named argument is only referred to by position in formatting string
+ | -- ^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `v$` by position
+ | this formatting argument uses named argument `v` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:89:26
|
LL | println!("{:0$.0$}", v = val);
- | -- ^ this named argument is only referred to by position in formatting string
+ | -- ^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `v$` by position
+ | this formatting argument uses named argument `v` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:89:26
|
LL | println!("{:0$.0$}", v = val);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `v` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `v` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:96:27
|
LL | println!("{0:0$.0$}", v = val);
- | -- ^ this named argument is only referred to by position in formatting string
+ | -- ^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `v$` by position
+ | this formatting argument uses named argument `v` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:96:27
|
LL | println!("{0:0$.0$}", v = val);
- | -- ^ this named argument is only referred to by position in formatting string
+ | -- ^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `v$` by position
+ | this formatting argument uses named argument `v` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:96:27
|
LL | println!("{0:0$.0$}", v = val);
- | - ^ this named argument is only referred to by position in formatting string
+ | - ^ this named argument is referred to by position in formatting string
| |
| this formatting argument uses named argument `v` by position
|
--> $DIR/issue-99265.rs:104:28
|
LL | println!("{} {a} {0}", a = 1);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `a` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `a` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:104:28
|
LL | println!("{} {a} {0}", a = 1);
- | - ^ this named argument is only referred to by position in formatting string
+ | - ^ this named argument is referred to by position in formatting string
| |
| this formatting argument uses named argument `a` by position
|
--> $DIR/issue-99265.rs:115:23
|
LL | {:1$.2$}",
- | -- this formatting argument uses named argument `b$` by position
+ | -- this formatting argument uses named argument `b` by position
...
LL | a = 1.0, b = 1, c = 2,
- | ^ this named argument is only referred to by position in formatting string
+ | ^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:115:30
|
LL | {:1$.2$}",
- | -- this formatting argument uses named argument `c$` by position
+ | -- this formatting argument uses named argument `c` by position
...
LL | a = 1.0, b = 1, c = 2,
- | ^ this named argument is only referred to by position in formatting string
+ | ^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:115:14
|
LL | {:1$.2$}",
- | - this formatting argument uses named argument `a` by position
+ | -- this formatting argument uses named argument `a` by position
...
LL | a = 1.0, b = 1, c = 2,
- | ^ this named argument is only referred to by position in formatting string
+ | ^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:126:23
|
LL | {0:1$.2$}",
- | -- this formatting argument uses named argument `b$` by position
+ | -- this formatting argument uses named argument `b` by position
...
LL | a = 1.0, b = 1, c = 2,
- | ^ this named argument is only referred to by position in formatting string
+ | ^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:126:30
|
LL | {0:1$.2$}",
- | -- this formatting argument uses named argument `c$` by position
+ | -- this formatting argument uses named argument `c` by position
...
LL | a = 1.0, b = 1, c = 2,
- | ^ this named argument is only referred to by position in formatting string
+ | ^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
| - this formatting argument uses named argument `a` by position
...
LL | a = 1.0, b = 1, c = 2,
- | ^ this named argument is only referred to by position in formatting string
+ | ^ this named argument is referred to by position in formatting string
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:132:39
|
LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
- | -- ^^^^^ this named argument is only referred to by position in formatting string
+ | -- ^^^^^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `width$` by position
+ | this formatting argument uses named argument `width` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:132:50
|
LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
- | -- ^^^^^^^^^ this named argument is only referred to by position in formatting string
+ | -- ^^^^^^^^^ this named argument is referred to by position in formatting string
| |
- | this formatting argument uses named argument `precision$` by position
+ | this formatting argument uses named argument `precision` by position
|
help: use the named argument by name to avoid ambiguity
|
--> $DIR/issue-99265.rs:132:30
|
LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
- | - ^ this named argument is only referred to by position in formatting string
- | |
- | this formatting argument uses named argument `x` by position
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `x` by position
|
help: use the named argument by name to avoid ambiguity
|
--- /dev/null
+// check-pass
+// run-rustfix
+
+fn main() {
+ println!("Hello {f:.1}!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+
+ println!("Hello {f:1.1}!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+
+ println!("Hello {f}!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+
+ println!("Hello {f}!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+
+ println!("Hello {f}!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+}
--- /dev/null
+// check-pass
+// run-rustfix
+
+fn main() {
+ println!("Hello {:.1}!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+
+ println!("Hello {:1.1}!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+
+ println!("Hello {}!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+
+ println!("Hello { }!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+
+ println!("Hello { }!", f = 0.02f32);
+ //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+ //~| HELP use the named argument by name to avoid ambiguity
+}
--- /dev/null
+warning: named argument `f` is not used by name
+ --> $DIR/issue-99907.rs:5:30
+ |
+LL | println!("Hello {:.1}!", f = 0.02f32);
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `f` by position
+ |
+ = note: `#[warn(named_arguments_used_positionally)]` on by default
+help: use the named argument by name to avoid ambiguity
+ |
+LL | println!("Hello {f:.1}!", f = 0.02f32);
+ | +
+
+warning: named argument `f` is not used by name
+ --> $DIR/issue-99907.rs:9:31
+ |
+LL | println!("Hello {:1.1}!", f = 0.02f32);
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `f` by position
+ |
+help: use the named argument by name to avoid ambiguity
+ |
+LL | println!("Hello {f:1.1}!", f = 0.02f32);
+ | +
+
+warning: named argument `f` is not used by name
+ --> $DIR/issue-99907.rs:13:27
+ |
+LL | println!("Hello {}!", f = 0.02f32);
+ | -- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `f` by position
+ |
+help: use the named argument by name to avoid ambiguity
+ |
+LL | println!("Hello {f}!", f = 0.02f32);
+ | +
+
+warning: named argument `f` is not used by name
+ --> $DIR/issue-99907.rs:17:28
+ |
+LL | println!("Hello { }!", f = 0.02f32);
+ | --- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `f` by position
+ |
+help: use the named argument by name to avoid ambiguity
+ |
+LL | println!("Hello {f}!", f = 0.02f32);
+ | +
+
+warning: named argument `f` is not used by name
+ --> $DIR/issue-99907.rs:21:29
+ |
+LL | println!("Hello { }!", f = 0.02f32);
+ | ---- ^ this named argument is referred to by position in formatting string
+ | |
+ | this formatting argument uses named argument `f` by position
+ |
+help: use the named argument by name to avoid ambiguity
+ |
+LL | println!("Hello {f}!", f = 0.02f32);
+ | +
+
+warning: 5 warnings emitted
+
use self::Join::*;
#[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
enum Join<A,B> {
Keep(A,B),
Skip(A,B),
assert_eq!(stringify_vis!(pub(crate)), "pub(crate) ");
assert_eq!(stringify_vis!(pub(self)), "pub(self) ");
assert_eq!(stringify_vis!(pub(super)), "pub(super) ");
- assert_eq!(stringify_vis!(pub(in self)), "pub(self) ");
- assert_eq!(stringify_vis!(pub(in super)), "pub(super) ");
+ assert_eq!(stringify_vis!(pub(in crate)), "pub(in crate) ");
+ assert_eq!(stringify_vis!(pub(in self)), "pub(in self) ");
+ assert_eq!(stringify_vis!(pub(in super)), "pub(in super) ");
assert_eq!(stringify_vis!(pub(in path::to)), "pub(in path::to) ");
assert_eq!(stringify_vis!(pub(in ::path::to)), "pub(in ::path::to) ");
assert_eq!(stringify_vis!(pub(in self::path::to)), "pub(in self::path::to) ");
// run-pass
-#![feature(box_syntax)]
#![feature(box_patterns)]
#[derive(Debug, PartialEq)]
}
fn main() {
- let a = box Test::Foo(10);
- let b = box Test::Bar(-20);
+ let a = Box::new(Test::Foo(10));
+ let b = Box::new(Test::Bar(-20));
match (a, b) {
(_, box Test::Foo(_)) => unreachable!(),
(box Test::Foo(x), b) => {
assert_eq!(x, 10);
- assert_eq!(b, box Test::Bar(-20));
+ assert_eq!(b, Box::new(Test::Bar(-20)));
},
_ => unreachable!(),
}
fn call(&self, _req: Self::Request);
}
-pub struct S<T>(T);
+pub struct S<T>(#[allow(unused_tuple_struct_fields)] T);
impl Service for ClientMap {
type Request = S<Box<dyn Fn(i32)>>;
impl MyTrait1 for Foo<u32> {}
-struct Foo<T>(T);
+struct Foo<T>(#[allow(unused_tuple_struct_fields)] T);
impl Deref for Foo<()> {
type Target = dyn MyTrait1 + 'static;
}
impl MyTrait2 for u32 {}
-struct Bar<T>(T, u32);
+struct Bar<T>(#[allow(unused_tuple_struct_fields)] T, u32);
impl Deref for Bar<u8> {
type Target = dyn MyTrait2 + 'static;
fn deref(&self) -> &(dyn MyTrait2 + 'static) {
// run-pass
enum Abc {
- A(u8),
- B(i8),
+ A(#[allow(unused_tuple_struct_fields)] u8),
+ B(#[allow(unused_tuple_struct_fields)] i8),
C,
D,
}
// run-pass
// test that ordinary fat pointer operations work.
-struct Wrapper<T: ?Sized>(u32, T);
+struct Wrapper<T: ?Sized>(#[allow(unused_tuple_struct_fields)] u32, T);
struct FatPtrContainer<'a> {
ptr: &'a [u8]
}
}
+#[allow(unused_tuple_struct_fields)]
struct S<T:?Sized>(u32, T);
fn main_ref() {
extern crate mir_external_refs as ext;
-struct S(u8);
+struct S(#[allow(unused_tuple_struct_fields)] u8);
#[derive(Debug, PartialEq, Eq)]
struct Unit;
impl X for S {}
enum E {
- U(u8)
+ U(#[allow(unused_tuple_struct_fields)] u8)
}
#[derive(PartialEq, Debug, Eq)]
| first introduced with type `&{integer}` here
|
= note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+ |
+LL | (0, ref y) | (ref y, 0) => {}
+ | +++
error: aborting due to 2 previous errors
--- /dev/null
+struct S;
+struct Y;
+
+trait Trait {}
+
+impl Trait for Y {}
+
+fn foo() -> impl Trait {
+ if true {
+ S
+ } else {
+ Y //~ ERROR `if` and `else` have incompatible types
+ }
+}
+
+fn bar() -> impl Trait {
+ match true {
+ true => S,
+ false => Y, //~ ERROR `match` arms have incompatible types
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs:12:9
+ |
+LL | / if true {
+LL | | S
+ | | - expected because of this
+LL | | } else {
+LL | | Y
+ | | ^ expected struct `S`, found struct `Y`
+LL | | }
+ | |_____- `if` and `else` have incompatible types
+
+error[E0308]: `match` arms have incompatible types
+ --> $DIR/do-not-suggest-boxed-trait-objects-instead-of-impl-trait.rs:19:18
+ |
+LL | / match true {
+LL | | true => S,
+ | | - this is found to be of type `S`
+LL | | false => Y,
+ | | ^ expected struct `S`, found struct `Y`
+LL | | }
+ | |_____- `match` arms have incompatible types
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// edition:2021
+
+async fn f(_: &()) {}
+//~^ NOTE function defined here
+//~| NOTE
+// Second note is the span of the underlined argument, I think...
+
+fn main() {
+ (|| async {
+ Err::<(), ()>(())?;
+ f(());
+ //~^ ERROR mismatched types
+ //~| NOTE arguments to this function are incorrect
+ //~| NOTE expected `&()`, found `()`
+ //~| HELP consider borrowing here
+ Ok::<(), ()>(())
+ })();
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/dont-point-return-on-E0308.rs:11:11
+ |
+LL | f(());
+ | - ^^
+ | | |
+ | | expected `&()`, found `()`
+ | | help: consider borrowing here: `&()`
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/dont-point-return-on-E0308.rs:3:10
+ |
+LL | async fn f(_: &()) {}
+ | ^ ------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
|
LL | length = { foo(&length) };
| ^^^^^^^^^^^^ expected `u32`, found `i32`
+ |
+help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
+ |
+LL | length = { foo(&length).try_into().unwrap() };
+ | ++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/issue-84976.rs:17:14
--- /dev/null
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+fn main() {
+ enum Blah {
+ A(isize, isize, usize),
+ B(isize, usize),
+ }
+
+ match Blah::A(1, 1, 2) {
+ Blah::A(_, x, ref y) | Blah::B(x, ref y) => {}
+ //~^ ERROR mismatched types
+ //~| ERROR variable `y` is bound inconsistently across alternatives separated by `|`
+ }
+
+ match Blah::A(1, 1, 2) {
+ Blah::A(_, x, y) | Blah::B(x, y) => {}
+ //~^ ERROR mismatched types
+ //~| variable `y` is bound inconsistently across alternatives separated by `|`
+ }
+}
--- /dev/null
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+fn main() {
+ enum Blah {
+ A(isize, isize, usize),
+ B(isize, usize),
+ }
+
+ match Blah::A(1, 1, 2) {
+ Blah::A(_, x, ref y) | Blah::B(x, y) => {}
+ //~^ ERROR mismatched types
+ //~| ERROR variable `y` is bound inconsistently across alternatives separated by `|`
+ }
+
+ match Blah::A(1, 1, 2) {
+ Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+ //~^ ERROR mismatched types
+ //~| variable `y` is bound inconsistently across alternatives separated by `|`
+ }
+}
--- /dev/null
+error[E0409]: variable `y` is bound inconsistently across alternatives separated by `|`
+ --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:11:43
+ |
+LL | Blah::A(_, x, ref y) | Blah::B(x, y) => {}
+ | - first binding ^ bound in different ways
+
+error[E0409]: variable `y` is bound inconsistently across alternatives separated by `|`
+ --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:17:43
+ |
+LL | Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+ | - first binding ^ bound in different ways
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:11:43
+ |
+LL | match Blah::A(1, 1, 2) {
+ | ---------------- this expression has type `Blah`
+LL | Blah::A(_, x, ref y) | Blah::B(x, y) => {}
+ | ----- ^ expected `&usize`, found `usize`
+ | |
+ | first introduced with type `&usize` here
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+ |
+LL | Blah::A(_, x, ref y) | Blah::B(x, ref y) => {}
+ | +++
+
+error[E0308]: mismatched types
+ --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:17:39
+ |
+LL | match Blah::A(1, 1, 2) {
+ | ---------------- this expression has type `Blah`
+LL | Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+ | - ^^^^^ expected `usize`, found `&usize`
+ | |
+ | first introduced with type `usize` here
+ |
+ = note: in the same arm, a binding must have the same type in all alternatives
+help: consider removing `ref`
+ |
+LL - Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+LL + Blah::A(_, x, y) | Blah::B(x, y) => {}
+ |
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0409.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+
+#![allow(dead_code)]
+
+struct S;
+struct Y;
+
+trait Trait {}
+
+impl Trait for S {}
+impl Trait for Y {}
+
+fn foo() -> Box<dyn Trait> {
+ if true {
+ Box::new(S)
+ } else {
+ Box::new(Y) //~ ERROR `if` and `else` have incompatible types
+ }
+}
+
+fn bar() -> Box<dyn Trait> {
+ match true {
+ true => Box::new(S),
+ false => Box::new(Y), //~ ERROR `match` arms have incompatible types
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+#![allow(dead_code)]
+
+struct S;
+struct Y;
+
+trait Trait {}
+
+impl Trait for S {}
+impl Trait for Y {}
+
+fn foo() -> impl Trait {
+ if true {
+ S
+ } else {
+ Y //~ ERROR `if` and `else` have incompatible types
+ }
+}
+
+fn bar() -> impl Trait {
+ match true {
+ true => S,
+ false => Y, //~ ERROR `match` arms have incompatible types
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/suggest-boxed-trait-objects-instead-of-impl-trait.rs:17:9
+ |
+LL | / if true {
+LL | | S
+ | | - expected because of this
+LL | | } else {
+LL | | Y
+ | | ^ expected struct `S`, found struct `Y`
+LL | | }
+ | |_____- `if` and `else` have incompatible types
+ |
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn foo() -> Box<dyn Trait> {
+ | ~~~~~~~ +
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL ~ Box::new(S)
+LL | } else {
+LL ~ Box::new(Y)
+ |
+
+error[E0308]: `match` arms have incompatible types
+ --> $DIR/suggest-boxed-trait-objects-instead-of-impl-trait.rs:24:18
+ |
+LL | / match true {
+LL | | true => S,
+ | | - this is found to be of type `S`
+LL | | false => Y,
+ | | ^ expected struct `S`, found struct `Y`
+LL | | }
+ | |_____- `match` arms have incompatible types
+ |
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn bar() -> Box<dyn Trait> {
+ | ~~~~~~~ +
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL ~ true => Box::new(S),
+LL ~ false => Box::new(Y),
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+fn main() {
+ let x: &Option<Box<i32>> = &Some(Box::new(0));
+
+ match x {
+ //~^ ERROR cannot move out of `x` as enum variant `Some` which is behind a shared reference
+ &Some(_y) => (),
+ &None => (),
+ }
+}
--- /dev/null
+error[E0507]: cannot move out of `x` as enum variant `Some` which is behind a shared reference
+ --> $DIR/issue-99470-move-out-of-some.rs:4:11
+ |
+LL | match x {
+ | ^
+LL |
+LL | &Some(_y) => (),
+ | ---------
+ | | |
+ | | data moved here
+ | | move occurs because `_y` has type `Box<i32>`, which does not implement the `Copy` trait
+ | help: consider removing the `&`: `Some(_y)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
-error[E0507]: cannot move out of `hellothere.x.0` which is behind a shared reference
+error[E0507]: cannot move out of `hellothere.x` as enum variant `Bar` which is behind a shared reference
--> $DIR/moves-based-on-type-block-bad.rs:22:19
|
LL | match hellothere.x {
-error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()`
+error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it returns `!`
--> $DIR/fallback-closure-wrap.rs:18:31
|
LL | let error = Closure::wrap(Box::new(move || {
fn main() {
let error = Closure::wrap(Box::new(move || {
- //[fallback]~^ ERROR type mismatch resolving
+ //[fallback]~^ to be a closure that returns `()`, but it returns `!`
panic!("Can't connect to server.");
}) as Box<dyn FnMut()>);
}
--- /dev/null
+// Regression test for #98589.
+// Previously, named lifetime `'a` that appears in the closure was unrelated to `'a`
+// that appears in the parent function iff `'a` is early-bound.
+// This made the following tests pass borrowck.
+
+// check-fail
+
+// The bound `'a: 'a` ensures that `'a` is early-bound.
+fn test_early_early<'a: 'a, 'b: 'b>() {
+ || { None::<&'a &'b ()>; };
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_early_late<'a: 'a, 'b>() {
+ || { None::<&'a &'b ()>; };
+ //~^ ERROR lifetime may not live long enough
+}
+
+// No early-bound lifetime; included for completeness.
+fn test_late_late<'a, 'b>() {
+ || { None::<&'a &'b ()>; };
+ //~^ ERROR lifetime may not live long enough
+}
+
+fn test_early_type<'a: 'a, T>() {
+ || { None::<&'a T>; };
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+// No early-bound lifetime; included for completeness.
+fn test_late_type<'a, T>() {
+ || { None::<&'a T>; };
+ //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:10:5
+ |
+LL | fn test_early_early<'a: 'a, 'b: 'b>() {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | || { None::<&'a &'b ()>; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:15:10
+ |
+LL | fn test_early_late<'a: 'a, 'b>() {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | || { None::<&'a &'b ()>; };
+ | ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:21:10
+ |
+LL | fn test_late_late<'a, 'b>() {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+LL | || { None::<&'a &'b ()>; };
+ | ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+ |
+ = help: consider adding the following bound: `'b: 'a`
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:26:5
+ |
+LL | || { None::<&'a T>; };
+ | ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test_early_type<'a: 'a, T: 'a>() {
+ | ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:32:5
+ |
+LL | || { None::<&'a T>; };
+ | ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn test_late_type<'a, T: 'a>() {
+ | ++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
| move occurs because value has type `A`, which does not implement the `Copy` trait
| help: consider borrowing here: `&[A("".to_string())][0]`
-error[E0507]: cannot move out of `a.0` which is behind a shared reference
+error[E0507]: cannot move out of `a` which is behind a shared reference
--> $DIR/move-errors.rs:38:16
|
LL | let A(s) = *a;
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
-error[E0507]: cannot move out of `x.0` which is behind a shared reference
+error[E0507]: cannot move out of `x` as enum variant `Err` which is behind a shared reference
--> $DIR/move-errors.rs:110:11
|
LL | match *x {
let _x = <fn(&())>::make_f();
//~^ ERROR implementation of `Y` is not general enough
//~| ERROR implementation of `Y` is not general enough
+ //~| ERROR implementation of `Y` is not general enough
}
= note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
= note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
-error: aborting due to 2 previous errors
+error: implementation of `Y` is not general enough
+ --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14
+ |
+LL | let _x = <fn(&())>::make_f();
+ | ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
+ |
+ = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
+ = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
+
+error: aborting due to 3 previous errors
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `Clone`
+help: one of the expressions' fields has a method of the same name
+ |
+LL | let _y = x.i.clone();
+ | ++
+help: one of the expressions' fields has a method of the same name
+ |
+LL | let _y = x.j.x.clone();
+ | ++++
error: aborting due to previous error
// trying to get assert failure messages that at least identify which case
// failed.
-enum E<T> { Thing(isize, T), Nothing((), ((), ()), [i8; 0]) }
+enum E<T> { Thing(isize, T), #[allow(unused_tuple_struct_fields)] Nothing((), ((), ()), [i8; 0]) }
impl<T> E<T> {
fn is_none(&self) -> bool {
match *self {
// compile-flags: -Z fuel=foo=0
+#[allow(unused_tuple_struct_fields)]
struct S1(u8, u16, u8);
+#[allow(unused_tuple_struct_fields)]
struct S2(u8, u16, u8);
fn main() {
// compile-flags: -Z fuel=foo=1
+#[allow(unused_tuple_struct_fields)]
struct S1(u8, u16, u8);
+#[allow(unused_tuple_struct_fields)]
struct S2(u8, u16, u8);
fn main() {
}
#[repr(transparent)]
-struct NotCopy(u8);
+struct NotCopy(#[allow(unused_tuple_struct_fields)] u8);
#[repr(packed)]
struct Packed<'a>(NotCopy, Aligned<'a>);
// run-pass
#[repr(packed)]
-struct Packed<T: Copy>(T);
+struct Packed<T: Copy>(#[allow(unused_tuple_struct_fields)] T);
impl<T: Copy> Copy for Packed<T> {}
impl<T: Copy> Clone for Packed<T> {
use std::mem;
#[repr(packed)]
+#[allow(unused_tuple_struct_fields)]
struct S4(u8,[u8; 3]);
#[repr(packed)]
+#[allow(unused_tuple_struct_fields)]
struct S5(u8,u32);
pub fn main() {
--- /dev/null
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+ foo()
+ [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,`
+}
+
+fn main() {}
--- /dev/null
+error: expected one of `.`, `?`, `]`, or an operator, found `,`
+ --> $DIR/do-not-suggest-suggest-semicolon-before-array.rs:5:5
+ |
+LL | [1, 3)
+ | ^ ^ help: `]` may belong here
+ | |
+ | unclosed delimiter
+
+error: aborting due to previous error
+
--- /dev/null
+// run-rustfix
+
+pub enum Range {
+ //~^ ERROR `enum` and `struct` are mutually exclusive
+ Valid {
+ begin: u32,
+ len: u32,
+ },
+ Out,
+}
+
+fn main() {
+}
--- /dev/null
+// run-rustfix
+
+pub enum struct Range {
+ //~^ ERROR `enum` and `struct` are mutually exclusive
+ Valid {
+ begin: u32,
+ len: u32,
+ },
+ Out,
+}
+
+fn main() {
+}
--- /dev/null
+error: `enum` and `struct` are mutually exclusive
+ --> $DIR/issue-99625-enum-struct-mutually-exclusive.rs:3:5
+ |
+LL | pub enum struct Range {
+ | ^^^^^^^^^^^ help: replace `enum struct` with: `enum`
+
+error: aborting due to previous error
+
// run-rustfix
// This is for checking if we can apply suggestions as-is.
-pub struct Foo(i32);
+pub struct Foo(#[allow(unused_tuple_struct_fields)] i32);
fn main() {
let Foo(..) = Foo(0); //~ ERROR unexpected `...`
// run-rustfix
// This is for checking if we can apply suggestions as-is.
-pub struct Foo(i32);
+pub struct Foo(#[allow(unused_tuple_struct_fields)] i32);
fn main() {
let Foo(...) = Foo(0); //~ ERROR unexpected `...`
// 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`
+// error-pattern:expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e`
fn m(){print!("",(c for&g
u
LL | fn m(){print!("",(c for&g
| ^^^ expected one of 8 possible tokens
-error: expected `;`, found `e`
- --> $DIR/issue-88770.rs:10:2
+error: expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e`
+ --> $DIR/issue-88770.rs:11:1
|
LL | e
- | ^ help: add `;` here
+ | - expected one of 9 possible tokens
LL | e
- | - unexpected token
+ | ^ 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
+error: aborting due to 6 previous errors
error: missing type for `const` item
- --> $DIR/issue-89574.rs:2:11
+ --> $DIR/issue-89574.rs:2:22
|
LL | const EMPTY_ARRAY = [];
- | ^^^^^^^^^^^ help: provide a type for the item: `EMPTY_ARRAY: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: aborting due to previous error
| help: provide a definition for the constant: `= <expr>;`
error: missing type for `const` item
- --> $DIR/item-free-const-no-body-semantic-fail.rs:6:7
+ --> $DIR/item-free-const-no-body-semantic-fail.rs:6:8
|
LL | const B;
- | ^ help: provide a type for the item: `B: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: aborting due to 3 previous errors
| help: provide a definition for the static: `= <expr>;`
error: missing type for `static` item
- --> $DIR/item-free-static-no-body-semantic-fail.rs:6:8
+ --> $DIR/item-free-static-no-body-semantic-fail.rs:6:9
|
LL | static B;
- | ^ help: provide a type for the item: `B: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: missing type for `static mut` item
- --> $DIR/item-free-static-no-body-semantic-fail.rs:10:12
+ --> $DIR/item-free-static-no-body-semantic-fail.rs:10:13
|
LL | static mut D;
- | ^ help: provide a type for the item: `D: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: aborting due to 6 previous errors
| - the item list ends here
error: missing type for `static` item
- --> $DIR/removed-syntax-static-fn.rs:4:12
+ --> $DIR/removed-syntax-static-fn.rs:4:14
|
LL | static fn f() {}
- | ^^ help: provide a type for the item: `r#fn: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: aborting due to 3 previous errors
--- /dev/null
+fn main() {
+ let v = [1
+ 2];
+ //~^ ERROR expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found `2`
+}
--- /dev/null
+error: expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found `2`
+ --> $DIR/suggest-semi-in-array.rs:3:5
+ |
+LL | let v = [1
+ | - expected one of `,`, `.`, `;`, `?`, `]`, or an operator
+LL | 2];
+ | ^ unexpected token
+
+error: aborting due to previous error
+
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+ foo();
+ [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+ foo()
+ [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
--- /dev/null
+error: expected `;`, found `[`
+ --> $DIR/suggest-suggest-semicolon-before-array.rs:8:5
+ |
+LL | [1, 3]
+ | ^
+ |
+help: consider adding `;` here
+ |
+LL | foo();
+ | +
+
+error: aborting due to previous error
+
--- /dev/null
+// run-rustfix
+
+fn main() {
+ match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
+ Some(1) => {}
+ // hello
+ Some(_) => {}
+ None => todo!()
+ }
+}
--- /dev/null
+// run-rustfix
+
+fn main() {
+ match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
+ Some(1) => {}
+ // hello
+ Some(_) => {}
+ }
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `None` not covered
+ --> $DIR/suggest-adding-appropriate-missing-pattern-excluding-comments.rs:4:11
+ |
+LL | match Some(1) {
+ | ^^^^^^^ pattern `None` not covered
+ |
+note: `Option<i32>` defined here
+ --> $SRC_DIR/core/src/option.rs:LL:COL
+ |
+LL | pub enum Option<T> {
+ | ------------------
+...
+LL | None,
+ | ^^^^ not covered
+ = note: the matched value is of type `Option<i32>`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+ |
+LL ~ Some(_) => {}
+LL + None => todo!()
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn cause_ice(_: TokenStream) -> TokenStream {
+ "
+ enum IceCause {
+ Variant,
+ }
+
+ pub use IceCause::Variant;
+ ".parse().unwrap()
+}
--- /dev/null
+// aux-build:re-export.rs
+// edition:2018
+
+extern crate re_export;
+
+use re_export::cause_ice;
+
+cause_ice!(); //~ ERROR `Variant` is only public within the crate, and cannot be re-exported outside
+
+fn main() {}
--- /dev/null
+error[E0364]: `Variant` is only public within the crate, and cannot be re-exported outside
+ --> $DIR/issue-79148.rs:8:1
+ |
+LL | cause_ice!();
+ | ^^^^^^^^^^^^
+ |
+note: consider marking `Variant` as `pub` in the imported module
+ --> $DIR/issue-79148.rs:8:1
+ |
+LL | cause_ice!();
+ | ^^^^^^^^^^^^
+ = note: this error originates in the macro `cause_ice` (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 E0364`.
pub fn return_range_to() -> RangeToInclusive<i32> { return ..=1; }
#[derive(Debug)]
-struct P(u8);
+struct P(#[allow(unused_tuple_struct_fields)] u8);
pub fn main() {
let mut count = 0;
-//~ ERROR cycle detected when computing layout of `S`
+//~ ERROR cycle detected when computing layout of `core::option::Option<S>`
+//~| NOTE ...which requires computing layout of `S`...
//~| NOTE ...which requires computing layout of `core::option::Option<<S as Mirror>::It>`...
-//~| NOTE ...which requires computing layout of `core::option::Option<S>`...
-//~| NOTE ...which again requires computing layout of `S`, completing the cycle
-
-// build-fail
+//~| NOTE ...which again requires computing layout of `core::option::Option<S>`, completing the cycle
+//~| NOTE cycle used when computing layout of `core::option::Option<<S as Mirror>::It>`
trait Mirror {
type It: ?Sized;
struct S(Option<<S as Mirror>::It>);
fn main() {
- //~^ NOTE cycle used when elaborating drops for `main`
let _s = S(None);
}
-error[E0391]: cycle detected when computing layout of `S`
+error[E0391]: cycle detected when computing layout of `core::option::Option<S>`
|
+ = note: ...which requires computing layout of `S`...
= note: ...which requires computing layout of `core::option::Option<<S as Mirror>::It>`...
- = note: ...which requires computing layout of `core::option::Option<S>`...
- = note: ...which again requires computing layout of `S`, completing the cycle
-note: cycle used when elaborating drops for `main`
- --> $DIR/issue-26548-recursion-via-normalize.rs:16:1
- |
-LL | fn main() {
- | ^^^^^^^^^
+ = note: ...which again requires computing layout of `core::option::Option<S>`, completing the cycle
+ = note: cycle used when computing layout of `core::option::Option<<S as Mirror>::It>`
error: aborting due to previous error
|
= note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}`
found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
+ = note: different `fn` items always have unique types, even if their signatures are the same
+ = help: change the expected type to be function pointer `extern "rust-intrinsic" fn(bool) -> bool`
+ = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `likely as extern "rust-intrinsic" fn(bool) -> bool`
error: aborting due to 3 previous errors
note: cycle used when collecting item types in top-level module
--> $DIR/issue-23305.rs:1:1
|
-LL | pub trait ToNbt<T> {
- | ^^^^^^^^^^^^^^^^^^
+LL | / pub trait ToNbt<T> {
+LL | | fn new(val: T) -> Self;
+LL | | }
+LL | |
+... |
+LL | |
+LL | | fn main() {}
+ | |____________^
error: aborting due to previous error
| first introduced with type `&isize` here
|
= note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+ |
+LL | Opts::A(ref i) | Opts::B(ref i) => {}
+ | +++
error[E0308]: mismatched types
--> $DIR/resolve-inconsistent-binding-mode.rs:18:34
| first introduced with type `&isize` here
|
= note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+ |
+LL | Opts::A(ref i) | Opts::B(ref i) => {}
+ | +++
error[E0308]: mismatched types
--> $DIR/resolve-inconsistent-binding-mode.rs:27:38
//~| ERROR mismatched types
//~| ERROR variable `c` is not bound in all patterns
//~| HELP if you meant to match on unit variant `E::A`, use the full path in the pattern
+ //~| HELP consider removing `ref`
}
let z = (10, 20);
| first binding
error[E0408]: variable `CONST1` is not bound in all patterns
- --> $DIR/resolve-inconsistent-names.rs:30:23
+ --> $DIR/resolve-inconsistent-names.rs:31:23
|
LL | (CONST1, _) | (_, Const2) => ()
| ------ ^^^^^^^^^^^ pattern doesn't bind `CONST1`
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible
error[E0408]: variable `Const2` is not bound in all patterns
- --> $DIR/resolve-inconsistent-names.rs:30:9
+ --> $DIR/resolve-inconsistent-names.rs:31:9
|
LL | (CONST1, _) | (_, Const2) => ()
| ^^^^^^^^^^^ ------ variable not in all patterns
| first introduced with type `E` here
|
= note: in the same arm, a binding must have the same type in all alternatives
+help: consider removing `ref`
+ |
+LL - (A, B) | (ref B, c) | (c, A) => ()
+LL + (A, B) | (B, c) | (c, A) => ()
+ |
error: aborting due to 9 previous errors
#![warn(pointer_structural_match)]
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
// This impl makes NoDerive irreflexive
// (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
#![warn(pointer_structural_match)]
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
// This impl makes NoDerive irreflexive
// (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
#![warn(pointer_structural_match)]
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
// This impl makes NoDerive irreflexive
// (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
#![warn(pointer_structural_match)]
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
// This impl makes NoDerive irreflexive
// (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
//
// See discussion on rust-lang/rust#62307 and rust-lang/rust#62339
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
// This impl makes NoDerive irreflexive.
impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
#![warn(indirect_structural_match)]
// run-pass
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
// This impl makes NoDerive irreflexive.
impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
#![warn(indirect_structural_match)]
// run-pass
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
// This impl makes NoDerive irreflexive.
impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
#![warn(indirect_structural_match)]
// run-pass
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
// This impl makes NoDerive irreflexive.
impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
#![warn(indirect_structural_match)]
// run-pass
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
// This impl makes NoDerive irreflexive.
impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
// aux-build:enums.rs
-// run-pass
extern crate enums;
fn main() {
let e = FieldLessWithNonExhaustiveVariant::default();
- // FIXME: https://github.com/rust-lang/rust/issues/91161
- // This `as` cast *should* be an error, since it would fail
- // if the non-exhaustive variant got fields. But today it
- // doesn't. The fix for that will update this test to
- // show an error (and not be run-pass any more).
- let d = e as u8;
+ let d = e as u8; //~ ERROR casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid [E0606]
assert_eq!(d, 0);
}
--- /dev/null
+error[E0606]: casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid
+ --> $DIR/enum-as-cast.rs:9:13
+ |
+LL | let d = e as u8;
+ | ^^^^^^^
+ |
+ = note: cannot cast an enum with a non-exhaustive variant when it's defined in another crate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
() if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
//~^ ERROR `if let` guards are experimental
//~| ERROR expected expression, found `let` statement
+ //~| ERROR expected expression, found `let` statement
+ //~| ERROR expected expression, found `let` statement
() if let Range { start: _, end: _ } = (true..true) && false => {}
//~^ ERROR `if let` guards are experimental
| ^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:52:16
+ --> $DIR/feature-gate.rs:32:55
+ |
+LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/feature-gate.rs:32:68
+ |
+LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/feature-gate.rs:54:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:54:16
+ --> $DIR/feature-gate.rs:56:16
|
LL | use_expr!((let 0 = 1));
| ^^^
error: no rules expected the token `let`
- --> $DIR/feature-gate.rs:62:15
+ --> $DIR/feature-gate.rs:64:15
|
LL | macro_rules! use_expr {
| --------------------- when calling this macro
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
- --> $DIR/feature-gate.rs:36:12
+ --> $DIR/feature-gate.rs:38:12
|
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
- --> $DIR/feature-gate.rs:58:12
+ --> $DIR/feature-gate.rs:60:12
|
LL | () if let 0 = 1 => {}
| ^^^^^^^^^^^^
= help: add `#![feature(if_let_guard)]` to the crate attributes to enable
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
-error: aborting due to 16 previous errors
+error: aborting due to 18 previous errors
For more information about this error, try `rustc --explain E0658`.
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR expected expression, found `let` statement
+ //~| ERROR expected expression, found `let` statement
+ //~| ERROR expected expression, found `let` statement
}
fn _while() {
//~| ERROR `let` expressions are not supported here
//~| ERROR `let` expressions are not supported here
//~| ERROR expected expression, found `let` statement
+ //~| ERROR expected expression, found `let` statement
+ //~| ERROR expected expression, found `let` statement
}
fn _macros() {
//~| ERROR expected expression, found `let` statement
if true || (true && let 0 = 0) {}
//~^ ERROR `let` expressions are not supported here
+ //~| ERROR expected expression, found `let` statement
let mut x = true;
if x = let 0 = 0 {}
//~| ERROR expected expression, found `let` statement
while true || (true && let 0 = 0) {}
//~^ ERROR `let` expressions are not supported here
+ //~| ERROR expected expression, found `let` statement
let mut x = true;
while x = let 0 = 0 {}
if let A::<{
true && let 1 = 1
//~^ ERROR `let` expressions are not supported here
+ //~| ERROR expected expression, found `let` statement
}>::O = 5 {}
while let A::<{
true && let 1 = 1
//~^ ERROR `let` expressions are not supported here
+ //~| ERROR expected expression, found `let` statement
}>::O = 5 {}
if A::<{
true && let 1 = 1
//~^ ERROR `let` expressions are not supported here
+ //~| ERROR expected expression, found `let` statement
}>::O == 5 {}
// In the cases above we have `ExprKind::Block` to help us out.
if A::<
true && let 1 = 1
//~^ ERROR `let` expressions are not supported here
- //~| ERROR expressions must be enclosed in braces
+ //~| ERROR expressions must be enclosed in braces
+ //~| ERROR expected expression, found `let` statement
>::O == 5 {}
}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:57:12
+ --> $DIR/disallowed-positions.rs:49:48
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:49:61
+ |
+LL | if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:59:12
|
LL | while (let 0 = 1) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:61:14
+ --> $DIR/disallowed-positions.rs:63:14
|
LL | while (((let 0 = 1))) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:65:12
+ --> $DIR/disallowed-positions.rs:67:12
|
LL | while (let 0 = 1) && true {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:69:20
+ --> $DIR/disallowed-positions.rs:71:20
|
LL | while true && (let 0 = 1) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:73:12
+ --> $DIR/disallowed-positions.rs:75:12
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:73:27
+ --> $DIR/disallowed-positions.rs:75:27
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:79:38
+ --> $DIR/disallowed-positions.rs:81:38
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:110:9
+ --> $DIR/disallowed-positions.rs:81:51
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:81:64
+ |
+LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:114:9
|
LL | if &let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:115:9
+ --> $DIR/disallowed-positions.rs:119:9
|
LL | if !let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:118:9
+ --> $DIR/disallowed-positions.rs:122:9
|
LL | if *let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:122:9
+ --> $DIR/disallowed-positions.rs:126:9
|
LL | if -let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:132:9
+ --> $DIR/disallowed-positions.rs:136:9
|
LL | if (let 0 = 0)? {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:138:16
+ --> $DIR/disallowed-positions.rs:142:16
|
LL | if true || let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:141:17
+ --> $DIR/disallowed-positions.rs:145:17
|
LL | if (true || let 0 = 0) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:144:25
+ --> $DIR/disallowed-positions.rs:148:25
|
LL | if true && (true || let 0 = 0) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:151:12
+ --> $DIR/disallowed-positions.rs:151:25
+ |
+LL | if true || (true && let 0 = 0) {}
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:156:12
|
LL | if x = let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:156:15
+ --> $DIR/disallowed-positions.rs:161:15
|
LL | if true..(let 0 = 0) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:160:11
+ --> $DIR/disallowed-positions.rs:165:11
|
LL | if ..(let 0 = 0) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:164:9
+ --> $DIR/disallowed-positions.rs:169:9
|
LL | if (let 0 = 0).. {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:195:19
+ --> $DIR/disallowed-positions.rs:200:19
|
LL | if let true = let true = true {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:201:12
+ --> $DIR/disallowed-positions.rs:206:12
|
LL | while &let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:206:12
+ --> $DIR/disallowed-positions.rs:211:12
|
LL | while !let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:209:12
+ --> $DIR/disallowed-positions.rs:214:12
|
LL | while *let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:213:12
+ --> $DIR/disallowed-positions.rs:218:12
|
LL | while -let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:223:12
+ --> $DIR/disallowed-positions.rs:228:12
|
LL | while (let 0 = 0)? {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:229:19
+ --> $DIR/disallowed-positions.rs:234:19
|
LL | while true || let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:232:20
+ --> $DIR/disallowed-positions.rs:237:20
|
LL | while (true || let 0 = 0) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:235:28
+ --> $DIR/disallowed-positions.rs:240:28
|
LL | while true && (true || let 0 = 0) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:242:15
+ --> $DIR/disallowed-positions.rs:243:28
+ |
+LL | while true || (true && let 0 = 0) {}
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:248:15
|
LL | while x = let 0 = 0 {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:247:18
+ --> $DIR/disallowed-positions.rs:253:18
|
LL | while true..(let 0 = 0) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:251:14
+ --> $DIR/disallowed-positions.rs:257:14
|
LL | while ..(let 0 = 0) {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:255:12
+ --> $DIR/disallowed-positions.rs:261:12
|
LL | while (let 0 = 0).. {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:286:22
+ --> $DIR/disallowed-positions.rs:292:22
|
LL | while let true = let true = true {}
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:302:6
+ --> $DIR/disallowed-positions.rs:308:6
|
LL | &let 0 = 0;
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:306:6
+ --> $DIR/disallowed-positions.rs:312:6
|
LL | !let 0 = 0;
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:309:6
+ --> $DIR/disallowed-positions.rs:315:6
|
LL | *let 0 = 0;
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:313:6
+ --> $DIR/disallowed-positions.rs:319:6
|
LL | -let 0 = 0;
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:323:6
+ --> $DIR/disallowed-positions.rs:329:6
|
LL | (let 0 = 0)?;
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:329:13
+ --> $DIR/disallowed-positions.rs:335:13
|
LL | true || let 0 = 0;
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:332:14
+ --> $DIR/disallowed-positions.rs:338:14
|
LL | (true || let 0 = 0);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:335:22
+ --> $DIR/disallowed-positions.rs:341:22
|
LL | true && (true || let 0 = 0);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:340:9
+ --> $DIR/disallowed-positions.rs:346:9
|
LL | x = let 0 = 0;
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:344:12
+ --> $DIR/disallowed-positions.rs:350:12
|
LL | true..(let 0 = 0);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:347:8
+ --> $DIR/disallowed-positions.rs:353:8
|
LL | ..(let 0 = 0);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:350:6
+ --> $DIR/disallowed-positions.rs:356:6
|
LL | (let 0 = 0)..;
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:354:6
+ --> $DIR/disallowed-positions.rs:360:6
|
LL | (let Range { start: _, end: _ } = true..true || false);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:359:6
+ --> $DIR/disallowed-positions.rs:365:6
|
LL | (let true = let true = true);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:359:17
+ --> $DIR/disallowed-positions.rs:365:17
|
LL | (let true = let true = true);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:366:25
+ --> $DIR/disallowed-positions.rs:372:25
|
LL | let x = true && let y = 1;
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:372:19
+ --> $DIR/disallowed-positions.rs:378:19
|
LL | [1, 2, 3][let _ = ()]
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:377:6
+ --> $DIR/disallowed-positions.rs:383:6
|
LL | &let 0 = 0
| ^^^
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:395:17
+ |
+LL | true && let 1 = 1
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:401:17
+ |
+LL | true && let 1 = 1
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:407:17
+ |
+LL | true && let 1 = 1
+ | ^^^
+
+error: expected expression, found `let` statement
+ --> $DIR/disallowed-positions.rs:419:17
+ |
+LL | true && let 1 = 1
+ | ^^^
+
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/disallowed-positions.rs:410:9
+ --> $DIR/disallowed-positions.rs:419:9
|
LL | true && let 1 = 1
| ^^^^^^^^^^^^^^^^^
| + +
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:419:9
+ --> $DIR/disallowed-positions.rs:429:9
|
LL | if (let Some(a) = opt && true) {
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:424:9
+ --> $DIR/disallowed-positions.rs:434:9
|
LL | if (let Some(a) = opt) && true {
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:428:9
+ --> $DIR/disallowed-positions.rs:438:9
|
LL | if (let Some(a) = opt) && (let Some(b) = a) {
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:428:32
+ --> $DIR/disallowed-positions.rs:438:32
|
LL | if (let Some(a) = opt) && (let Some(b) = a) {
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:437:9
+ --> $DIR/disallowed-positions.rs:447:9
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:437:31
+ --> $DIR/disallowed-positions.rs:447:31
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:443:9
+ --> $DIR/disallowed-positions.rs:453:9
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && true {
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:443:31
+ --> $DIR/disallowed-positions.rs:453:31
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && true {
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:449:9
+ --> $DIR/disallowed-positions.rs:459:9
|
LL | if (let Some(a) = opt && (true)) && true {
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:466:22
+ --> $DIR/disallowed-positions.rs:476:22
|
LL | let x = (true && let y = 1);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:471:20
+ --> $DIR/disallowed-positions.rs:481:20
|
LL | ([1, 2, 3][let _ = ()])
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:475:20
+ --> $DIR/disallowed-positions.rs:485:20
|
LL | #[cfg(FALSE)] (let 0 = 1);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:93:16
+ --> $DIR/disallowed-positions.rs:97:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:97:16
+ --> $DIR/disallowed-positions.rs:101:16
|
LL | use_expr!((let 0 = 1));
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:101:23
+ --> $DIR/disallowed-positions.rs:105:23
|
LL | use_expr!(true && let 0 = 1);
| ^^^
error: expected expression, found `let` statement
- --> $DIR/disallowed-positions.rs:105:17
+ --> $DIR/disallowed-positions.rs:109:17
|
LL | noop_expr!((let 0 = 1));
| ^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:57:12
+ --> $DIR/disallowed-positions.rs:59:12
|
LL | while (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:57:12
+ --> $DIR/disallowed-positions.rs:59:12
|
LL | while (let 0 = 1) {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:61:14
+ --> $DIR/disallowed-positions.rs:63:14
|
LL | while (((let 0 = 1))) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:61:14
+ --> $DIR/disallowed-positions.rs:63:14
|
LL | while (((let 0 = 1))) {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:65:12
+ --> $DIR/disallowed-positions.rs:67:12
|
LL | while (let 0 = 1) && true {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:65:12
+ --> $DIR/disallowed-positions.rs:67:12
|
LL | while (let 0 = 1) && true {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:69:20
+ --> $DIR/disallowed-positions.rs:71:20
|
LL | while true && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:69:20
+ --> $DIR/disallowed-positions.rs:71:20
|
LL | while true && (let 0 = 1) {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:73:12
+ --> $DIR/disallowed-positions.rs:75:12
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:73:12
+ --> $DIR/disallowed-positions.rs:75:12
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:73:27
+ --> $DIR/disallowed-positions.rs:75:27
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:73:27
+ --> $DIR/disallowed-positions.rs:75:27
|
LL | while (let 0 = 1) && (let 0 = 1) {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:79:38
+ --> $DIR/disallowed-positions.rs:81:38
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:79:38
+ --> $DIR/disallowed-positions.rs:81:38
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:79:51
+ --> $DIR/disallowed-positions.rs:81:51
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:79:38
+ --> $DIR/disallowed-positions.rs:81:38
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:79:64
+ --> $DIR/disallowed-positions.rs:81:64
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:79:38
+ --> $DIR/disallowed-positions.rs:81:38
|
LL | while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:93:16
+ --> $DIR/disallowed-positions.rs:97:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:93:16
+ --> $DIR/disallowed-positions.rs:97:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:93:16
+ --> $DIR/disallowed-positions.rs:97:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:93:16
+ --> $DIR/disallowed-positions.rs:97:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:97:16
+ --> $DIR/disallowed-positions.rs:101:16
|
LL | use_expr!((let 0 = 1));
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:97:16
+ --> $DIR/disallowed-positions.rs:101:16
|
LL | use_expr!((let 0 = 1));
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:97:16
+ --> $DIR/disallowed-positions.rs:101:16
|
LL | use_expr!((let 0 = 1));
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:97:16
+ --> $DIR/disallowed-positions.rs:101:16
|
LL | use_expr!((let 0 = 1));
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:110:9
+ --> $DIR/disallowed-positions.rs:114:9
|
LL | if &let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:115:9
+ --> $DIR/disallowed-positions.rs:119:9
|
LL | if !let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:118:9
+ --> $DIR/disallowed-positions.rs:122:9
|
LL | if *let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:122:9
+ --> $DIR/disallowed-positions.rs:126:9
|
LL | if -let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:132:9
+ --> $DIR/disallowed-positions.rs:136:9
|
LL | if (let 0 = 0)? {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:132:9
+ --> $DIR/disallowed-positions.rs:136:9
|
LL | if (let 0 = 0)? {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:138:16
+ --> $DIR/disallowed-positions.rs:142:16
|
LL | if true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
- --> $DIR/disallowed-positions.rs:138:13
+ --> $DIR/disallowed-positions.rs:142:13
|
LL | if true || let 0 = 0 {}
| ^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:141:17
+ --> $DIR/disallowed-positions.rs:145:17
|
LL | if (true || let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
- --> $DIR/disallowed-positions.rs:141:14
+ --> $DIR/disallowed-positions.rs:145:14
|
LL | if (true || let 0 = 0) {}
| ^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:144:25
+ --> $DIR/disallowed-positions.rs:148:25
|
LL | if true && (true || let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
- --> $DIR/disallowed-positions.rs:144:22
+ --> $DIR/disallowed-positions.rs:148:22
|
LL | if true && (true || let 0 = 0) {}
| ^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:147:25
+ --> $DIR/disallowed-positions.rs:151:25
|
LL | if true || (true && let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:147:17
+ --> $DIR/disallowed-positions.rs:151:17
|
LL | if true || (true && let 0 = 0) {}
| ^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:151:12
+ --> $DIR/disallowed-positions.rs:156:12
|
LL | if x = let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:156:15
+ --> $DIR/disallowed-positions.rs:161:15
|
LL | if true..(let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:156:15
+ --> $DIR/disallowed-positions.rs:161:15
|
LL | if true..(let 0 = 0) {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:160:11
+ --> $DIR/disallowed-positions.rs:165:11
|
LL | if ..(let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:160:11
+ --> $DIR/disallowed-positions.rs:165:11
|
LL | if ..(let 0 = 0) {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:164:9
+ --> $DIR/disallowed-positions.rs:169:9
|
LL | if (let 0 = 0).. {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:164:9
+ --> $DIR/disallowed-positions.rs:169:9
|
LL | if (let 0 = 0).. {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:170:8
+ --> $DIR/disallowed-positions.rs:175:8
|
LL | if let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:174:8
+ --> $DIR/disallowed-positions.rs:179:8
|
LL | if let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:181:8
+ --> $DIR/disallowed-positions.rs:186:8
|
LL | if let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:189:8
+ --> $DIR/disallowed-positions.rs:194:8
|
LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:195:19
+ --> $DIR/disallowed-positions.rs:200:19
|
LL | if let true = let true = true {}
| ^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:201:12
+ --> $DIR/disallowed-positions.rs:206:12
|
LL | while &let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:206:12
+ --> $DIR/disallowed-positions.rs:211:12
|
LL | while !let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:209:12
+ --> $DIR/disallowed-positions.rs:214:12
|
LL | while *let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:213:12
+ --> $DIR/disallowed-positions.rs:218:12
|
LL | while -let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:223:12
+ --> $DIR/disallowed-positions.rs:228:12
|
LL | while (let 0 = 0)? {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:223:12
+ --> $DIR/disallowed-positions.rs:228:12
|
LL | while (let 0 = 0)? {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:229:19
+ --> $DIR/disallowed-positions.rs:234:19
|
LL | while true || let 0 = 0 {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
- --> $DIR/disallowed-positions.rs:229:16
+ --> $DIR/disallowed-positions.rs:234:16
|
LL | while true || let 0 = 0 {}
| ^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:232:20
+ --> $DIR/disallowed-positions.rs:237:20
|
LL | while (true || let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
- --> $DIR/disallowed-positions.rs:232:17
+ --> $DIR/disallowed-positions.rs:237:17
|
LL | while (true || let 0 = 0) {}
| ^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:235:28
+ --> $DIR/disallowed-positions.rs:240:28
|
LL | while true && (true || let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
- --> $DIR/disallowed-positions.rs:235:25
+ --> $DIR/disallowed-positions.rs:240:25
|
LL | while true && (true || let 0 = 0) {}
| ^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:238:28
+ --> $DIR/disallowed-positions.rs:243:28
|
LL | while true || (true && let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:238:20
+ --> $DIR/disallowed-positions.rs:243:20
|
LL | while true || (true && let 0 = 0) {}
| ^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:242:15
+ --> $DIR/disallowed-positions.rs:248:15
|
LL | while x = let 0 = 0 {}
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:247:18
+ --> $DIR/disallowed-positions.rs:253:18
|
LL | while true..(let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:247:18
+ --> $DIR/disallowed-positions.rs:253:18
|
LL | while true..(let 0 = 0) {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:251:14
+ --> $DIR/disallowed-positions.rs:257:14
|
LL | while ..(let 0 = 0) {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:251:14
+ --> $DIR/disallowed-positions.rs:257:14
|
LL | while ..(let 0 = 0) {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:255:12
+ --> $DIR/disallowed-positions.rs:261:12
|
LL | while (let 0 = 0).. {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:255:12
+ --> $DIR/disallowed-positions.rs:261:12
|
LL | while (let 0 = 0).. {}
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:261:11
+ --> $DIR/disallowed-positions.rs:267:11
|
LL | while let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:265:11
+ --> $DIR/disallowed-positions.rs:271:11
|
LL | while let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:272:11
+ --> $DIR/disallowed-positions.rs:278:11
|
LL | while let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:280:11
+ --> $DIR/disallowed-positions.rs:286:11
|
LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:286:22
+ --> $DIR/disallowed-positions.rs:292:22
|
LL | while let true = let true = true {}
| ^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:302:6
+ --> $DIR/disallowed-positions.rs:308:6
|
LL | &let 0 = 0;
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:306:6
+ --> $DIR/disallowed-positions.rs:312:6
|
LL | !let 0 = 0;
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:309:6
+ --> $DIR/disallowed-positions.rs:315:6
|
LL | *let 0 = 0;
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:313:6
+ --> $DIR/disallowed-positions.rs:319:6
|
LL | -let 0 = 0;
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:323:6
+ --> $DIR/disallowed-positions.rs:329:6
|
LL | (let 0 = 0)?;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:323:6
+ --> $DIR/disallowed-positions.rs:329:6
|
LL | (let 0 = 0)?;
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:329:13
+ --> $DIR/disallowed-positions.rs:335:13
|
LL | true || let 0 = 0;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
- --> $DIR/disallowed-positions.rs:329:10
+ --> $DIR/disallowed-positions.rs:335:10
|
LL | true || let 0 = 0;
| ^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:332:14
+ --> $DIR/disallowed-positions.rs:338:14
|
LL | (true || let 0 = 0);
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
- --> $DIR/disallowed-positions.rs:332:11
+ --> $DIR/disallowed-positions.rs:338:11
|
LL | (true || let 0 = 0);
| ^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:335:22
+ --> $DIR/disallowed-positions.rs:341:22
|
LL | true && (true || let 0 = 0);
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `||` operators are not supported in let chain expressions
- --> $DIR/disallowed-positions.rs:335:19
+ --> $DIR/disallowed-positions.rs:341:19
|
LL | true && (true || let 0 = 0);
| ^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:340:9
+ --> $DIR/disallowed-positions.rs:346:9
|
LL | x = let 0 = 0;
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:344:12
+ --> $DIR/disallowed-positions.rs:350:12
|
LL | true..(let 0 = 0);
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:344:12
+ --> $DIR/disallowed-positions.rs:350:12
|
LL | true..(let 0 = 0);
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:347:8
+ --> $DIR/disallowed-positions.rs:353:8
|
LL | ..(let 0 = 0);
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:347:8
+ --> $DIR/disallowed-positions.rs:353:8
|
LL | ..(let 0 = 0);
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:350:6
+ --> $DIR/disallowed-positions.rs:356:6
|
LL | (let 0 = 0)..;
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:350:6
+ --> $DIR/disallowed-positions.rs:356:6
|
LL | (let 0 = 0)..;
| ^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:354:6
+ --> $DIR/disallowed-positions.rs:360:6
|
LL | (let Range { start: _, end: _ } = true..true || false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:359:6
+ --> $DIR/disallowed-positions.rs:365:6
|
LL | (let true = let true = true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:359:6
+ --> $DIR/disallowed-positions.rs:365:6
|
LL | (let true = let true = true);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:377:6
+ --> $DIR/disallowed-positions.rs:383:6
|
LL | &let 0 = 0
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:389:17
+ --> $DIR/disallowed-positions.rs:395:17
|
LL | true && let 1 = 1
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:394:17
+ --> $DIR/disallowed-positions.rs:401:17
|
LL | true && let 1 = 1
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:399:17
+ --> $DIR/disallowed-positions.rs:407:17
|
LL | true && let 1 = 1
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:410:17
+ --> $DIR/disallowed-positions.rs:419:17
|
LL | true && let 1 = 1
| ^^^^^^^^^
= note: only supported directly in conditions of `if` and `while` expressions
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:419:9
+ --> $DIR/disallowed-positions.rs:429:9
|
LL | if (let Some(a) = opt && true) {
| ^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:419:9
+ --> $DIR/disallowed-positions.rs:429:9
|
LL | if (let Some(a) = opt && true) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:424:9
+ --> $DIR/disallowed-positions.rs:434:9
|
LL | if (let Some(a) = opt) && true {
| ^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:424:9
+ --> $DIR/disallowed-positions.rs:434:9
|
LL | if (let Some(a) = opt) && true {
| ^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:428:9
+ --> $DIR/disallowed-positions.rs:438:9
|
LL | if (let Some(a) = opt) && (let Some(b) = a) {
| ^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:428:9
+ --> $DIR/disallowed-positions.rs:438:9
|
LL | if (let Some(a) = opt) && (let Some(b) = a) {
| ^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:428:32
+ --> $DIR/disallowed-positions.rs:438:32
|
LL | if (let Some(a) = opt) && (let Some(b) = a) {
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:428:32
+ --> $DIR/disallowed-positions.rs:438:32
|
LL | if (let Some(a) = opt) && (let Some(b) = a) {
| ^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:437:9
+ --> $DIR/disallowed-positions.rs:447:9
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
| ^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:437:9
+ --> $DIR/disallowed-positions.rs:447:9
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:437:31
+ --> $DIR/disallowed-positions.rs:447:31
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:437:31
+ --> $DIR/disallowed-positions.rs:447:31
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
| ^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:443:9
+ --> $DIR/disallowed-positions.rs:453:9
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && true {
| ^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:443:9
+ --> $DIR/disallowed-positions.rs:453:9
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && true {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:443:31
+ --> $DIR/disallowed-positions.rs:453:31
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && true {
| ^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:443:31
+ --> $DIR/disallowed-positions.rs:453:31
|
LL | if (let Some(a) = opt && (let Some(b) = a)) && true {
| ^^^^^^^^^^^^^^^
error: `let` expressions are not supported here
- --> $DIR/disallowed-positions.rs:449:9
+ --> $DIR/disallowed-positions.rs:459:9
|
LL | if (let Some(a) = opt && (true)) && true {
| ^^^^^^^^^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/disallowed-positions.rs:449:9
+ --> $DIR/disallowed-positions.rs:459:9
|
LL | if (let Some(a) = opt && (true)) && true {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:110:8
+ --> $DIR/disallowed-positions.rs:114:8
|
LL | if &let 0 = 0 {}
| ^^^^^^^^^^ expected `bool`, found `&bool`
|
error[E0614]: type `bool` cannot be dereferenced
- --> $DIR/disallowed-positions.rs:118:8
+ --> $DIR/disallowed-positions.rs:122:8
|
LL | if *let 0 = 0 {}
| ^^^^^^^^^^
error[E0600]: cannot apply unary operator `-` to type `bool`
- --> $DIR/disallowed-positions.rs:122:8
+ --> $DIR/disallowed-positions.rs:126:8
|
LL | if -let 0 = 0 {}
| ^^^^^^^^^^ cannot apply unary operator `-`
error[E0277]: the `?` operator can only be applied to values that implement `Try`
- --> $DIR/disallowed-positions.rs:132:8
+ --> $DIR/disallowed-positions.rs:136:8
|
LL | if (let 0 = 0)? {}
| ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
= help: the trait `Try` is not implemented for `bool`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
- --> $DIR/disallowed-positions.rs:132:19
+ --> $DIR/disallowed-positions.rs:136:19
|
LL | / fn nested_within_if_expr() {
LL | | if &let 0 = 0 {}
= help: the trait `FromResidual<_>` is not implemented for `()`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:151:8
+ --> $DIR/disallowed-positions.rs:156:8
|
LL | if x = let 0 = 0 {}
| ^^^^^^^^^^^^^ expected `bool`, found `()`
| ~~
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:156:8
+ --> $DIR/disallowed-positions.rs:161:8
|
LL | if true..(let 0 = 0) {}
| ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:160:8
+ --> $DIR/disallowed-positions.rs:165:8
|
LL | if ..(let 0 = 0) {}
| ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
found struct `RangeTo<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:164:8
+ --> $DIR/disallowed-positions.rs:169:8
|
LL | if (let 0 = 0).. {}
| ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
found struct `RangeFrom<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:170:12
+ --> $DIR/disallowed-positions.rs:175:12
|
LL | if let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
found struct `std::ops::Range<_>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:170:8
+ --> $DIR/disallowed-positions.rs:175:8
|
LL | if let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:174:12
+ --> $DIR/disallowed-positions.rs:179:12
|
LL | if let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
found struct `std::ops::Range<_>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:174:8
+ --> $DIR/disallowed-positions.rs:179:8
|
LL | if let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:181:12
+ --> $DIR/disallowed-positions.rs:186:12
|
LL | if let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool`
found struct `std::ops::Range<_>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:181:41
+ --> $DIR/disallowed-positions.rs:186:41
|
LL | if let Range { start: F, end } = F..|| true {}
| ^^^^^^^ expected `bool`, found closure
|
= note: expected type `bool`
- found closure `[closure@$DIR/disallowed-positions.rs:181:41: 181:43]`
+ found closure `[closure@$DIR/disallowed-positions.rs:186:41: 186:43]`
help: use parentheses to call this closure
|
LL | if let Range { start: F, end } = F..(|| true)() {}
| + +++
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:181:8
+ --> $DIR/disallowed-positions.rs:186:8
|
LL | if let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:189:12
+ --> $DIR/disallowed-positions.rs:194:12
|
LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool`
found struct `std::ops::Range<_>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:189:44
+ --> $DIR/disallowed-positions.rs:194:44
|
LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^ expected `bool`, found `&&bool`
|
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:189:8
+ --> $DIR/disallowed-positions.rs:194:8
|
LL | if let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0277]: the `?` operator can only be applied to values that implement `Try`
- --> $DIR/disallowed-positions.rs:128:20
+ --> $DIR/disallowed-positions.rs:132:20
|
LL | if let 0 = 0? {}
| ^^ the `?` operator cannot be applied to type `{integer}`
= help: the trait `Try` is not implemented for `{integer}`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:201:11
+ --> $DIR/disallowed-positions.rs:206:11
|
LL | while &let 0 = 0 {}
| ^^^^^^^^^^ expected `bool`, found `&bool`
|
error[E0614]: type `bool` cannot be dereferenced
- --> $DIR/disallowed-positions.rs:209:11
+ --> $DIR/disallowed-positions.rs:214:11
|
LL | while *let 0 = 0 {}
| ^^^^^^^^^^
error[E0600]: cannot apply unary operator `-` to type `bool`
- --> $DIR/disallowed-positions.rs:213:11
+ --> $DIR/disallowed-positions.rs:218:11
|
LL | while -let 0 = 0 {}
| ^^^^^^^^^^ cannot apply unary operator `-`
error[E0277]: the `?` operator can only be applied to values that implement `Try`
- --> $DIR/disallowed-positions.rs:223:11
+ --> $DIR/disallowed-positions.rs:228:11
|
LL | while (let 0 = 0)? {}
| ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
= help: the trait `Try` is not implemented for `bool`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
- --> $DIR/disallowed-positions.rs:223:22
+ --> $DIR/disallowed-positions.rs:228:22
|
LL | / fn nested_within_while_expr() {
LL | | while &let 0 = 0 {}
= help: the trait `FromResidual<_>` is not implemented for `()`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:242:11
+ --> $DIR/disallowed-positions.rs:248:11
|
LL | while x = let 0 = 0 {}
| ^^^^^^^^^^^^^ expected `bool`, found `()`
| ~~
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:247:11
+ --> $DIR/disallowed-positions.rs:253:11
|
LL | while true..(let 0 = 0) {}
| ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:251:11
+ --> $DIR/disallowed-positions.rs:257:11
|
LL | while ..(let 0 = 0) {}
| ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
found struct `RangeTo<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:255:11
+ --> $DIR/disallowed-positions.rs:261:11
|
LL | while (let 0 = 0).. {}
| ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
found struct `RangeFrom<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:261:15
+ --> $DIR/disallowed-positions.rs:267:15
|
LL | while let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
found struct `std::ops::Range<_>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:261:11
+ --> $DIR/disallowed-positions.rs:267:11
|
LL | while let Range { start: _, end: _ } = true..true && false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:265:15
+ --> $DIR/disallowed-positions.rs:271:15
|
LL | while let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
found struct `std::ops::Range<_>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:265:11
+ --> $DIR/disallowed-positions.rs:271:11
|
LL | while let Range { start: _, end: _ } = true..true || false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:272:15
+ --> $DIR/disallowed-positions.rs:278:15
|
LL | while let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `fn() -> bool`
found struct `std::ops::Range<_>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:272:44
+ --> $DIR/disallowed-positions.rs:278:44
|
LL | while let Range { start: F, end } = F..|| true {}
| ^^^^^^^ expected `bool`, found closure
|
= note: expected type `bool`
- found closure `[closure@$DIR/disallowed-positions.rs:272:44: 272:46]`
+ found closure `[closure@$DIR/disallowed-positions.rs:278:44: 278:46]`
help: use parentheses to call this closure
|
LL | while let Range { start: F, end } = F..(|| true)() {}
| + +++
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:272:11
+ --> $DIR/disallowed-positions.rs:278:11
|
LL | while let Range { start: F, end } = F..|| true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:280:15
+ --> $DIR/disallowed-positions.rs:286:15
|
LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ - this expression has type `&&bool`
found struct `std::ops::Range<_>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:280:47
+ --> $DIR/disallowed-positions.rs:286:47
|
LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^ expected `bool`, found `&&bool`
|
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:280:11
+ --> $DIR/disallowed-positions.rs:286:11
|
LL | while let Range { start: true, end } = t..&&false {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
found struct `std::ops::Range<bool>`
error[E0277]: the `?` operator can only be applied to values that implement `Try`
- --> $DIR/disallowed-positions.rs:219:23
+ --> $DIR/disallowed-positions.rs:224:23
|
LL | while let 0 = 0? {}
| ^^ the `?` operator cannot be applied to type `{integer}`
= help: the trait `Try` is not implemented for `{integer}`
error[E0614]: type `bool` cannot be dereferenced
- --> $DIR/disallowed-positions.rs:309:5
+ --> $DIR/disallowed-positions.rs:315:5
|
LL | *let 0 = 0;
| ^^^^^^^^^^
error[E0600]: cannot apply unary operator `-` to type `bool`
- --> $DIR/disallowed-positions.rs:313:5
+ --> $DIR/disallowed-positions.rs:319:5
|
LL | -let 0 = 0;
| ^^^^^^^^^^ cannot apply unary operator `-`
error[E0277]: the `?` operator can only be applied to values that implement `Try`
- --> $DIR/disallowed-positions.rs:323:5
+ --> $DIR/disallowed-positions.rs:329:5
|
LL | (let 0 = 0)?;
| ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
= help: the trait `Try` is not implemented for `bool`
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
- --> $DIR/disallowed-positions.rs:323:16
+ --> $DIR/disallowed-positions.rs:329:16
|
LL | / fn outside_if_and_while_expr() {
LL | | &let 0 = 0;
= help: the trait `FromResidual<_>` is not implemented for `()`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:354:10
+ --> $DIR/disallowed-positions.rs:360:10
|
LL | (let Range { start: _, end: _ } = true..true || false);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ---- this expression has type `bool`
found struct `std::ops::Range<_>`
error[E0308]: mismatched types
- --> $DIR/disallowed-positions.rs:377:5
+ --> $DIR/disallowed-positions.rs:383:5
|
LL | fn outside_if_and_while_expr() {
| - help: try adding a return type: `-> &bool`
| ^^^^^^^^^^ expected `()`, found `&bool`
error[E0277]: the `?` operator can only be applied to values that implement `Try`
- --> $DIR/disallowed-positions.rs:319:17
+ --> $DIR/disallowed-positions.rs:325:17
|
LL | let 0 = 0?;
| ^^ the `?` operator cannot be applied to type `{integer}`
|
= help: the trait `Try` is not implemented for `{integer}`
-error: aborting due to 208 previous errors
+error: aborting due to 218 previous errors
Some errors have detailed explanations: E0277, E0308, E0600, E0614.
For more information about an error, try `rustc --explain E0277`.
#[link_ordinal(42)]
//~^ ERROR cannot use `#[link_name]` with `#[link_ordinal]`
fn foo();
+ #[link_name="foo"]
+ #[link_ordinal(5)]
+ //~^ ERROR cannot use `#[link_name]` with `#[link_ordinal]`
+ static mut imported_variable: i32;
}
fn main() {}
LL | #[link_ordinal(42)]
| ^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error; 1 warning emitted
+error: cannot use `#[link_name]` with `#[link_ordinal]`
+ --> $DIR/link-ordinal-and-name.rs:11:5
+ |
+LL | #[link_ordinal(5)]
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
#[link_ordinal("JustMonika")]
//~^ ERROR illegal ordinal format in `link_ordinal`
fn foo();
+ #[link_ordinal("JustMonika")]
+ //~^ ERROR illegal ordinal format in `link_ordinal`
+ static mut imported_variable: i32;
}
fn main() {}
|
= note: an unsuffixed integer value, e.g., `1`, is expected
-error: aborting due to previous error; 1 warning emitted
+error: illegal ordinal format in `link_ordinal`
+ --> $DIR/link-ordinal-invalid-format.rs:9:5
+ |
+LL | #[link_ordinal("JustMonika")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: an unsuffixed integer value, e.g., `1`, is expected
+
+error: aborting due to 2 previous errors; 1 warning emitted
#[link_ordinal()]
//~^ ERROR incorrect number of arguments to `#[link_ordinal]`
fn foo();
+ #[link_ordinal()]
+ //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
+ static mut imported_variable: i32;
}
fn main() {}
|
= note: the attribute requires exactly one argument
-error: aborting due to previous error; 1 warning emitted
+error: incorrect number of arguments to `#[link_ordinal]`
+ --> $DIR/link-ordinal-missing-argument.rs:9:5
+ |
+LL | #[link_ordinal()]
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: the attribute requires exactly one argument
+
+error: aborting due to 2 previous errors; 1 warning emitted
#[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes
#[link_ordinal(2)]
fn foo();
+ #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes
+ #[link_ordinal(2)]
+ static mut imported_variable: i32;
}
fn main() {}
LL | #[link_ordinal(2)]
| ^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error; 1 warning emitted
+error: multiple `link_ordinal` attributes
+ --> $DIR/link-ordinal-multiple.rs:10:5
+ |
+LL | #[link_ordinal(1)]
+ | ^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ |
+note: attribute also specified here
+ --> $DIR/link-ordinal-multiple.rs:11:5
+ |
+LL | #[link_ordinal(2)]
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
--- /dev/null
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link_ordinal(123)]
+//~^ ERROR attribute should be applied to a foreign function or static
+struct Foo {}
+
+#[link_ordinal(123)]
+//~^ ERROR attribute should be applied to a foreign function or static
+fn test() {}
+
+#[link_ordinal(42)]
+//~^ ERROR attribute should be applied to a foreign function or static
+static mut imported_val: i32 = 123;
+
+#[link(name = "exporter", kind = "raw-dylib")]
+extern {
+ #[link_ordinal(13)]
+ fn imported_function();
+
+ #[link_ordinal(42)]
+ static mut imported_variable: i32;
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/link-ordinal-not-foreign-fn.rs:1:12
+ |
+LL | #![feature(raw_dylib)]
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: attribute should be applied to a foreign function or static
+ --> $DIR/link-ordinal-not-foreign-fn.rs:4:1
+ |
+LL | #[link_ordinal(123)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: attribute should be applied to a foreign function or static
+ --> $DIR/link-ordinal-not-foreign-fn.rs:8:1
+ |
+LL | #[link_ordinal(123)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: attribute should be applied to a foreign function or static
+ --> $DIR/link-ordinal-not-foreign-fn.rs:12:1
+ |
+LL | #[link_ordinal(42)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
#[link_ordinal(72436)]
//~^ ERROR ordinal value in `link_ordinal` is too large: `72436`
fn foo();
+ #[link_ordinal(72436)]
+ //~^ ERROR ordinal value in `link_ordinal` is too large: `72436`
+ static mut imported_variable: i32;
}
fn main() {}
|
= note: the value may not exceed `u16::MAX`
-error: aborting due to previous error; 1 warning emitted
+error: ordinal value in `link_ordinal` is too large: `72436`
+ --> $DIR/link-ordinal-too-large.rs:9:5
+ |
+LL | #[link_ordinal(72436)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the value may not exceed `u16::MAX`
+
+error: aborting due to 2 previous errors; 1 warning emitted
#[link_ordinal(3, 4)]
//~^ ERROR incorrect number of arguments to `#[link_ordinal]`
fn foo();
+ #[link_ordinal(3, 4)]
+ //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
+ static mut imported_variable: i32;
}
fn main() {}
|
= note: the attribute requires exactly one argument
-error: aborting due to previous error; 1 warning emitted
+error: incorrect number of arguments to `#[link_ordinal]`
+ --> $DIR/link-ordinal-too-many-arguments.rs:9:5
+ |
+LL | #[link_ordinal(3, 4)]
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the attribute requires exactly one argument
+
+error: aborting due to 2 previous errors; 1 warning emitted
--- /dev/null
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link(name = "foo")]
+extern "C" {
+ #[link_ordinal(3)]
+ //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+ fn foo();
+}
+
+#[link(name = "bar", kind = "static")]
+extern "C" {
+ #[link_ordinal(3)]
+ //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+ fn bar();
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/link-ordinal-unsupported-link-kind.rs:1:12
+ |
+LL | #![feature(raw_dylib)]
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+ --> $DIR/link-ordinal-unsupported-link-kind.rs:6:5
+ |
+LL | #[link_ordinal(3)]
+ | ^^^^^^^^^^^^^^^^^^
+
+error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+ --> $DIR/link-ordinal-unsupported-link-kind.rs:13:5
+ |
+LL | #[link_ordinal(3)]
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
}
fn main() {
- struct HasDropGlue(Box<u8>);
+ struct HasDropGlue(#[allow(unused_tuple_struct_fields)] Box<u8>);
struct HasDropImpl;
impl Drop for HasDropImpl {
fn drop(&mut self) {
}
#[r#derive(r#Debug)]
-struct Test2(u32);
+struct Test2(#[allow(unused_tuple_struct_fields)] u32);
pub fn main() {
assert_eq!(mem::size_of::<Test>(), 9);
type X = i32;
fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
//~^ ERROR
- 0
+ #[doc(alias = "stmt")] //~ ERROR
+ let x = 0;
+ #[doc(alias = "expr")] //~ ERROR
+ match x {
+ #[doc(alias = "arm")] //~ ERROR
+ _ => 0
+ }
}
}
LL | fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
| ^^^^^^^^^^^^^^^^^^^^^
-error: `#[doc(alias = "...")]` isn't allowed on extern block
+error: `#[doc(alias = "...")]` isn't allowed on foreign module
--> $DIR/check-doc-alias-attr-location.rs:9:7
|
LL | #[doc(alias = "foo")]
LL | #[doc(alias = "assoc")]
| ^^^^^^^^^^^^^^^
-error: aborting due to 5 previous errors
+error: `#[doc(alias = "...")]` isn't allowed on statement
+ --> $DIR/check-doc-alias-attr-location.rs:24:15
+ |
+LL | #[doc(alias = "stmt")]
+ | ^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` isn't allowed on expression
+ --> $DIR/check-doc-alias-attr-location.rs:26:15
+ |
+LL | #[doc(alias = "expr")]
+ | ^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` isn't allowed on match arm
+ --> $DIR/check-doc-alias-attr-location.rs:28:19
+ |
+LL | #[doc(alias = "arm")]
+ | ^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
--- /dev/null
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+trait X {}
+trait Y: X {}
+trait Z {
+ type Assoc: Y;
+}
+struct A<T>(T);
+
+impl<T> Y for T where T: X {}
+impl<T: X> Z for A<T> {
+ type Assoc = T;
+}
+
+// this impl is invalid, but causes an ICE anyway
+impl<T> From<<A<T> as Z>::Assoc> for T {}
+//~^ ERROR type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
+
+fn main() {}
--- /dev/null
+error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
+ --> $DIR/issue-43037.rs:17:6
+ |
+LL | impl<T> From<<A<T> as Z>::Assoc> for T {}
+ | ^ type parameter `T` must be used as the type parameter for some local type
+ |
+ = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
+ = note: only traits defined in the current crate can be implemented for a type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0210`.
--- /dev/null
+//~ ERROR overflow evaluating the requirement `T: Trait<_>`
+
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+pub trait Trait<T> {}
+
+default impl<T, U> Trait<T> for U {}
+
+impl<T> Trait<<T as Iterator>::Item> for T {}
+
+fn main() {}
--- /dev/null
+error[E0275]: overflow evaluating the requirement `T: Trait<_>`
+ |
+ = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_45814`)
+note: required because of the requirements on the impl of `Trait<_>` for `T`
+ --> $DIR/issue-45814.rs:8:20
+ |
+LL | default impl<T, U> Trait<T> for U {}
+ | ^^^^^^^^ ^
+ = note: 128 redundant requirements hidden
+ = note: required because of the requirements on the impl of `Trait<_>` for `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
struct MarkedAndClone;
impl MyMarker for MarkedAndClone {}
-struct MyType<T>(T);
+struct MyType<T>(#[allow(unused_tuple_struct_fields)] T);
impl<T> Foo for MyType<T> {
default fn foo(&self) -> &'static str {
"generic MyType"
type Item = &'a u32;
}
-struct Cloned<I>(I);
+struct Cloned<I>(#[allow(unused_tuple_struct_fields)] I);
impl<'a, I, T: 'a> Iterator for Cloned<I>
where I: WithAssoc<Item=&'a T>, T: Clone
--- /dev/null
+#![crate_type = "lib"]
+#![feature(staged_api, rustc_attrs)]
+#![stable(feature = "stable_feature", since = "1.0.0")]
+
+#[stable(feature = "stable_feature", since = "1.0.0")]
+pub trait JustTrait {
+ #[stable(feature = "stable_feature", since = "1.0.0")]
+ #[rustc_default_body_unstable(feature = "constant_default_body", issue = "none")]
+ const CONSTANT: usize = 0;
+
+ #[rustc_default_body_unstable(feature = "fun_default_body", issue = "none")]
+ #[stable(feature = "stable_feature", since = "1.0.0")]
+ fn fun() {}
+}
+
+#[rustc_must_implement_one_of(eq, neq)]
+#[stable(feature = "stable_feature", since = "1.0.0")]
+pub trait Equal {
+ #[rustc_default_body_unstable(feature = "eq_default_body", issue = "none")]
+ #[stable(feature = "stable_feature", since = "1.0.0")]
+ fn eq(&self, other: &Self) -> bool {
+ !self.neq(other)
+ }
+
+ #[stable(feature = "stable_feature", since = "1.0.0")]
+ fn neq(&self, other: &Self) -> bool {
+ !self.eq(other)
+ }
+}
--- /dev/null
+// aux-build:default_body.rs
+#![crate_type = "lib"]
+
+extern crate default_body;
+
+use default_body::{Equal, JustTrait};
+
+struct Type;
+
+impl JustTrait for Type {}
+//~^ ERROR not all trait items implemented, missing: `CONSTANT` [E0046]
+//~| ERROR not all trait items implemented, missing: `fun` [E0046]
+
+impl Equal for Type {
+ //~^ ERROR not all trait items implemented, missing: `eq` [E0046]
+ fn neq(&self, other: &Self) -> bool {
+ false
+ }
+}
--- /dev/null
+error[E0046]: not all trait items implemented, missing: `CONSTANT`
+ --> $DIR/default-body-stability-err.rs:10:1
+ |
+LL | impl JustTrait for Type {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: default implementation of `CONSTANT` is unstable
+ = note: use of unstable library feature 'constant_default_body'
+ = help: add `#![feature(constant_default_body)]` to the crate attributes to enable
+
+error[E0046]: not all trait items implemented, missing: `fun`
+ --> $DIR/default-body-stability-err.rs:10:1
+ |
+LL | impl JustTrait for Type {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: default implementation of `fun` is unstable
+ = note: use of unstable library feature 'fun_default_body'
+ = help: add `#![feature(fun_default_body)]` to the crate attributes to enable
+
+error[E0046]: not all trait items implemented, missing: `eq`
+ --> $DIR/default-body-stability-err.rs:14:1
+ |
+LL | / impl Equal for Type {
+LL | |
+LL | | fn neq(&self, other: &Self) -> bool {
+LL | | false
+LL | | }
+LL | | }
+ | |_^
+ |
+ = note: default implementation of `eq` is unstable
+ = note: use of unstable library feature 'eq_default_body'
+ = help: add `#![feature(eq_default_body)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0046`.
--- /dev/null
+// check-pass
+// aux-build:default_body.rs
+#![crate_type = "lib"]
+#![feature(fun_default_body, eq_default_body, constant_default_body)]
+
+extern crate default_body;
+
+use default_body::{Equal, JustTrait};
+
+struct Type;
+
+impl JustTrait for Type {}
+
+impl Equal for Type {
+ fn neq(&self, other: &Self) -> bool {
+ false
+ }
+}
--- /dev/null
+// check-pass
+// aux-build:default_body.rs
+#![crate_type = "lib"]
+
+extern crate default_body;
+
+use default_body::{Equal, JustTrait};
+
+struct Type;
+
+impl JustTrait for Type {
+ const CONSTANT: usize = 1;
+
+ fn fun() {}
+}
+
+impl Equal for Type {
+ fn eq(&self, other: &Self) -> bool {
+ false
+ }
+}
--- /dev/null
+// check-pass
+// compile-flags: -Zhir-stats
+// only-x86_64
+
+// The aim here is to include at least one of every different type of top-level
+// AST/HIR node reported by `-Zhir-stats`.
+
+#![allow(dead_code)]
+
+use std::arch::asm;
+use std::fmt::Debug;
+use std::ffi::c_void;
+
+extern "C" { fn f(p: *mut c_void); }
+
+/// An enum.
+enum E<'a, T: Copy> { A { t: T }, B(&'a u32) }
+
+trait Go {
+ type G: Debug;
+ fn go(self) -> u32;
+}
+
+impl<'a, T: Copy> Go for E<'a, T> {
+ type G = bool;
+ fn go(self) -> u32 {
+ 99
+ }
+}
+
+fn f2<T>(t: T) where T: Debug {}
+
+fn main() {
+ let x = E::A { t: 3 };
+ match x {
+ E::A { .. } => {}
+ _ => {}
+ }
+
+ unsafe { asm!("mov rdi, 1"); }
+}
--- /dev/null
+
+PRE EXPANSION AST STATS
+
+Name Accumulated Size Count Item Size
+----------------------------------------------------------------
+ExprField 48 ( 0.5%) 1 48
+GenericArgs 64 ( 0.7%) 1 64
+- AngleBracketed 64 ( 0.7%) 1
+Local 72 ( 0.8%) 1 72
+WherePredicate 72 ( 0.8%) 1 72
+- BoundPredicate 72 ( 0.8%) 1
+Crate 72 ( 0.8%) 1 72
+Arm 96 ( 1.0%) 2 48
+FieldDef 160 ( 1.7%) 2 80
+ForeignItem 160 ( 1.7%) 1 160
+- Fn 160 ( 1.7%) 1
+Stmt 160 ( 1.7%) 5 32
+- Local 32 ( 0.3%) 1
+- MacCall 32 ( 0.3%) 1
+- Expr 96 ( 1.0%) 3
+Param 160 ( 1.7%) 4 40
+FnDecl 200 ( 2.2%) 5 40
+Variant 240 ( 2.6%) 2 120
+Block 288 ( 3.1%) 6 48
+Attribute 304 ( 3.3%) 2 152
+- Normal 152 ( 1.7%) 1
+- DocComment 152 ( 1.7%) 1
+GenericBound 352 ( 3.8%) 4 88
+- Trait 352 ( 3.8%) 4
+GenericParam 520 ( 5.7%) 5 104
+AssocItem 640 ( 7.0%) 4 160
+- TyAlias 320 ( 3.5%) 2
+- Fn 320 ( 3.5%) 2
+PathSegment 720 ( 7.9%) 30 24
+Expr 832 ( 9.1%) 8 104
+- Path 104 ( 1.1%) 1
+- Match 104 ( 1.1%) 1
+- Struct 104 ( 1.1%) 1
+- Lit 208 ( 2.3%) 2
+- Block 312 ( 3.4%) 3
+Pat 840 ( 9.2%) 7 120
+- Struct 120 ( 1.3%) 1
+- Wild 120 ( 1.3%) 1
+- Ident 600 ( 6.6%) 5
+Ty 1_344 (14.7%) 14 96
+- Rptr 96 ( 1.0%) 1
+- Ptr 96 ( 1.0%) 1
+- ImplicitSelf 192 ( 2.1%) 2
+- Path 960 (10.5%) 10
+Item 1_800 (19.7%) 9 200
+- Trait 200 ( 2.2%) 1
+- Enum 200 ( 2.2%) 1
+- ForeignMod 200 ( 2.2%) 1
+- Impl 200 ( 2.2%) 1
+- Fn 400 ( 4.4%) 2
+- Use 600 ( 6.6%) 3
+----------------------------------------------------------------
+Total 9_144
+
+
+POST EXPANSION AST STATS
+
+Name Accumulated Size Count Item Size
+----------------------------------------------------------------
+ExprField 48 ( 0.5%) 1 48
+GenericArgs 64 ( 0.6%) 1 64
+- AngleBracketed 64 ( 0.6%) 1
+Local 72 ( 0.7%) 1 72
+WherePredicate 72 ( 0.7%) 1 72
+- BoundPredicate 72 ( 0.7%) 1
+Crate 72 ( 0.7%) 1 72
+Arm 96 ( 0.9%) 2 48
+InlineAsm 120 ( 1.2%) 1 120
+FieldDef 160 ( 1.6%) 2 80
+ForeignItem 160 ( 1.6%) 1 160
+- Fn 160 ( 1.6%) 1
+Stmt 160 ( 1.6%) 5 32
+- Local 32 ( 0.3%) 1
+- Semi 32 ( 0.3%) 1
+- Expr 96 ( 0.9%) 3
+Param 160 ( 1.6%) 4 40
+FnDecl 200 ( 2.0%) 5 40
+Variant 240 ( 2.4%) 2 120
+Block 288 ( 2.8%) 6 48
+GenericBound 352 ( 3.5%) 4 88
+- Trait 352 ( 3.5%) 4
+GenericParam 520 ( 5.1%) 5 104
+Attribute 608 ( 6.0%) 4 152
+- DocComment 152 ( 1.5%) 1
+- Normal 456 ( 4.5%) 3
+AssocItem 640 ( 6.3%) 4 160
+- TyAlias 320 ( 3.2%) 2
+- Fn 320 ( 3.2%) 2
+PathSegment 792 ( 7.8%) 33 24
+Pat 840 ( 8.3%) 7 120
+- Struct 120 ( 1.2%) 1
+- Wild 120 ( 1.2%) 1
+- Ident 600 ( 5.9%) 5
+Expr 936 ( 9.2%) 9 104
+- Path 104 ( 1.0%) 1
+- Match 104 ( 1.0%) 1
+- Struct 104 ( 1.0%) 1
+- InlineAsm 104 ( 1.0%) 1
+- Lit 208 ( 2.1%) 2
+- Block 312 ( 3.1%) 3
+Ty 1_344 (13.2%) 14 96
+- Rptr 96 ( 0.9%) 1
+- Ptr 96 ( 0.9%) 1
+- ImplicitSelf 192 ( 1.9%) 2
+- Path 960 ( 9.5%) 10
+Item 2_200 (21.7%) 11 200
+- Trait 200 ( 2.0%) 1
+- Enum 200 ( 2.0%) 1
+- ExternCrate 200 ( 2.0%) 1
+- ForeignMod 200 ( 2.0%) 1
+- Impl 200 ( 2.0%) 1
+- Fn 400 ( 3.9%) 2
+- Use 800 ( 7.9%) 4
+----------------------------------------------------------------
+Total 10_144
+
+
+HIR STATS
+
+Name Accumulated Size Count Item Size
+----------------------------------------------------------------
+Param 64 ( 0.7%) 2 32
+Local 64 ( 0.7%) 1 64
+ForeignItem 72 ( 0.7%) 1 72
+FieldDef 96 ( 1.0%) 2 48
+Arm 96 ( 1.0%) 2 48
+Stmt 96 ( 1.0%) 3 32
+FnDecl 120 ( 1.2%) 3 40
+Lifetime 128 ( 1.3%) 4 32
+Variant 160 ( 1.6%) 2 80
+ImplItem 176 ( 1.8%) 2 88
+GenericBound 192 ( 2.0%) 4 48
+TraitItem 192 ( 2.0%) 2 96
+WherePredicate 216 ( 2.2%) 3 72
+Block 288 ( 3.0%) 6 48
+QPath 408 ( 4.2%) 17 24
+Pat 440 ( 4.5%) 5 88
+Attribute 608 ( 6.2%) 4 152
+Expr 672 ( 6.9%) 12 56
+Item 960 ( 9.9%) 12 80
+Ty 1_152 (11.8%) 16 72
+Path 1_296 (13.3%) 27 48
+PathSegment 2_240 (23.0%) 40 56
+----------------------------------------------------------------
+Total 9_736
+
// compile-flags:-g
// compile-flags:-Cstrip=none
-#![feature(backtrace)]
-
use std::env;
use std::process::Command;
use std::str;
}
}
+#[allow(unused_tuple_struct_fields)]
struct S<T:?Sized>(u32, T);
fn main() {
std::mem::size_of::<T>()
}
-struct Foo(i64);
+struct Foo(#[allow(unused_tuple_struct_fields)] i64);
// Test that the (symbol) mangling of `Foo` (the `struct` type) and that of
// `typeof Foo` (the function type of the `struct` constructor) don't collide.
// run-pass
#![allow(dead_code)]
-#![feature(box_syntax)]
use std::mem;
assert_eq!(mem::size_of_val(&a), 32);
assert!(is_aligned_to(&a, 16));
- let mut large = box AlignLarge {
+ let mut large = Box::new(AlignLarge {
stuff: [0; 0x10000],
- };
+ });
large.stuff[0] = 132;
*large.stuff.last_mut().unwrap() = 102;
assert_eq!(large.stuff[0], 132);
trait Trait { fn dummy(&self) { } }
trait Mirror { type Image; }
impl<T> Mirror for T { type Image = T; }
-struct ParamTypeStruct<T>(T);
-struct AssocTypeStruct<T>(<T as Mirror>::Image);
+struct ParamTypeStruct<T>(#[allow(unused_tuple_struct_fields)] T);
+struct AssocTypeStruct<T>(#[allow(unused_tuple_struct_fields)] <T as Mirror>::Image);
#[repr(transparent)]
union MaybeUninitUnion<T: Copy> {
_value: T,
struct Foo {
_a: Box<isize>
}
- struct Bar(Box<isize>);
+ struct Bar(#[allow(unused_tuple_struct_fields)] Box<isize>);
// Should apply through structs
assert_eq!(size_of::<Foo>(), size_of::<Option<Foo>>());
* represented with nullable pointers could be misoptimized in some cases.
*/
-enum List<X> { Nil, Cons(X, Box<List<X>>) }
+enum List<X> { Nil, Cons(X, #[allow(unused_tuple_struct_fields)] Box<List<X>>) }
pub fn main() {
match List::Cons(10, Box::new(List::Nil)) {
List::Cons(10, _) => {}
}
}
-enum option<T> { none, some(T), }
+enum option<T> { none, some(#[allow(unused_tuple_struct_fields)] T), }
fn sink(_res: option<close_res>) { }
// run-pass
+#[allow(unused_tuple_struct_fields)]
#[derive(Debug)]
struct Foo(isize, isize);
// run-pass
-pub struct Z(&'static Z);
+pub struct Z(#[allow(unused_tuple_struct_fields)] &'static Z);
pub fn main() {}
// note: do not suggest because of `E: usize`
let x: &Result<usize, usize> = &Ok(3);
let y: Result<&usize, usize> = x; //~ ERROR mismatched types [E0308]
+
+ let multiple_ref_opt = &&Some(Foo);
+ multiple_ref_opt.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308]
+ multiple_ref_opt.and_then(|arg| Some(takes_ref(arg))); //~ ERROR mismatched types [E0308]
+ let multiple_ref_result = &&Ok(Foo);
+ multiple_ref_result.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308]
+ multiple_ref_result.and_then(|arg| Ok(takes_ref(arg))); //~ ERROR mismatched types [E0308]
}
= note: expected enum `Result<&usize, usize>`
found reference `&Result<usize, usize>`
-error: aborting due to 7 previous errors
+error[E0308]: mismatched types
+ --> $DIR/as-ref.rs:22:42
+ |
+LL | multiple_ref_opt.map(|arg| takes_ref(arg));
+ | --- --------- ^^^ expected `&Foo`, found struct `Foo`
+ | | |
+ | | arguments to this function are incorrect
+ | help: consider using `as_ref` instead: `as_ref().map`
+ |
+note: function defined here
+ --> $DIR/as-ref.rs:3:4
+ |
+LL | fn takes_ref(_: &Foo) {}
+ | ^^^^^^^^^ -------
+
+error[E0308]: mismatched types
+ --> $DIR/as-ref.rs:23:52
+ |
+LL | multiple_ref_opt.and_then(|arg| Some(takes_ref(arg)));
+ | -------- --------- ^^^ expected `&Foo`, found struct `Foo`
+ | | |
+ | | arguments to this function are incorrect
+ | help: consider using `as_ref` instead: `as_ref().and_then`
+ |
+note: function defined here
+ --> $DIR/as-ref.rs:3:4
+ |
+LL | fn takes_ref(_: &Foo) {}
+ | ^^^^^^^^^ -------
+
+error[E0308]: mismatched types
+ --> $DIR/as-ref.rs:25:45
+ |
+LL | multiple_ref_result.map(|arg| takes_ref(arg));
+ | --- --------- ^^^ expected `&Foo`, found struct `Foo`
+ | | |
+ | | arguments to this function are incorrect
+ | help: consider using `as_ref` instead: `as_ref().map`
+ |
+note: function defined here
+ --> $DIR/as-ref.rs:3:4
+ |
+LL | fn takes_ref(_: &Foo) {}
+ | ^^^^^^^^^ -------
+
+error[E0308]: mismatched types
+ --> $DIR/as-ref.rs:26:53
+ |
+LL | multiple_ref_result.and_then(|arg| Ok(takes_ref(arg)));
+ | -------- --------- ^^^ expected `&Foo`, found struct `Foo`
+ | | |
+ | | arguments to this function are incorrect
+ | help: consider using `as_ref` instead: `as_ref().and_then`
+ |
+note: function defined here
+ --> $DIR/as-ref.rs:3:4
+ |
+LL | fn takes_ref(_: &Foo) {}
+ | ^^^^^^^^^ -------
+
+error: aborting due to 11 previous errors
For more information about this error, try `rustc --explain E0308`.
const C2 = 42;
//~^ ERROR missing type for `const` item
//~| HELP provide a type for the item
-//~| SUGGESTION C2: <type>
+//~| SUGGESTION : <type>
#[cfg(FALSE)]
static S2 = "abc";
//~^ ERROR missing type for `static` item
//~| HELP provide a type for the item
-//~| SUGGESTION S2: <type>
+//~| SUGGESTION : <type>
#[cfg(FALSE)]
static mut SM2 = "abc";
//~^ ERROR missing type for `static mut` item
//~| HELP provide a type for the item
-//~| SUGGESTION SM2: <type>
+//~| SUGGESTION : <type>
// These will, so the diagnostics should be stolen by typeck:
const C = 42;
//~^ ERROR missing type for `const` item
//~| HELP provide a type for the constant
-//~| SUGGESTION C: i32
+//~| SUGGESTION : i32
const D = &&42;
//~^ ERROR missing type for `const` item
//~| HELP provide a type for the constant
-//~| SUGGESTION D: &&i32
+//~| SUGGESTION : &&i32
static S = Vec::<String>::new();
//~^ ERROR missing type for `static` item
//~| HELP provide a type for the static variable
-//~| SUGGESTION S: Vec<String>
+//~| SUGGESTION : Vec<String>
static mut SM = "abc";
//~^ ERROR missing type for `static mut` item
//~| HELP provide a type for the static variable
-//~| SUGGESTION &str
+//~| SUGGESTION : &str
error: missing type for `const` item
- --> $DIR/const-no-type.rs:33:7
+ --> $DIR/const-no-type.rs:33:8
|
LL | const C = 42;
- | ^ help: provide a type for the constant: `C: i32`
+ | ^ help: provide a type for the constant: `: i32`
error: missing type for `const` item
- --> $DIR/const-no-type.rs:38:7
+ --> $DIR/const-no-type.rs:38:8
|
LL | const D = &&42;
- | ^ help: provide a type for the constant: `D: &&i32`
+ | ^ help: provide a type for the constant: `: &&i32`
error: missing type for `static` item
- --> $DIR/const-no-type.rs:43:8
+ --> $DIR/const-no-type.rs:43:9
|
LL | static S = Vec::<String>::new();
- | ^ help: provide a type for the static variable: `S: Vec<String>`
+ | ^ help: provide a type for the static variable: `: Vec<String>`
error: missing type for `static mut` item
- --> $DIR/const-no-type.rs:48:12
+ --> $DIR/const-no-type.rs:48:14
|
LL | static mut SM = "abc";
- | ^^ help: provide a type for the static variable: `SM: &str`
+ | ^ help: provide a type for the static variable: `: &str`
error: missing type for `const` item
- --> $DIR/const-no-type.rs:14:7
+ --> $DIR/const-no-type.rs:14:9
|
LL | const C2 = 42;
- | ^^ help: provide a type for the item: `C2: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: missing type for `static` item
- --> $DIR/const-no-type.rs:20:8
+ --> $DIR/const-no-type.rs:20:10
|
LL | static S2 = "abc";
- | ^^ help: provide a type for the item: `S2: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: missing type for `static mut` item
- --> $DIR/const-no-type.rs:26:12
+ --> $DIR/const-no-type.rs:26:15
|
LL | static mut SM2 = "abc";
- | ^^^ help: provide a type for the item: `SM2: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: aborting due to 7 previous errors
-error[E0507]: cannot move out of `s.0` which is behind a shared reference
+error[E0507]: cannot move out of `s` which is behind a shared reference
--> $DIR/simple.rs:38:17
|
LL | let X(_t) = *s;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
--> $DIR/simple.rs:42:30
|
LL | if let Either::One(_t) = *r { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
--> $DIR/simple.rs:46:33
|
LL | while let Either::One(_t) = *r { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `Two` which is behind a shared reference
--> $DIR/simple.rs:50:11
|
LL | match *r {
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
--> $DIR/simple.rs:57:11
|
LL | match *r {
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `sm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `sm` which is behind a mutable reference
--> $DIR/simple.rs:66:17
|
LL | let X(_t) = *sm;
| data moved here
| move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
--> $DIR/simple.rs:70:30
|
LL | if let Either::One(_t) = *rm { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
--> $DIR/simple.rs:74:33
|
LL | while let Either::One(_t) = *rm { }
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `Two` which is behind a mutable reference
--> $DIR/simple.rs:78:11
|
LL | match *rm {
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
--> $DIR/simple.rs:85:11
|
LL | match *rm {
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
--> $DIR/simple.rs:93:11
|
LL | match *rm {
| data moved here
| move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-error[E0507]: cannot move out of `s.0` which is behind a shared reference
+error[E0507]: cannot move out of `s` which is behind a shared reference
--> $DIR/simple.rs:168:18
|
LL | let &X(_t) = s;
| | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
| help: consider removing the `&`: `X(_t)`
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
--> $DIR/simple.rs:172:31
|
LL | if let &Either::One(_t) = r { }
| | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
| help: consider removing the `&`: `Either::One(_t)`
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
--> $DIR/simple.rs:176:34
|
LL | while let &Either::One(_t) = r { }
| | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
| help: consider removing the `&`: `Either::One(_t)`
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `Two` which is behind a shared reference
--> $DIR/simple.rs:180:11
|
LL | match r {
LL ~ | &Either::Two(_t) => (),
|
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
--> $DIR/simple.rs:188:11
|
LL | match r {
| | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
| help: consider removing the `&`: `Either::One(_t)`
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
--> $DIR/simple.rs:195:11
|
LL | match r {
| | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
| help: consider removing the `&`: `Either::One(_t)`
-error[E0507]: cannot move out of `sm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `sm` which is behind a mutable reference
--> $DIR/simple.rs:207:22
|
LL | let &mut X(_t) = sm;
| | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
| help: consider removing the `&mut`: `X(_t)`
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
--> $DIR/simple.rs:211:35
|
LL | if let &mut Either::One(_t) = rm { }
| | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
| help: consider removing the `&mut`: `Either::One(_t)`
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
--> $DIR/simple.rs:215:38
|
LL | while let &mut Either::One(_t) = rm { }
| | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
| help: consider removing the `&mut`: `Either::One(_t)`
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `Two` which is behind a mutable reference
--> $DIR/simple.rs:219:11
|
LL | match rm {
LL | Either::Two(_t) => (),
| ~~~~~~~~~~~~~~~
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
--> $DIR/simple.rs:228:11
|
LL | match rm {
| | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
| help: consider removing the `&mut`: `Either::One(_t)`
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
--> $DIR/simple.rs:235:11
|
LL | match rm {
| | move occurs because `_t` has type `X`, which does not implement the `Copy` trait
| help: consider removing the `&mut`: `Either::One(_t)`
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
--> $DIR/simple.rs:242:11
|
LL | match rm {
--- /dev/null
+use a::TyCtxt;
+
+mod a {
+ use std::ops::Deref;
+ pub struct TyCtxt<'tcx> {
+ gcx: &'tcx GlobalCtxt<'tcx>,
+ }
+
+ impl<'tcx> Deref for TyCtxt<'tcx> {
+ type Target = &'tcx GlobalCtxt<'tcx>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.gcx
+ }
+ }
+
+ pub struct GlobalCtxt<'tcx> {
+ pub sess: &'tcx Session,
+ _t: &'tcx (),
+ }
+
+ pub struct Session {
+ pub opts: (),
+ }
+}
+
+mod b {
+ fn foo<'tcx>(tcx: crate::TyCtxt<'tcx>) {
+ tcx.opts;
+ //~^ ERROR no field `opts` on type `TyCtxt<'tcx>`
+ //~| HELP one of the expressions' fields has a field of the same name
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0609]: no field `opts` on type `TyCtxt<'tcx>`
+ --> $DIR/field-access-considering-privacy.rs:29:13
+ |
+LL | tcx.opts;
+ | ^^^^ unknown field
+ |
+help: one of the expressions' fields has a field of the same name
+ |
+LL | tcx.sess.opts;
+ | +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.
error: missing type for `const` item
- --> $DIR/unnamable-types.rs:6:7
+ --> $DIR/unnamable-types.rs:6:8
|
LL | const A = 5;
- | ^ help: provide a type for the constant: `A: i32`
+ | ^ help: provide a type for the constant: `: i32`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
--> $DIR/unnamable-types.rs:10:11
| ^^^^^
error: missing type for `const` item
- --> $DIR/unnamable-types.rs:23:7
+ --> $DIR/unnamable-types.rs:23:8
|
LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
- | ^
+ | ^
|
note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:45]>` cannot be named
--> $DIR/unnamable-types.rs:23:11
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing type for `const` item
- --> $DIR/unnamable-types.rs:29:7
+ --> $DIR/unnamable-types.rs:29:8
|
LL | const E = foo;
- | ^ help: provide a type for the constant: `E: fn() -> i32`
+ | ^ help: provide a type for the constant: `: fn() -> i32`
error: missing type for `const` item
- --> $DIR/unnamable-types.rs:32:7
+ --> $DIR/unnamable-types.rs:32:8
|
LL | const F = S { t: foo };
- | ^ help: provide a type for the constant: `F: S<fn() -> i32>`
+ | ^ help: provide a type for the constant: `: S<fn() -> i32>`
error: missing type for `const` item
- --> $DIR/unnamable-types.rs:37:7
+ --> $DIR/unnamable-types.rs:37:8
|
LL | const G = || -> i32 { yield 0; return 1; };
- | ^
+ | ^
|
note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:20]` cannot be named
--> $DIR/unnamable-types.rs:37:11
+++ /dev/null
-// Black and White have the same discriminator value ...
-
-enum Color {
- //~^ ERROR discriminant value `0` assigned more than once
- Red = 0xff0000,
- Green = 0x00ff00,
- Blue = 0x0000ff,
- Black = 0x000000,
- White = 0x000000,
-}
-
-fn main() { }
+++ /dev/null
-error[E0081]: discriminant value `0` assigned more than once
- --> $DIR/tag-variant-disr-dup.rs:3:1
- |
-LL | enum Color {
- | ^^^^^^^^^^
-...
-LL | Black = 0x000000,
- | -------- first assignment of `0`
-LL | White = 0x000000,
- | -------- second assignment of `0`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0081`.
fn f<T,>(_: T,) {}
-struct Foo<T,>(T);
+struct Foo<T,>(#[allow(unused_tuple_struct_fields)] T);
struct Bar;
}
enum Baz {
- Qux(isize,),
+ Qux(#[allow(unused_tuple_struct_fields)] isize,),
}
#[allow(unused,)]
use std::vec::IntoIter;
-pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
+pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
type Key;
}
impl Foo for IntoIter<i32> {
- type Key = u32; //~ ERROR type mismatch
+ type Key = u32;
+ //~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
}
-fn main() {
-}
+fn main() {}
-error[E0271]: type mismatch resolving `<std::vec::IntoIter<i32> as Iterator>::Item == u32`
+error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
--> $DIR/assoc-type-in-superbad.rs:12:16
|
LL | type Key = u32;
note: required by a bound in `Foo`
--> $DIR/assoc-type-in-superbad.rs:7:25
|
-LL | pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
- | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
+LL | pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
error: aborting due to previous error
// run-pass
use std::ops::AddAssign;
-struct Int(i32);
+struct Int(#[allow(unused_tuple_struct_fields)] i32);
impl AddAssign for Int {
fn add_assign(&mut self, _: Int) {
LL | / fn recurse<T>(elements: T) -> Vec<char>
LL | | where
LL | | T: Iterator<Item = ()>,
-LL | | {
-LL | | recurse(IteratorOfWrapped(elements).map(|t| t.0))
- | | ------------------------------------------------- recursive call site
-LL | | }
- | |_^ cannot return without recursing
+ | |___________________________^ cannot return without recursing
+LL | {
+LL | recurse(IteratorOfWrapped(elements).map(|t| t.0))
+ | ------------------------------------------------- recursive call site
|
= note: `#[warn(unconditional_recursion)]` on by default
= help: a `loop` may express intention better if this is on purpose
pub struct WaitToken;
impl !Send for WaitToken {}
-pub struct Test<T>(T);
+pub struct Test<T>(#[allow(unused_tuple_struct_fields)] T);
unsafe impl<T: 'static> Send for Test<T> {}
pub fn spawn<F>(_: F) -> () where F: FnOnce(), F: Send + 'static {}
}
}
-struct Map<A>(A);
+struct Map<A>(#[allow(unused_tuple_struct_fields)] A);
impl<A: Future> Future for Map<A> {}
pub struct Promise;
// test for #8601
-enum Type<T> { Constant(T) }
+enum Type<T> { Constant(#[allow(unused_tuple_struct_fields)] T) }
trait Trait<K,V> {
fn method(&self, _: Type<(K,V)>) -> isize;
type Bar = ();
}
-struct Wrapper1<T: Foo>(<T as Foo>::Bar);
-struct Wrapper2<T: Foo>(<Wrapper1<T> as Pointee>::Metadata);
+struct Wrapper1<T: Foo>(#[allow(unused_tuple_struct_fields)] <T as Foo>::Bar);
+struct Wrapper2<T: Foo>(#[allow(unused_tuple_struct_fields)] <Wrapper1<T> as Pointee>::Metadata);
fn main() {
let _: Wrapper2<()> = Wrapper2(());
// Array is to make sure the size is not exactly pointer-size, so
// we can be sure we are measuring the right size in the
// `size_of_val` test.
-struct SetOnDrop<'a>(&'a AtomicUsize, [u8; 64]);
+struct SetOnDrop<'a>(&'a AtomicUsize, #[allow(unused_tuple_struct_fields)] [u8; 64]);
impl<'a> Drop for SetOnDrop<'a> {
fn drop(&mut self) {
self.0.store(self.0.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
--> $DIR/cyclic-trait-resolution.rs:1:1
|
LL | trait A: B + A {}
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^
error: aborting due to previous error
--- /dev/null
+// check-pass
+//! The implementation should behave correctly when the `ASSUME` parameters are
+//! provided indirectly through an abstraction.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<
+ Src,
+ Dst,
+ Context,
+ const ASSUME_ALIGNMENT: bool,
+ const ASSUME_LIFETIMES: bool,
+ const ASSUME_VALIDITY: bool,
+ const ASSUME_VISIBILITY: bool,
+ >()
+ where
+ Dst: BikeshedIntrinsicFrom<
+ Src,
+ Context,
+ ASSUME_ALIGNMENT,
+ ASSUME_LIFETIMES,
+ ASSUME_VALIDITY,
+ ASSUME_VISIBILITY,
+ >,
+ {}
+}
+
+fn direct() {
+ struct Context;
+ #[repr(C)] struct Src;
+ #[repr(C)] struct Dst;
+
+ assert::is_transmutable::<Src, Dst, Context, false, false, false, false>();
+}
+
+fn via_const() {
+ struct Context;
+ #[repr(C)] struct Src;
+ #[repr(C)] struct Dst;
+
+ const FALSE: bool = false;
+
+ assert::is_transmutable::<Src, Dst, Context, FALSE, FALSE, FALSE, FALSE>();
+}
+
+fn via_associated_const() {
+ struct Context;
+ #[repr(C)] struct Src;
+ #[repr(C)] struct Dst;
+
+ trait Trait {
+ const FALSE: bool = true;
+ }
+
+ struct Ty;
+
+ impl Trait for Ty {}
+
+ assert::is_transmutable::<
+ Src,
+ Dst,
+ Context,
+ {Ty::FALSE},
+ {Ty::FALSE},
+ {Ty::FALSE},
+ {Ty::FALSE}
+ >();
+}
--- /dev/null
+// check-pass
+//! An array must have the correct length.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn array_like<T, E, const N: usize>()
+ where
+ T: BikeshedIntrinsicFrom<[E; N], Context, false, false, false, true>,
+ [E; N]: BikeshedIntrinsicFrom<T, Context, false, false, false, true>
+ {}
+}
+
+fn len_0() {
+ type Array = [u8; 0];
+ #[repr(C)] struct Struct();
+ assert::array_like::<Struct, u8, 0>();
+}
+
+fn len_1() {
+ type Array = [u8; 1];
+ #[repr(C)] struct Struct(u8);
+ assert::array_like::<Struct, u8, 1>();
+}
+
+fn len_2() {
+ type Array = [u8; 2];
+ #[repr(C)] struct Struct(u8, u8);
+ assert::array_like::<Struct, u8, 2>();
+}
+
+fn len_3() {
+ type Array = [u8; 3];
+ #[repr(C)] struct Struct(u8, u8, u8);
+ assert::array_like::<Struct, u8, 3>();
+}
--- /dev/null
+// check-pass
+//! An array must have the correct length.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn should_have_len_0() {
+ type Array = [u8; 0];
+ #[repr(C)] struct Struct();
+ assert::is_maybe_transmutable::<Array, Struct>();
+ assert::is_maybe_transmutable::<Struct, Array>();
+}
+
+fn should_have_len_1() {
+ type Array = [u8; 1];
+ #[repr(C)] struct Struct(u8);
+ assert::is_maybe_transmutable::<Array, Struct>();
+ assert::is_maybe_transmutable::<Struct, Array>();
+}
+
+fn should_have_len_2() {
+ type Array = [u8; 2];
+ #[repr(C)] struct Struct(u8, u8);
+ assert::is_maybe_transmutable::<Array, Struct>();
+ assert::is_maybe_transmutable::<Struct, Array>();
+}
+
+fn should_have_len_3() {
+ type Array = [u8; 3];
+ #[repr(C)] struct Struct(u8, u8, u8);
+ assert::is_maybe_transmutable::<Array, Struct>();
+ assert::is_maybe_transmutable::<Struct, Array>();
+}
--- /dev/null
+// check-pass
+//! An array must inherit the alignment of its inner type.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+#[repr(C)]
+union Uninit {
+ a: (),
+ b: OxFF,
+}
+
+#[repr(C, align(2))] struct align_2(Ox00);
+
+fn len_0() {
+ #[repr(C)] struct ImplicitlyPadded([align_2; 0], Ox01);
+ #[repr(C)] struct ExplicitlyPadded(Ox01, Uninit);
+
+ #[repr(C)] struct Struct();
+ assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+ assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
+
+fn len_1() {
+ #[repr(C)] struct ImplicitlyPadded([align_2; 1], Ox01);
+ #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox01, Uninit);
+
+ #[repr(C)] struct Struct();
+ assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+ assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
+
+fn len_2() {
+ #[repr(C)] struct ImplicitlyPadded([align_2; 2], Ox01);
+ #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox00, Uninit, Ox01, Uninit);
+
+ #[repr(C)] struct Struct();
+ assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+ assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
--- /dev/null
+//! An array must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn should_reject_repr_rust()
+{
+ fn unit() {
+ type repr_rust = [String; 0];
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn singleton() {
+ type repr_rust = [String; 1];
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn duplex() {
+ type repr_rust = [String; 2];
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+}
+
+fn should_accept_repr_C()
+{
+ fn unit() {
+ #[repr(C)] struct repr_c(u8, u16, u8);
+ type array = [repr_c; 0];
+ assert::is_maybe_transmutable::<array, ()>();
+ assert::is_maybe_transmutable::<i128, array>();
+ }
+
+ fn singleton() {
+ #[repr(C)] struct repr_c(u8, u16, u8);
+ type array = [repr_c; 1];
+ assert::is_maybe_transmutable::<array, repr_c>();
+ assert::is_maybe_transmutable::<repr_c, array>();
+ }
+
+ fn duplex() {
+ #[repr(C)] struct repr_c(u8, u16, u8);
+ #[repr(C)] struct duplex(repr_c, repr_c);
+ type array = [repr_c; 2];
+ assert::is_maybe_transmutable::<array, duplex>();
+ assert::is_maybe_transmutable::<duplex, array>();
+ }
+}
--- /dev/null
+error[E0277]: `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:21:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:22:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 0]`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:27:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:28:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 1]`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:33:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:34:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 2]`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! An enum with a primitive repr should have exactly the size of that primitive.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+#[repr(C)]
+struct Zst;
+
+#[derive(Clone, Copy)]
+#[repr(i8)] enum V0i8 { V }
+#[repr(u8)] enum V0u8 { V }
+#[repr(i16)] enum V0i16 { V }
+#[repr(u16)] enum V0u16 { V }
+#[repr(i32)] enum V0i32 { V }
+#[repr(u32)] enum V0u32 { V }
+#[repr(i64)] enum V0i64 { V }
+#[repr(u64)] enum V0u64 { V }
+#[repr(isize)] enum V0isize { V }
+#[repr(usize)] enum V0usize { V }
+
+fn n8() {
+ struct Context;
+
+ type Smaller = Zst;
+ type Analog = u8;
+ type Larger = u16;
+
+ fn i_should_have_correct_length() {
+ type Current = V0i8;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn u_should_have_correct_length() {
+ type Current = V0u8;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+}
+
+fn n16() {
+ struct Context;
+
+ type Smaller = u8;
+ type Analog = u16;
+ type Larger = u32;
+
+ fn i_should_have_correct_length() {
+ type Current = V0i16;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn u_should_have_correct_length() {
+ type Current = V0u16;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+}
+
+fn n32() {
+ struct Context;
+
+ type Smaller = u16;
+ type Analog = u32;
+ type Larger = u64;
+
+ fn i_should_have_correct_length() {
+ type Current = V0i32;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn u_should_have_correct_length() {
+ type Current = V0u32;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+}
+
+fn n64() {
+ struct Context;
+
+ type Smaller = u32;
+ type Analog = u64;
+ type Larger = u128;
+
+ fn i_should_have_correct_length() {
+ type Current = V0i64;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn u_should_have_correct_length() {
+ type Current = V0u64;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+}
+
+fn nsize() {
+ struct Context;
+
+ type Smaller = u8;
+ type Analog = usize;
+ type Larger = [usize; 2];
+
+ fn i_should_have_correct_length() {
+ type Current = V0isize;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn u_should_have_correct_length() {
+ type Current = V0usize;
+
+ assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<Current, Analog, Context>();
+ assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+ }
+}
--- /dev/null
+error[E0277]: `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:41:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0i8`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:43:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0i8, n8::Context, true, true, true, true>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:49:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0u8`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:51:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0u8, n8::Context, true, true, true, true>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:65:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0i16`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:67:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0i16, n16::Context, true, true, true, true>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:73:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0u16`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:75:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0u16, n16::Context, true, true, true, true>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:89:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0i32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:91:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0i32, n32::Context, true, true, true, true>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:97:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0u32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:99:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0u32, n32::Context, true, true, true, true>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:113:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0i64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:115:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0i64, n64::Context, true, true, true, true>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:121:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:123:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0u64, n64::Context, true, true, true, true>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:137:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0isize`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:139:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0isize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:145:44
+ |
+LL | assert::is_transmutable::<Smaller, Current, Context>();
+ | ^^^^^^^ `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0usize`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:147:44
+ |
+LL | assert::is_transmutable::<Current, Larger, Context>();
+ | ^^^^^^ `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<V0usize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
+note: required by a bound in `is_transmutable`
+ --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 20 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! An enum must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(repr128)]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn should_reject_repr_rust() {
+ fn void() {
+ enum repr_rust {}
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn singleton() {
+ enum repr_rust { V }
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn duplex() {
+ enum repr_rust { A, B }
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+}
+
+fn should_accept_primitive_reprs()
+{
+ fn should_accept_repr_i8() {
+ #[repr(i8)] enum repr_i8 { V }
+ assert::is_maybe_transmutable::<repr_i8, ()>();
+ assert::is_maybe_transmutable::<i8, repr_i8>();
+ }
+
+ fn should_accept_repr_u8() {
+ #[repr(u8)] enum repr_u8 { V }
+ assert::is_maybe_transmutable::<repr_u8, ()>();
+ assert::is_maybe_transmutable::<u8, repr_u8>();
+ }
+
+ fn should_accept_repr_i16() {
+ #[repr(i16)] enum repr_i16 { V }
+ assert::is_maybe_transmutable::<repr_i16, ()>();
+ assert::is_maybe_transmutable::<i16, repr_i16>();
+ }
+
+ fn should_accept_repr_u16() {
+ #[repr(u16)] enum repr_u16 { V }
+ assert::is_maybe_transmutable::<repr_u16, ()>();
+ assert::is_maybe_transmutable::<u16, repr_u16>();
+ }
+
+ fn should_accept_repr_i32() {
+ #[repr(i32)] enum repr_i32 { V }
+ assert::is_maybe_transmutable::<repr_i32, ()>();
+ assert::is_maybe_transmutable::<i32, repr_i32>();
+ }
+
+ fn should_accept_repr_u32() {
+ #[repr(u32)] enum repr_u32 { V }
+ assert::is_maybe_transmutable::<repr_u32, ()>();
+ assert::is_maybe_transmutable::<u32, repr_u32>();
+ }
+
+ fn should_accept_repr_i64() {
+ #[repr(i64)] enum repr_i64 { V }
+ assert::is_maybe_transmutable::<repr_i64, ()>();
+ assert::is_maybe_transmutable::<i64, repr_i64>();
+ }
+
+ fn should_accept_repr_u64() {
+ #[repr(u64)] enum repr_u64 { V }
+ assert::is_maybe_transmutable::<repr_u64, ()>();
+ assert::is_maybe_transmutable::<u64, repr_u64>();
+ }
+
+ fn should_accept_repr_i128() {
+ #[repr(i128)] enum repr_i128 { V }
+ assert::is_maybe_transmutable::<repr_i128, ()>();
+ assert::is_maybe_transmutable::<i128, repr_i128>();
+ }
+
+ fn should_accept_repr_u128() {
+ #[repr(u128)] enum repr_u128 { V }
+ assert::is_maybe_transmutable::<repr_u128, ()>();
+ assert::is_maybe_transmutable::<u128, repr_u128>();
+ }
+
+ fn should_accept_repr_isize() {
+ #[repr(isize)] enum repr_isize { V }
+ assert::is_maybe_transmutable::<repr_isize, ()>();
+ assert::is_maybe_transmutable::<isize, repr_isize>();
+ }
+
+ fn should_accept_repr_usize() {
+ #[repr(usize)] enum repr_usize { V }
+ assert::is_maybe_transmutable::<repr_usize, ()>();
+ assert::is_maybe_transmutable::<usize, repr_usize>();
+ }
+}
+
+fn should_accept_repr_C() {
+ #[repr(C)] enum repr_c { V }
+ assert::is_maybe_transmutable::<repr_c, ()>();
+ assert::is_maybe_transmutable::<i128, repr_c>();
+}
--- /dev/null
+error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:21:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<void::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:14:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:22:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `void::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:14:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:27:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<singleton::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:14:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:28:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `singleton::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:14:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:33:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<duplex::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:14:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:34:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `duplex::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:14:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+//! The payloads of an enum variant should be ordered after its tag.
+
+#![crate_type = "lib"]
+#![feature(arbitrary_enum_discriminant)]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+#[repr(u8)] enum V0 { V = 0 }
+#[repr(u8)] enum V1 { V = 1 }
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(u8)] enum E01 { V0(V1) = 0u8 }
+#[repr(u8)] enum E012 { V0(V1, V2) = 0u8 }
+
+fn should_order_tag_and_fields_correctly() {
+ // An implementation that (incorrectly) arranges E01 as [0x01, 0x00] will,
+ // in principle, reject this transmutation.
+ assert::is_transmutable::<E01, V0>();
+ // Again, but with one more field.
+ assert::is_transmutable::<E012, E01>();
+}
--- /dev/null
+//! The variants of an enum must be padded with uninit bytes such that they have
+//! the same length (in bytes).
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)] struct Zst;
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V0 { V = 0 }
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(C, u8)]
+enum Lopsided {
+ Smol(Zst),
+ Lorg(V0),
+}
+
+#[repr(C)] struct Src(V0, Zst, V2);
+#[repr(C)] struct Dst(Lopsided, V2);
+
+fn should_pad_variants() {
+ struct Context;
+ // If the implementation (incorrectly) fails to pad `Lopsided::Smol` with
+ // an uninitialized byte, this transmutation might be (wrongly) accepted:
+ assert::is_transmutable::<Src, Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+ --> $DIR/should_pad_variants.rs:39:36
+ |
+LL | assert::is_transmutable::<Src, Dst, Context>();
+ | ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_pad_variants.rs:13:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! The target endianness should be a consideration in computing the layout of
+//! an enum with a multi-byte tag.
+
+#![crate_type = "lib"]
+#![feature(arbitrary_enum_discriminant)]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+#[repr(u16)] enum Src { V = 0xCAFE }
+
+#[repr(u8)] enum OxCA { V = 0xCA }
+#[repr(u8)] enum OxFE { V = 0xFE }
+
+#[cfg(target_endian = "big")] #[repr(C)] struct Expected(OxCA, OxFE);
+#[cfg(target_endian = "big")] #[repr(C)] struct Unexpected(OxFE, OxCA);
+
+#[cfg(target_endian = "little")] #[repr(C)] struct Expected(OxFE, OxCA);
+#[cfg(target_endian = "little")] #[repr(C)] struct Unexpected(OxCA, OxFE);
+
+fn should_respect_endianness() {
+ assert::is_transmutable::<Src, Expected>();
+ assert::is_transmutable::<Src, Unexpected>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
+ --> $DIR/should_respect_endianness.rs:32:36
+ |
+LL | assert::is_transmutable::<Src, Unexpected>();
+ | ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Src, assert::Context, true, true, true, true>` is not implemented for `Unexpected`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_respect_endianness.rs:15:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// The trait must not be available if its feature flag is absent.
+
+#![crate_type = "lib"]
+
+use std::mem::BikeshedIntrinsicFrom;
+//~^ ERROR use of unstable library feature 'transmutability' [E0658]
+
+use std::mem::Assume;
+//~^ ERROR use of unstable library feature 'transmutability' [E0658]
--- /dev/null
+error[E0658]: use of unstable library feature 'transmutability'
+ --> $DIR/feature-missing.rs:5:5
+ |
+LL | use std::mem::BikeshedIntrinsicFrom;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #99571 <https://github.com/rust-lang/rust/issues/99571> for more information
+ = help: add `#![feature(transmutability)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'transmutability'
+ --> $DIR/feature-missing.rs:8:5
+ |
+LL | use std::mem::Assume;
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #99571 <https://github.com/rust-lang/rust/issues/99571> for more information
+ = help: add `#![feature(transmutability)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// An unknown destination type should be gracefully handled.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ {}
+}
+
+fn should_gracefully_handle_unknown_dst() {
+ struct Context;
+ struct Src;
+ assert::is_transmutable::<Src, Dst, Context>(); //~ cannot find type
+}
--- /dev/null
+error[E0412]: cannot find type `Dst` in this scope
+ --> $DIR/unknown_dst.rs:20:36
+ |
+LL | fn should_gracefully_handle_unknown_dst() {
+ | - help: you might be missing a type parameter: `<Dst>`
+...
+LL | assert::is_transmutable::<Src, Dst, Context>();
+ | ^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
--- /dev/null
+// An unknown source type should be gracefully handled.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ {}
+}
+
+fn should_gracefully_handle_unknown_src() {
+ struct Context;
+ #[repr(C)] struct Dst;
+ assert::is_transmutable::<Src, Dst, Context>(); //~ cannot find type
+}
--- /dev/null
+error[E0412]: cannot find type `Src` in this scope
+ --> $DIR/unknown_src.rs:20:31
+ |
+LL | fn should_gracefully_handle_unknown_src() {
+ | - help: you might be missing a type parameter: `<Src>`
+...
+LL | assert::is_transmutable::<Src, Dst, Context>();
+ | ^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
--- /dev/null
+// An unknown destination type should be gracefully handled.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ {}
+}
+
+fn should_gracefully_handle_unknown_dst_field() {
+ struct Context;
+ #[repr(C)] struct Src;
+ #[repr(C)] struct Dst(Missing); //~ cannot find type
+ assert::is_transmutable::<Src, Dst, Context>();
+}
--- /dev/null
+error[E0412]: cannot find type `Missing` in this scope
+ --> $DIR/unknown_src_field.rs:20:27
+ |
+LL | #[repr(C)] struct Dst(Missing);
+ | ^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
--- /dev/null
+//! The implementation must behave well if const values of wrong types are
+//! provided.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<
+ Src,
+ Dst,
+ Context,
+ const ASSUME_ALIGNMENT: bool,
+ const ASSUME_LIFETIMES: bool,
+ const ASSUME_VALIDITY: bool,
+ const ASSUME_VISIBILITY: bool,
+ >()
+ where
+ Dst: BikeshedIntrinsicFrom<
+ Src,
+ Context,
+ ASSUME_ALIGNMENT,
+ ASSUME_LIFETIMES,
+ ASSUME_VALIDITY,
+ ASSUME_VISIBILITY,
+ >,
+ {}
+}
+
+fn test() {
+ struct Context;
+ #[repr(C)] struct Src;
+ #[repr(C)] struct Dst;
+ assert::is_transmutable::<Src, Dst, Context, {0u8}, false, false, false>(); //~ ERROR mismatched types
+ assert::is_transmutable::<Src, Dst, Context, false, {0u8}, false, false>(); //~ ERROR mismatched types
+ assert::is_transmutable::<Src, Dst, Context, false, false, {0u8}, false>(); //~ ERROR mismatched types
+ assert::is_transmutable::<Src, Dst, Context, false, false, false, {0u8}>(); //~ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/wrong-type-assume.rs:36:51
+ |
+LL | assert::is_transmutable::<Src, Dst, Context, {0u8}, false, false, false>();
+ | ^^^ expected `bool`, found `u8`
+
+error[E0308]: mismatched types
+ --> $DIR/wrong-type-assume.rs:37:58
+ |
+LL | assert::is_transmutable::<Src, Dst, Context, false, {0u8}, false, false>();
+ | ^^^ expected `bool`, found `u8`
+
+error[E0308]: mismatched types
+ --> $DIR/wrong-type-assume.rs:38:65
+ |
+LL | assert::is_transmutable::<Src, Dst, Context, false, false, {0u8}, false>();
+ | ^^^ expected `bool`, found `u8`
+
+error[E0308]: mismatched types
+ --> $DIR/wrong-type-assume.rs:39:72
+ |
+LL | assert::is_transmutable::<Src, Dst, Context, false, false, false, {0u8}>();
+ | ^^^ expected `bool`, found `u8`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ {}
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+ {}
+}
+
+fn contrast_with_u8() {
+ assert::is_transmutable::<u8, bool>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u8, bool>();
+ assert::is_transmutable::<bool, u8>();
+}
--- /dev/null
+error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`.
+ --> $DIR/bool.rs:22:35
+ |
+LL | assert::is_transmutable::<u8, bool>();
+ | ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, true>` is not implemented for `bool`
+note: required by a bound in `is_transmutable`
+ --> $DIR/bool.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ struct Context;
+
+ pub fn is_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ {}
+}
+
+fn should_accept_identity() {
+ assert::is_transmutable::< i8, i8>();
+ assert::is_transmutable::< u8, u8>();
+ assert::is_transmutable::< i16, i16>();
+ assert::is_transmutable::< u16, u16>();
+ assert::is_transmutable::< i32, i32>();
+ assert::is_transmutable::< f32, f32>();
+ assert::is_transmutable::< u32, u32>();
+ assert::is_transmutable::< i64, i64>();
+ assert::is_transmutable::< f64, f64>();
+ assert::is_transmutable::< u64, u64>();
+ assert::is_transmutable::< i128, i128>();
+ assert::is_transmutable::< u128, u128>();
+ assert::is_transmutable::<isize, isize>();
+ assert::is_transmutable::<usize, usize>();
+}
+
+fn should_be_bitransmutable() {
+ assert::is_transmutable::< i8, u8>();
+ assert::is_transmutable::< u8, i8>();
+
+ assert::is_transmutable::< i16, u16>();
+ assert::is_transmutable::< u16, i16>();
+
+ assert::is_transmutable::< i32, f32>();
+ assert::is_transmutable::< i32, u32>();
+ assert::is_transmutable::< f32, i32>();
+ assert::is_transmutable::< f32, u32>();
+ assert::is_transmutable::< u32, i32>();
+ assert::is_transmutable::< u32, f32>();
+
+ assert::is_transmutable::< u64, i64>();
+ assert::is_transmutable::< u64, f64>();
+ assert::is_transmutable::< i64, u64>();
+ assert::is_transmutable::< i64, f64>();
+ assert::is_transmutable::< f64, u64>();
+ assert::is_transmutable::< f64, i64>();
+
+ assert::is_transmutable::< u128, i128>();
+ assert::is_transmutable::< i128, u128>();
+
+ assert::is_transmutable::<isize, usize>();
+ assert::is_transmutable::<usize, isize>();
+}
+
+fn should_reject_extension() {
+ assert::is_transmutable::< i8, i16>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i8, u16>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i8, i32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i8, f32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i8, u32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i8, u64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i8, i64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i8, f64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i8, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i8, i128>(); //~ ERROR cannot be safely transmuted
+
+ assert::is_transmutable::< u8, i16>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u8, u16>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u8, i32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u8, f32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u8, u32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u8, u64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u8, i64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u8, f64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u8, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u8, i128>(); //~ ERROR cannot be safely transmuted
+
+ assert::is_transmutable::< i16, i32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i16, f32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i16, u32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i16, u64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i16, i64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i16, f64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i16, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i16, i128>(); //~ ERROR cannot be safely transmuted
+
+ assert::is_transmutable::< u16, i32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u16, f32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u16, u32>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u16, u64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u16, i64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u16, f64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u16, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u16, i128>(); //~ ERROR cannot be safely transmuted
+
+ assert::is_transmutable::< i32, u64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i32, i64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i32, f64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i32, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i32, i128>(); //~ ERROR cannot be safely transmuted
+
+ assert::is_transmutable::< f32, u64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< f32, i64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< f32, f64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< f32, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< f32, i128>(); //~ ERROR cannot be safely transmuted
+
+ assert::is_transmutable::< u32, u64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u32, i64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u32, f64>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u32, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u32, i128>(); //~ ERROR cannot be safely transmuted
+
+ assert::is_transmutable::< u64, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< u64, i128>(); //~ ERROR cannot be safely transmuted
+
+ assert::is_transmutable::< i64, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< i64, i128>(); //~ ERROR cannot be safely transmuted
+
+ assert::is_transmutable::< f64, u128>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::< f64, i128>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:62:40
+ |
+LL | assert::is_transmutable::< i8, i16>();
+ | ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i16`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:63:40
+ |
+LL | assert::is_transmutable::< i8, u16>();
+ | ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:64:40
+ |
+LL | assert::is_transmutable::< i8, i32>();
+ | ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:65:40
+ |
+LL | assert::is_transmutable::< i8, f32>();
+ | ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:66:40
+ |
+LL | assert::is_transmutable::< i8, u32>();
+ | ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:67:40
+ |
+LL | assert::is_transmutable::< i8, u64>();
+ | ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:68:40
+ |
+LL | assert::is_transmutable::< i8, i64>();
+ | ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:69:40
+ |
+LL | assert::is_transmutable::< i8, f64>();
+ | ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:70:39
+ |
+LL | assert::is_transmutable::< i8, u128>();
+ | ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:71:39
+ |
+LL | assert::is_transmutable::< i8, i128>();
+ | ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:73:40
+ |
+LL | assert::is_transmutable::< u8, i16>();
+ | ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i16`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:74:40
+ |
+LL | assert::is_transmutable::< u8, u16>();
+ | ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:75:40
+ |
+LL | assert::is_transmutable::< u8, i32>();
+ | ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:76:40
+ |
+LL | assert::is_transmutable::< u8, f32>();
+ | ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:77:40
+ |
+LL | assert::is_transmutable::< u8, u32>();
+ | ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:78:40
+ |
+LL | assert::is_transmutable::< u8, u64>();
+ | ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:79:40
+ |
+LL | assert::is_transmutable::< u8, i64>();
+ | ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:80:40
+ |
+LL | assert::is_transmutable::< u8, f64>();
+ | ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:81:39
+ |
+LL | assert::is_transmutable::< u8, u128>();
+ | ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:82:39
+ |
+LL | assert::is_transmutable::< u8, i128>();
+ | ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:84:40
+ |
+LL | assert::is_transmutable::< i16, i32>();
+ | ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:85:40
+ |
+LL | assert::is_transmutable::< i16, f32>();
+ | ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:86:40
+ |
+LL | assert::is_transmutable::< i16, u32>();
+ | ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:87:40
+ |
+LL | assert::is_transmutable::< i16, u64>();
+ | ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:88:40
+ |
+LL | assert::is_transmutable::< i16, i64>();
+ | ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:89:40
+ |
+LL | assert::is_transmutable::< i16, f64>();
+ | ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:90:39
+ |
+LL | assert::is_transmutable::< i16, u128>();
+ | ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:91:39
+ |
+LL | assert::is_transmutable::< i16, i128>();
+ | ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:93:40
+ |
+LL | assert::is_transmutable::< u16, i32>();
+ | ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:94:40
+ |
+LL | assert::is_transmutable::< u16, f32>();
+ | ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:95:40
+ |
+LL | assert::is_transmutable::< u16, u32>();
+ | ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:96:40
+ |
+LL | assert::is_transmutable::< u16, u64>();
+ | ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:97:40
+ |
+LL | assert::is_transmutable::< u16, i64>();
+ | ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:98:40
+ |
+LL | assert::is_transmutable::< u16, f64>();
+ | ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:99:39
+ |
+LL | assert::is_transmutable::< u16, u128>();
+ | ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:100:39
+ |
+LL | assert::is_transmutable::< u16, i128>();
+ | ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:102:40
+ |
+LL | assert::is_transmutable::< i32, u64>();
+ | ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:103:40
+ |
+LL | assert::is_transmutable::< i32, i64>();
+ | ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:104:40
+ |
+LL | assert::is_transmutable::< i32, f64>();
+ | ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:105:39
+ |
+LL | assert::is_transmutable::< i32, u128>();
+ | ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:106:39
+ |
+LL | assert::is_transmutable::< i32, i128>();
+ | ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:108:40
+ |
+LL | assert::is_transmutable::< f32, u64>();
+ | ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:109:40
+ |
+LL | assert::is_transmutable::< f32, i64>();
+ | ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:110:40
+ |
+LL | assert::is_transmutable::< f32, f64>();
+ | ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:111:39
+ |
+LL | assert::is_transmutable::< f32, u128>();
+ | ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:112:39
+ |
+LL | assert::is_transmutable::< f32, i128>();
+ | ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:114:40
+ |
+LL | assert::is_transmutable::< u32, u64>();
+ | ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:115:40
+ |
+LL | assert::is_transmutable::< u32, i64>();
+ | ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:116:40
+ |
+LL | assert::is_transmutable::< u32, f64>();
+ | ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:117:39
+ |
+LL | assert::is_transmutable::< u32, u128>();
+ | ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:118:39
+ |
+LL | assert::is_transmutable::< u32, i128>();
+ | ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:120:39
+ |
+LL | assert::is_transmutable::< u64, u128>();
+ | ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:121:39
+ |
+LL | assert::is_transmutable::< u64, i128>();
+ | ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:123:39
+ |
+LL | assert::is_transmutable::< i64, u128>();
+ | ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:124:39
+ |
+LL | assert::is_transmutable::< i64, i128>();
+ | ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:126:39
+ |
+LL | assert::is_transmutable::< f64, u128>();
+ | ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ --> $DIR/numbers.rs:127:39
+ |
+LL | assert::is_transmutable::< f64, i128>();
+ | ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+ --> $DIR/numbers.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 57 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! The unit type, `()`, should be one byte.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+#[repr(C)]
+struct Zst;
+
+fn should_have_correct_size() {
+ struct Context;
+ assert::is_transmutable::<(), Zst, Context>();
+ assert::is_transmutable::<Zst, (), Context>();
+ assert::is_transmutable::<(), u8, Context>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
+ --> $DIR/unit.rs:23:35
+ |
+LL | assert::is_transmutable::<(), u8, Context>();
+ | ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8`
+note: required by a bound in `is_transmutable`
+ --> $DIR/unit.rs:12:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! Transmutations involving references are not yet supported.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn not_yet_implemented() {
+ #[repr(C)] struct Unit;
+ assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
+ --> $DIR/references.rs:19:37
+ |
+LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
+ | ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/references.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn should_pad_explicitly_aligned_field() {
+ #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+
+ #[repr(C)]
+ pub union Uninit {
+ a: (),
+ b: V0u8,
+ }
+
+ #[repr(C, align(2))] struct align_2(V0u8);
+
+ #[repr(C)] struct ImplicitlyPadded(align_2, V0u8);
+ #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8);
+
+ // An implementation that (incorrectly) does not place a padding byte after
+ // `align_2` will, incorrectly, reject the following transmutations.
+ assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+ assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
--- /dev/null
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn should_pad_explicitly_packed_field() {
+ #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+ #[derive(Clone, Copy)] #[repr(u32)] enum V0u32 { V = 0 }
+
+ #[repr(C)]
+ pub union Uninit {
+ a: (),
+ b: V0u8,
+ }
+
+ #[repr(C, packed(2))] struct ImplicitlyPadded(V0u8, V0u32);
+ #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8, V0u8, V0u8, V0u8);
+
+ // An implementation that (incorrectly) does not place a padding byte after
+ // `align_2` will, incorrectly, reject the following transmutations.
+ assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+ assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
--- /dev/null
+//! A struct must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn should_reject_repr_rust()
+{
+ fn unit() {
+ struct repr_rust;
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn tuple() {
+ struct repr_rust();
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn braces() {
+ struct repr_rust{}
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn aligned() {
+ #[repr(align(1))] struct repr_rust{}
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn packed() {
+ #[repr(packed)] struct repr_rust{}
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+ }
+
+ fn nested() {
+ struct repr_rust;
+ #[repr(C)] struct repr_c(repr_rust);
+ assert::is_maybe_transmutable::<repr_c, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_c>(); //~ ERROR cannot be safely transmuted
+ }
+}
+
+fn should_accept_repr_C()
+{
+ fn unit() {
+ #[repr(C)] struct repr_c;
+ assert::is_maybe_transmutable::<repr_c, ()>();
+ assert::is_maybe_transmutable::<i128, repr_c>();
+ }
+
+ fn tuple() {
+ #[repr(C)] struct repr_c();
+ assert::is_maybe_transmutable::<repr_c, ()>();
+ assert::is_maybe_transmutable::<i128, repr_c>();
+ }
+
+ fn braces() {
+ #[repr(C)] struct repr_c{}
+ assert::is_maybe_transmutable::<repr_c, ()>();
+ assert::is_maybe_transmutable::<i128, repr_c>();
+ }
+}
--- /dev/null
+error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:21:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::unit::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:22:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::unit::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:27:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::tuple::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:28:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::tuple::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:33:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::braces::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:34:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::braces::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:39:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<aligned::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:40:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `aligned::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:45:52
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<packed::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:46:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `packed::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:52:49
+ |
+LL | assert::is_maybe_transmutable::<repr_c, ()>();
+ | ^^ `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<nested::repr_c, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:53:47
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_c>();
+ | ^^^^^^ `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `nested::repr_c`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+//! The fields of a struct should be laid out in lexical order.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+#[repr(u8)] enum V0 { V = 0 }
+#[repr(u8)] enum V1 { V = 1 }
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(C)] struct S01(V0, V1);
+#[repr(C)] struct S012(V0, V1, V2);
+
+fn should_order_tag_and_fields_correctly() {
+ // An implementation that (incorrectly) arranges S01 as [0x01, 0x00] will,
+ // in principle, reject this transmutation.
+ assert::is_transmutable::<S01, V0>();
+ // Again, but with one more field.
+ assert::is_transmutable::<S012, S01>();
+}
--- /dev/null
+// check-pass
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![feature(marker_trait_attr)]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ {}
+}
+
+fn should_match_bool() {
+ #[derive(Copy, Clone)] #[repr(u8)] pub enum False { V = 0 }
+ #[derive(Copy, Clone)] #[repr(u8)] pub enum True { V = 1 }
+
+ #[repr(C)]
+ pub union Bool {
+ pub f: False,
+ pub t: True,
+ }
+
+ assert::is_transmutable::<Bool, bool>();
+ assert::is_transmutable::<bool, Bool>();
+}
--- /dev/null
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn should_pad_explicitly_aligned_field() {
+ #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+ #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 }
+
+ #[repr(C)]
+ pub union Uninit {
+ a: (),
+ b: V1u8,
+ }
+
+ #[repr(C, align(2))]
+ pub union align_2 {
+ a: V0u8,
+ }
+
+ #[repr(C)] struct ImplicitlyPadded(align_2, V0u8);
+ #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8);
+
+ // An implementation that (incorrectly) does not place a padding byte after
+ // `align_2` will, incorrectly, reject the following transmutations.
+ assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+ assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
--- /dev/null
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn should_pad_explicitly_packed_field() {
+ #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+ #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 }
+ #[derive(Clone, Copy)] #[repr(u8)] enum V2u8 { V = 2 }
+ #[derive(Clone, Copy)] #[repr(u32)] enum V3u32 { V = 3 }
+
+ #[repr(C)]
+ pub union Uninit {
+ a: (),
+ b: V1u8,
+ }
+
+ #[repr(C, packed(2))]
+ pub union Packed {
+ a: [V3u32; 0],
+ b: V0u8,
+ }
+
+ #[repr(C)] struct ImplicitlyPadded(Packed, V2u8);
+ #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V2u8);
+
+ assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+ assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
--- /dev/null
+//! A struct must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+fn should_reject_repr_rust()
+{
+ union repr_rust {
+ a: u8
+ }
+
+ assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+}
+
+fn should_accept_repr_C()
+{
+ #[repr(C)]
+ union repr_c {
+ a: u8
+ }
+
+ struct repr_rust;
+ assert::is_maybe_transmutable::<repr_c, ()>();
+ assert::is_maybe_transmutable::<u128, repr_c>();
+}
--- /dev/null
+error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:23:48
+ |
+LL | assert::is_maybe_transmutable::<repr_rust, ()>();
+ | ^^ `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
+ --> $DIR/should_require_well_defined_layout.rs:24:43
+ |
+LL | assert::is_maybe_transmutable::<u128, repr_rust>();
+ | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_require_well_defined_layout.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! The variants of a union must be padded with uninit bytes such that they have
+//! the same length (in bytes).
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ {}
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)] struct Zst;
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V0 { V = 0 }
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(C)]
+union Lopsided {
+ smol: Zst,
+ lorg: V0,
+}
+
+#[repr(C)] struct Src(V0, Zst, V2);
+#[repr(C)] struct Dst(V0, Lopsided, V2);
+
+fn should_pad_variants() {
+ struct Context;
+ // If the implementation (incorrectly) fails to pad `Lopsided::smol` with
+ // an uninitialized byte, this transmutation might be (wrongly) accepted:
+ assert::is_transmutable::<Src, Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+ --> $DIR/should_pad_variants.rs:39:36
+ |
+LL | assert::is_transmutable::<Src, Dst, Context>();
+ | ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_pad_variants.rs:13:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+//! If validity is assumed, there need only be one matching bit-pattern between
+//! the source and destination types.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+ // validity IS assumed --------------------------------^^^^
+ {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+ #[repr(C)]
+ union A {
+ a: Ox00,
+ b: Ox7F,
+ }
+
+ #[repr(C)]
+ union B {
+ a: Ox7F,
+ b: OxFF,
+ }
+
+ assert::is_maybe_transmutable::<A, B>();
+ assert::is_maybe_transmutable::<B, A>();
+}
--- /dev/null
+//! Validity may not be contracted, unless validity is assumed.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+ #[repr(C)]
+ union Subset {
+ a: Ox00,
+ b: OxFF,
+ }
+
+ #[repr(C)]
+ union Superset {
+ a: Ox00,
+ b: OxFF,
+ c: Ox01,
+ }
+
+ assert::is_transmutable::<Superset, Subset>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`.
+ --> $DIR/should_reject_contraction.rs:35:41
+ |
+LL | assert::is_transmutable::<Superset, Subset>();
+ | ^^^^^^ `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Superset, assert::Context, false, false, false, true>` is not implemented for `Subset`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_reject_contraction.rs:13:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! Validity must be satisfiable, even if validity is assumed.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+ // validity IS assumed --------------------------------^^^^
+ {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+ #[repr(C)]
+ union A {
+ a: Ox00,
+ b: OxFF,
+ }
+
+ #[repr(C)]
+ union B {
+ c: Ox01,
+ }
+
+ assert::is_maybe_transmutable::<A, B>(); //~ ERROR cannot be safely transmuted
+ assert::is_maybe_transmutable::<B, A>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+ --> $DIR/should_reject_disjoint.rs:34:40
+ |
+LL | assert::is_maybe_transmutable::<A, B>();
+ | ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, true, true>` is not implemented for `B`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_reject_disjoint.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+ --> $DIR/should_reject_disjoint.rs:35:40
+ |
+LL | assert::is_maybe_transmutable::<B, A>();
+ | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, true, true>` is not implemented for `A`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/should_reject_disjoint.rs:13:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! ALL valid bit patterns of the source must be valid bit patterns of the
+//! destination type, unless validity is assumed.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+ pub struct Context;
+
+ pub fn is_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ // validity is NOT assumed ----------------------------^^^^^
+ {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+ #[repr(C)]
+ union A {
+ a: Ox00,
+ b: Ox7F,
+ }
+
+ #[repr(C)]
+ union B {
+ a: Ox7F,
+ b: OxFF,
+ }
+
+ assert::is_transmutable::<A, B>(); //~ ERROR cannot be safely transmuted
+ assert::is_transmutable::<B, A>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+ --> $DIR/should_reject_intersecting.rs:36:34
+ |
+LL | assert::is_transmutable::<A, B>();
+ | ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, false, true>` is not implemented for `B`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_reject_intersecting.rs:14:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+ --> $DIR/should_reject_intersecting.rs:37:34
+ |
+LL | assert::is_transmutable::<B, A>();
+ | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, false, true>` is not implemented for `A`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_reject_intersecting.rs:14:14
+ |
+LL | pub fn is_transmutable<Src, Dst>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains a private field.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ // visibility IS assumed -------------------------------------^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(self) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(self) field: Zst,
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(self) field: Zst, // <- private field
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
--- /dev/null
+// check-pass
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains a private variant.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ // visibility IS assumed -------------------------------------^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(self) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(self) field: Zst,
+ }
+}
+
+mod dst {
+ #[derive(Copy, Clone)]
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) union Dst {
+ pub(self) field: Zst, // <- private variant
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
--- /dev/null
+// check-pass
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+//!
+//! This test exercises a tricky-to-implement instance of this principle: the
+//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is
+//! unreachable from `Context`.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ // visibility IS assumed -------------------------------------^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(in super) field: Zst,
+ }
+}
+
+mod dst {
+ mod private {
+ #[repr(C)] pub struct Zst; // <- unreachable type
+ }
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(in super) field: private::Zst,
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
--- /dev/null
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ // visibility IS assumed -------------------------------------^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(self) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(self) field: Zst,
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(self) struct Zst; // <- unreachable type
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(in super) field: Zst, //~ ERROR private type
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
--- /dev/null
+error[E0446]: private type `dst::Zst` in public interface
+ --> $DIR/should_accept_if_dst_has_unreachable_field.rs:32:9
+ |
+LL | #[repr(C)] pub(self) struct Zst; // <- unreachable type
+ | -------------------- `dst::Zst` declared as private
+...
+LL | pub(in super) field: Zst,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0446`.
--- /dev/null
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+ // visibility IS assumed -------------------------------------^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(self) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(self) field: Zst,
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(in super) struct Zst;
+
+ // unreachable type
+ #[repr(C)] pub(self) struct Dst {
+ pub(in super) field: Zst,
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR `Dst` is private
+}
--- /dev/null
+error[E0603]: struct `Dst` is private
+ --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:39:46
+ |
+LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
+ | ^^^ private struct
+ |
+note: the struct `Dst` is defined here
+ --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:32:16
+ |
+LL | #[repr(C)] pub(self) struct Dst {
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
--- /dev/null
+// check-pass
+//! The presence of a private field in the source type does not affect
+//! transmutability.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ // visibility is NOT assumed ---------------------------------^^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(self) field: Zst, // <- private field
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(in super) field: Zst,
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
--- /dev/null
+// check-pass
+//! The presence of a private variant in the source type does not affect
+//! transmutability.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ // visibility is NOT assumed ---------------------------------^^^^^
+ {}
+}
+
+mod src {
+ #[derive(Copy, Clone)]
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) union Src {
+ pub(self) field: Zst, // <- private variant
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(in super) field: Zst,
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
--- /dev/null
+//! The presence of an unreachable field in the source type (e.g., a public
+//! field with a private type does not affect transmutability. (This rule is
+//! distinct from type privacy, which still may forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ // visibility is NOT assumed ---------------------------------^^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(self) struct Zst; // <- unreachable type
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(in super) field: Zst, //~ ERROR private type
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(in super) field: Zst,
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
--- /dev/null
+error[E0446]: private type `src::Zst` in public interface
+ --> $DIR/should_accept_if_src_has_unreachable_field.rs:23:9
+ |
+LL | #[repr(C)] pub(self) struct Zst; // <- unreachable type
+ | -------------------- `src::Zst` declared as private
+...
+LL | pub(in super) field: Zst,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0446`.
--- /dev/null
+//! The presence of an unreachable source type (i.e., the source type is
+//! private) does not affect transmutability. (This rule is distinct from type
+//! privacy, which still may forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ // visibility is NOT assumed ---------------------------------^^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(in super) struct Zst;
+
+ // unreachable type
+ #[repr(C)] pub(self) struct Src {
+ pub(in super) field: Zst,
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(in super) field: Zst,
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR `Src` is private
+}
--- /dev/null
+error[E0603]: struct `Src` is private
+ --> $DIR/should_accept_if_src_has_unreachable_ty.rs:38:36
+ |
+LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
+ | ^^^ private struct
+ |
+note: the struct `Src` is defined here
+ --> $DIR/should_accept_if_src_has_unreachable_ty.rs:23:16
+ |
+LL | #[repr(C)] pub(self) struct Src {
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
--- /dev/null
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains a private field.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ // visibility is NOT assumed ---------------------------------^^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(in super) field: Zst,
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(self) field: Zst, // <- private field
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+ --> $DIR/should_reject_if_dst_has_private_field.rs:36:41
+ |
+LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
+ | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_reject_if_dst_has_private_field.rs:13:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains a private variant.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ // visibility is NOT assumed ---------------------------------^^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(in super) field: Zst,
+ }
+}
+
+mod dst {
+ #[derive(Copy, Clone)]
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) union Dst {
+ pub(self) field: Zst, // <- private variant
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+ --> $DIR/should_reject_if_dst_has_private_variant.rs:37:41
+ |
+LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
+ | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_reject_if_dst_has_private_variant.rs:13:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+//! NOTE: This test documents a known-bug in the implementation of the
+//! transmutability trait. Once fixed, the above "check-pass" header should be
+//! removed, and an "ERROR cannot be safely transmuted" annotation should be added at the end
+//! of the line starting with `assert::is_transmutable`.
+//!
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+//!
+//! This test exercises a tricky-to-implement instance of this principle: the
+//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is
+//! unreachable from `Context`. Consequently, the transmute from `Src` to `Dst`
+//! SHOULD be rejected.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ // visibility is NOT assumed ---------------------------------^^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(in super) field: Zst,
+ }
+}
+
+mod dst {
+ mod private {
+ #[repr(C)] pub struct Zst; // <- unreachable type
+ }
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(in super) field: private::Zst,
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
--- /dev/null
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ // visibility is NOT assumed ---------------------------------^^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(in super) field: Zst,
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(self) struct Zst; // <- unreachable type
+
+ #[repr(C)] pub(in super) struct Dst {
+ pub(in super) field: Zst,
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+ --> $DIR/should_reject_if_dst_has_unreachable_field.rs:38:41
+ |
+LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
+ | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::BikeshedIntrinsicFrom;
+
+ pub fn is_transmutable<Src, Dst, Context>()
+ where
+ Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ // visibility is NOT assumed ---------------------------------^^^^^
+ {}
+}
+
+mod src {
+ #[repr(C)] pub(in super) struct Zst;
+
+ #[repr(C)] pub(in super) struct Src {
+ pub(in super) field: Zst,
+ }
+}
+
+mod dst {
+ #[repr(C)] pub(in super) struct Zst;
+
+ // unreachable type
+ #[repr(C)] pub(self) struct Dst {
+ pub(in super) field: Zst,
+ }
+}
+
+fn test() {
+ struct Context;
+ assert::is_transmutable::<src::Src, dst::Dst, Context>();
+ //~^ ERROR `Dst` is private
+ //~| ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0603]: struct `Dst` is private
+ --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:46
+ |
+LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
+ | ^^^ private struct
+ |
+note: the struct `Dst` is defined here
+ --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:32:16
+ |
+LL | #[repr(C)] pub(self) struct Dst {
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+ --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:41
+ |
+LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
+ | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+ --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14
+ |
+LL | pub fn is_transmutable<Src, Dst, Context>()
+ | --------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0603.
+For more information about an error, try `rustc --explain E0277`.
#![allow(irrefutable_let_patterns)]
-enum Enum<T> { TSVariant(T), SVariant { _v: T }, UVariant }
+enum Enum<T> { TSVariant(#[allow(unused_tuple_struct_fields)] T), SVariant { _v: T }, UVariant }
type Alias<T> = Enum<T>;
type AliasFixed = Enum<()>;
--> $DIR/self-in-enum-definition.rs:5:10
|
LL | V3 = Self::V1 {} as u8 + 2,
- | ^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`...
--> $DIR/self-in-enum-definition.rs:5:10
|
LL | V3 = Self::V1 {} as u8 + 2,
- | ^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`...
--> $DIR/self-in-enum-definition.rs:5:10
|
LL | V3 = Self::V1 {} as u8 + 2,
- | ^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Alpha`...
= note: ...which again requires simplifying constant for the type system `Alpha::V3::{constant#0}`, completing the cycle
note: cycle used when collecting item types in top-level module
impl Foo for () {
type Bar = std::vec::IntoIter<u32>;
- //~^ ERROR type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X
+ //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
}
fn incoherent() {
-error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X`
+error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
--> $DIR/issue-57961.rs:10:16
|
LL | type X = impl Sized;
--> $DIR/issue-74280.rs:9:5
|
LL | fn test() -> Test {
- | ---- expected `_` because of return type
+ | ---- expected `()` because of return type
LL | let y = || -> Test { () };
LL | 7
| ^ expected `()`, found integer
// edition:2018
-type AsyncFnPtr = Box<
- dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>,
->;
+type AsyncFnPtr = Box<dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>>;
async fn test() {}
#[allow(unused_must_use)]
fn main() {
Box::new(test) as AsyncFnPtr;
- //~^ ERROR type mismatch
+ //~^ ERROR expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
}
-error[E0271]: type mismatch resolving `<fn() -> impl Future<Output = ()> {test} as FnOnce<()>>::Output == Pin<Box<(dyn Future<Output = ()> + 'static)>>`
- --> $DIR/issue-98604.rs:11:5
+error[E0271]: expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+ --> $DIR/issue-98604.rs:9:5
|
LL | Box::new(test) as AsyncFnPtr;
| ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type
|
note: while checking the return type of the `async fn`
- --> $DIR/issue-98604.rs:7:17
+ --> $DIR/issue-98604.rs:5:17
|
LL | async fn test() {}
| ^ checked the `Output` of this `async fn`, found opaque type
-fn hi() -> impl Sized { std::ptr::null::<u8>() }
+fn hi() -> impl Sized {
+ std::ptr::null::<u8>()
+}
fn main() {
let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
- //~^ ERROR type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
+ //~^ ERROR expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
let boxed = b();
let null = *boxed;
println!("{null:?}");
-error[E0271]: type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
- --> $DIR/issue-98608.rs:4:39
+error[E0271]: expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
+ --> $DIR/issue-98608.rs:6:39
|
-LL | fn hi() -> impl Sized { std::ptr::null::<u8>() }
+LL | fn hi() -> impl Sized {
| ---------- the found opaque type
...
LL | let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
--- /dev/null
+// run-rustfix
+fn main() {
+ let mut _foo: i32 = 1;
+ let _foo: i32 = 4; //~ ERROR type ascription is experimental
+}
--- /dev/null
+// run-rustfix
+fn main() {
+ let mut _foo: i32 = 1;
+ _foo: i32 = 4; //~ ERROR type ascription is experimental
+}
--- /dev/null
+error[E0658]: type ascription is experimental
+ --> $DIR/missing-let-in-binding.rs:4:5
+ |
+LL | _foo: i32 = 4;
+ | ^^^^^^^^^
+ |
+ = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+ = help: add `#![feature(type_ascription)]` to the crate attributes to enable
+help: you might have meant to introduce a new binding
+ |
+LL | let _foo: i32 = 4;
+ | +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// run-rustfix
+
+const _A: i32 = 123;
+//~^ ERROR: missing type for `const` item
+
+fn main() {
+ const _B: i32 = 123;
+ //~^ ERROR: missing type for `const` item
+}
--- /dev/null
+// run-rustfix
+
+const _A: = 123;
+//~^ ERROR: missing type for `const` item
+
+fn main() {
+ const _B: = 123;
+ //~^ ERROR: missing type for `const` item
+}
--- /dev/null
+error: missing type for `const` item
+ --> $DIR/issue-100164.rs:3:10
+ |
+LL | const _A: = 123;
+ | ^ help: provide a type for the constant: `i32`
+
+error: missing type for `const` item
+ --> $DIR/issue-100164.rs:7:14
+ |
+LL | const _B: = 123;
+ | ^ help: provide a type for the constant: `i32`
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+#![recursion_limit = "5"] // To reduce noise
+
+//expect incompatible type error when ambiguous traits are in scope
+//and not an overflow error on the span in the main function.
+
+struct Ratio<T>(T);
+
+pub trait Pow {
+ fn pow(self) -> Self;
+}
+
+impl<'a, T> Pow for &'a Ratio<T>
+where
+ &'a T: Pow,
+{
+ fn pow(self) -> Self {
+ self
+ }
+}
+
+fn downcast<'a, W: ?Sized>() -> std::io::Result<&'a W> {
+ todo!()
+}
+
+struct Other;
+
+fn main() -> std::io::Result<()> {
+ let other: Other = downcast()?;//~ERROR 28:24: 28:35: `?` operator has incompatible types
+ Ok(())
+}
--- /dev/null
+error[E0308]: `?` operator has incompatible types
+ --> $DIR/issue-100246.rs:28:24
+ |
+LL | let other: Other = downcast()?;
+ | ^^^^^^^^^^^ expected struct `Other`, found reference
+ |
+ = note: `?` operator cannot convert from `&_` to `Other`
+ = note: expected struct `Other`
+ found reference `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
| &str
error: missing type for `const` item
- --> $DIR/issue-79040.rs:2:11
+ --> $DIR/issue-79040.rs:2:14
|
LL | const FOO = "hello" + 1;
- | ^^^ help: provide a type for the item: `FOO: <type>`
+ | ^ help: provide a type for the item: `: <type>`
error: aborting due to 2 previous errors
--> $DIR/issue-91210-ptr-method.rs:10:7
|
LL | x.read = 4;
- | - ^^^^ method, not a field
- | |
- | help: to access the field, dereference first: `(*x)`
+ | ^^^^ method, not a field
+ |
+help: to access the field, dereference first
+ |
+LL | (*x).read = 4;
+ | ++ +
error: aborting due to previous error
--- /dev/null
+fn foo() -> i32 {
+ for i in 0..0 {
+ //~^ ERROR: mismatched types [E0308]
+ return i;
+ }
+ //~| help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-98982.rs:2:5
+ |
+LL | fn foo() -> i32 {
+ | --- expected `i32` because of return type
+LL | / for i in 0..0 {
+LL | |
+LL | | return i;
+LL | | }
+ | |_____^ expected `i32`, found `()`
+ |
+note: the function expects a value to always be returned, but loops might run zero times
+ --> $DIR/issue-98982.rs:2:5
+ |
+LL | for i in 0..0 {
+ | ^^^^^^^^^^^^^ this might have zero elements to iterate on
+LL |
+LL | return i;
+ | -------- if the loop doesn't execute, this value would never get returned
+ = help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
|
error: missing type for `static` item
- --> $DIR/typeck_type_placeholder_item.rs:73:12
+ --> $DIR/typeck_type_placeholder_item.rs:73:13
|
LL | static A = 42;
- | ^ help: provide a type for the static variable: `A: i32`
+ | ^ help: provide a type for the static variable: `: i32`
error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
--> $DIR/typeck_type_placeholder_item.rs:75:15
use std::any::{Any, TypeId};
-struct Struct<'a>(&'a ());
+struct Struct<'a>(#[allow(unused_tuple_struct_fields)] &'a ());
trait Trait<'a> {}
fn main() {
#![allow(incomplete_features, unused_braces, unused_parens)]
#![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)]
-struct A<X: ?Sized>(X);
+struct A<X: ?Sized>(#[allow(unused_tuple_struct_fields)] X);
fn udrop<T: ?Sized>(_x: T) {}
fn foo() -> Box<[u8]> {
// run-pass
// Test that we allow unsizing even if there is an unchanged param in the
// field getting unsized.
-struct A<T, U: ?Sized + 'static>(T, B<T, U>);
-struct B<T, U: ?Sized>(T, U);
+struct A<T, U: ?Sized + 'static>(#[allow(unused_tuple_struct_fields)] T, B<T, U>);
+struct B<T, U: ?Sized>(#[allow(unused_tuple_struct_fields)] T, U);
fn main() {
let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
-Subproject commit 85b500ccad8cd0b63995fd94a03ddd4b83f7905b
+Subproject commit efd4ca3dc0b89929dc8c5f5c023d25978d76cb61
[#7407](https://github.com/rust-lang/rust-clippy/pull/7407)
* [`redundant_allocation`]: Now additionally supports the `Arc<>` type
[#7308](https://github.com/rust-lang/rust-clippy/pull/7308)
-* [`blacklisted_name`]: Now allows blacklisted names in test code
+* [`disallowed_names`]: Now allows disallowed names in test code
[#7379](https://github.com/rust-lang/rust-clippy/pull/7379)
* [`redundant_closure`]: Suggests `&mut` for `FnMut`
[#7437](https://github.com/rust-lang/rust-clippy/pull/7437)
[#5692](https://github.com/rust-lang/rust-clippy/pull/5692)
* [`if_same_then_else`]: Don't assume multiplication is always commutative
[#5702](https://github.com/rust-lang/rust-clippy/pull/5702)
-* [`blacklisted_name`]: Remove `bar` from the default configuration
+* [`disallowed_names`]: Remove `bar` from the default configuration
[#5712](https://github.com/rust-lang/rust-clippy/pull/5712)
* [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts
[#5724](https://github.com/rust-lang/rust-clippy/pull/5724)
[`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
[`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
+[`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names
[`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
[`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
+[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
[`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
[`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap
[`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
[`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
+[`overly_complex_bool_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#overly_complex_bool_expr
[`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
[`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
[`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
[`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
[`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
+[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
[`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
## The Clippy book
If you're new to Clippy and don't know where to start the [Clippy book] includes
-a developer guide and is a good place to start your journey.
+a [developer guide] and is a good place to start your journey.
-<!-- FIXME: Link to the deployed book, once it is deployed through CI -->
-[Clippy book]: book/src
+[Clippy book]: https://doc.rust-lang.org/nightly/clippy/index.html
+[developer guide]: https://doc.rust-lang.org/nightly/clippy/development/index.html
## High level approach
[package]
name = "clippy"
-version = "0.1.64"
+version = "0.1.65"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
```toml
avoid-breaking-exported-api = false
-blacklisted-names = ["toto", "tata", "titi"]
+disallowed-names = ["toto", "tata", "titi"]
cognitive-complexity-threshold = 30
```
```toml
avoid-breaking-exported-api = false
-blacklisted-names = ["toto", "tata", "titi"]
+disallowed-names = ["toto", "tata", "titi"]
cognitive-complexity-threshold = 30
```
let mut lint_context = None;
let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| {
- let range = offset..offset + t.len;
+ let range = offset..offset + t.len as usize;
offset = range.end;
LintDeclSearchResult {
fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
let mut offset = 0usize;
let mut iter = tokenize(contents).map(|t| {
- let range = offset..offset + t.len;
+ let range = offset..offset + t.len as usize;
offset = range.end;
LintDeclSearchResult {
fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) {
let mut offset = 0usize;
let mut iter = tokenize(contents).map(|t| {
- let range = offset..offset + t.len;
+ let range = offset..offset + t.len as usize;
offset = range.end;
LintDeclSearchResult {
for line in contents.lines() {
let mut offset = 0usize;
let mut iter = tokenize(line).map(|t| {
- let range = offset..offset + t.len;
+ let range = offset..offset + t.len as usize;
offset = range.end;
LintDeclSearchResult {
[package]
name = "clippy_lints"
-version = "0.1.64"
+version = "0.1.65"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
/// ### Why is this bad?
/// An assertion failure cannot output an useful message of the error.
///
+ /// ### Known problems
+ /// The suggested replacement decreases the readability of code and log output.
+ ///
/// ### Example
/// ```rust,ignore
/// # let r = Ok::<_, ()>(());
/// ```
#[clippy::version = "1.64.0"]
pub ASSERTIONS_ON_RESULT_STATES,
- style,
+ restriction,
"`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`"
}
if result_type_with_refs != result_type {
return;
} else if let Res::Local(binding_id) = path_res(cx, recv)
- && local_used_after_expr(cx, binding_id, recv) {
+ && local_used_after_expr(cx, binding_id, recv)
+ {
return;
}
}
let mut app = Applicability::MachineApplicable;
match method_segment.ident.as_str() {
- "is_ok" if has_debug_impl(cx, substs.type_at(1)) => {
+ "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => {
span_lint_and_sugg(
cx,
ASSERTIONS_ON_RESULT_STATES,
app,
);
}
- "is_err" if has_debug_impl(cx, substs.type_at(0)) => {
+ "is_err" if type_suitable_to_unwrap(cx, substs.type_at(0)) => {
span_lint_and_sugg(
cx,
ASSERTIONS_ON_RESULT_STATES,
.get_diagnostic_item(sym::Debug)
.map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
}
+
+fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+ has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never()
+}
+++ /dev/null
-use clippy_utils::{diagnostics::span_lint, is_test_module_or_function};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{Item, Pat, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for usage of blacklisted names for variables, such
- /// as `foo`.
- ///
- /// ### Why is this bad?
- /// These names are usually placeholder names and should be
- /// avoided.
- ///
- /// ### Example
- /// ```rust
- /// let foo = 3.14;
- /// ```
- #[clippy::version = "pre 1.29.0"]
- pub BLACKLISTED_NAME,
- style,
- "usage of a blacklisted/placeholder name"
-}
-
-#[derive(Clone, Debug)]
-pub struct BlacklistedName {
- blacklist: FxHashSet<String>,
- test_modules_deep: u32,
-}
-
-impl BlacklistedName {
- pub fn new(blacklist: FxHashSet<String>) -> Self {
- Self {
- blacklist,
- test_modules_deep: 0,
- }
- }
-
- fn in_test_module(&self) -> bool {
- self.test_modules_deep != 0
- }
-}
-
-impl_lint_pass!(BlacklistedName => [BLACKLISTED_NAME]);
-
-impl<'tcx> LateLintPass<'tcx> for BlacklistedName {
- fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
- if is_test_module_or_function(cx.tcx, item) {
- self.test_modules_deep = self.test_modules_deep.saturating_add(1);
- }
- }
-
- fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
- // Check whether we are under the `test` attribute.
- if self.in_test_module() {
- return;
- }
-
- if let PatKind::Binding(.., ident, _) = pat.kind {
- if self.blacklist.contains(&ident.name.to_string()) {
- span_lint(
- cx,
- BLACKLISTED_NAME,
- ident.span,
- &format!("use of a blacklisted/placeholder name `{}`", ident.name),
- );
- }
- }
- }
-
- fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
- if is_test_module_or_function(cx.tcx, item) {
- self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
- }
- }
-}
/// if a {}
/// ```
#[clippy::version = "pre 1.29.0"]
- pub LOGIC_BUG,
+ pub OVERLY_COMPLEX_BOOL_EXPR,
correctness,
"boolean expressions that contain terminals which can be eliminated"
}
// For each pairs, both orders are considered.
const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
-declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, LOGIC_BUG]);
+declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]);
impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
fn check_fn(
if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 {
span_lint_hir_and_then(
self.cx,
- LOGIC_BUG,
+ OVERLY_COMPLEX_BOOL_EXPR,
e.hir_id,
e.span,
"this boolean expression contains a logic bug",
span,
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
"replace with",
- format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
+ format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()),
Applicability::MachineApplicable,
);
}
let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
if_chain! {
// `from_type::from, to_type::max_value()`
- if let ExprKind::Call(from_func, args) = &expr.kind;
- // `to_type::max_value()`
- if args.len() == 1;
- if let limit = &args[0];
+ if let ExprKind::Call(from_func, [limit]) = &expr.kind;
// `from_type::from`
if let ExprKind::Path(ref path) = &from_func.kind;
if let Some(from_sym) = get_implementing_type(path, INTS, "from");
impl LateLintPass<'_> for CreateDir {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
- if let ExprKind::Call(func, args) = expr.kind;
+ if let ExprKind::Call(func, [arg, ..]) = expr.kind;
if let ExprKind::Path(ref path) = func.kind;
if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR);
expr.span,
"calling `std::fs::create_dir` where there may be a better way",
"consider calling `std::fs::create_dir_all` instead",
- format!("create_dir_all({})", snippet(cx, args[0].span, "..")),
+ format!("create_dir_all({})", snippet(cx, arg.span, "..")),
Applicability::MaybeIncorrect,
)
}
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_macro_callsite;
use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, match_def_path, paths};
+use clippy_utils::{
+ any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths,
+};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
if let QPath::Resolved(None, _path) = qpath;
let expr_ty = cx.typeck_results().expr_ty(expr);
if let ty::Adt(def, ..) = expr_ty.kind();
+ if !is_from_proc_macro(cx, expr);
then {
// TODO: Work out a way to put "whatever the imported way of referencing
// this type in this file" rather than a fully-qualified type.
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, variant_of_res};
+use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res};
use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage};
use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
use rustc_data_structures::fx::FxIndexMap;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults};
+use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::sym, Span, Symbol};
+use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
declare_clippy_lint! {
},
DerefedBorrow(DerefedBorrow),
ExplicitDeref {
- // Span and id of the top-level deref expression if the parent expression is a borrow.
- deref_span_id: Option<(Span, HirId)>,
+ mutability: Option<Mutability>,
},
ExplicitDerefField {
name: Symbol,
},
Reborrow {
- deref_span: Span,
- deref_hir_id: HirId,
+ mutability: Mutability,
+ },
+ Borrow {
+ mutability: Mutability,
},
- Borrow,
}
// A reference operation considered by this lint pass
enum RefOp {
Method(Mutability),
Deref,
- AddrOf,
+ AddrOf(Mutability),
}
struct RefPat {
));
} else if position.is_deref_stable() {
self.state = Some((
- State::ExplicitDeref { deref_span_id: None },
+ State::ExplicitDeref { mutability: None },
StateData { span: expr.span, hir_id: expr.hir_id, position },
));
}
},
));
},
- RefOp::AddrOf => {
+ RefOp::AddrOf(mutability) => {
// Find the number of times the borrow is auto-derefed.
let mut iter = adjustments.iter();
let mut deref_count = 0usize;
}),
StateData { span: expr.span, hir_id: expr.hir_id, position },
));
- } else if position.is_deref_stable() {
+ } else if position.is_deref_stable()
+ // Auto-deref doesn't combine with other adjustments
+ && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
+ && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
+ {
self.state = Some((
- State::Borrow,
+ State::Borrow { mutability },
StateData {
span: expr.span,
hir_id: expr.hir_id,
data,
));
},
- (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) if state.count != 0 => {
+ (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(_)) if state.count != 0 => {
self.state = Some((
State::DerefedBorrow(DerefedBorrow {
count: state.count - 1,
data,
));
},
- (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) => {
+ (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
let position = data.position;
report(cx, expr, State::DerefedBorrow(state), data);
if position.is_deref_stable() {
self.state = Some((
- State::Borrow,
+ State::Borrow { mutability },
StateData {
span: expr.span,
hir_id: expr.hir_id,
));
} else if position.is_deref_stable() {
self.state = Some((
- State::ExplicitDeref { deref_span_id: None },
+ State::ExplicitDeref { mutability: None },
StateData { span: expr.span, hir_id: expr.hir_id, position },
));
}
},
- (Some((State::Borrow, data)), RefOp::Deref) => {
+ (Some((State::Borrow { mutability }, data)), RefOp::Deref) => {
if typeck.expr_ty(sub_expr).is_ref() {
- self.state = Some((
- State::Reborrow {
- deref_span: expr.span,
- deref_hir_id: expr.hir_id,
- },
- data,
- ));
+ self.state = Some((State::Reborrow { mutability }, data));
} else {
self.state = Some((
State::ExplicitDeref {
- deref_span_id: Some((expr.span, expr.hir_id)),
+ mutability: Some(mutability),
},
data,
));
}
},
- (
- Some((
- State::Reborrow {
- deref_span,
- deref_hir_id,
- },
- data,
- )),
- RefOp::Deref,
- ) => {
+ (Some((State::Reborrow { mutability }, data)), RefOp::Deref) => {
self.state = Some((
State::ExplicitDeref {
- deref_span_id: Some((deref_span, deref_hir_id)),
+ mutability: Some(mutability),
},
data,
));
ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
return Some((RefOp::Deref, sub_expr));
},
- ExprKind::AddrOf(BorrowKind::Ref, _, sub_expr) => return Some((RefOp::AddrOf, sub_expr)),
+ ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)),
_ => return None,
};
if tcx.is_diagnostic_item(sym::deref_method, def_id) {
Postfix,
Deref,
/// Any other location which will trigger auto-deref to a specific time.
- DerefStable(i8),
+ /// Contains the precedence of the parent expression and whether the target type is sized.
+ DerefStable(i8, bool),
/// Any other location which will trigger auto-reborrowing.
+ /// Contains the precedence of the parent expression.
ReborrowStable(i8),
+ /// Contains the precedence of the parent expression.
Other(i8),
}
impl Position {
fn is_deref_stable(self) -> bool {
- matches!(self, Self::DerefStable(_))
+ matches!(self, Self::DerefStable(..))
}
fn is_reborrow_stable(self) -> bool {
- matches!(self, Self::DerefStable(_) | Self::ReborrowStable(_))
+ matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
}
fn can_auto_borrow(self) -> bool {
}
fn lint_explicit_deref(self) -> bool {
- matches!(self, Self::Other(_) | Self::DerefStable(_) | Self::ReborrowStable(_))
+ matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
}
fn precedence(self) -> i8 {
| Self::FieldAccess(_)
| Self::Postfix => PREC_POSTFIX,
Self::Deref => PREC_PREFIX,
- Self::DerefStable(p) | Self::ReborrowStable(p) | Self::Other(p) => p,
+ Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
}
}
}
}
match parent {
Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
- Some(binding_ty_auto_deref_stability(ty, precedence))
+ Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
},
Node::Item(&Item {
kind: ItemKind::Static(..) | ItemKind::Const(..),
..
}) if span.ctxt() == ctxt => {
let ty = cx.tcx.type_of(def_id);
- Some(if ty.is_ref() {
- Position::DerefStable(precedence)
- } else {
- Position::Other(precedence)
- })
+ Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
},
Node::Item(&Item {
span,
..
}) if span.ctxt() == ctxt => {
- let output = cx.tcx.fn_sig(def_id.to_def_id()).skip_binder().output();
- Some(if !output.is_ref() {
- Position::Other(precedence)
- } else if output.has_placeholders() || output.has_opaque_types() {
- Position::ReborrowStable(precedence)
- } else {
- Position::DerefStable(precedence)
- })
+ let output = cx
+ .tcx
+ .erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output());
+ Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
},
Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
ExprKind::Ret(_) => {
let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
Some(
- if let Node::Expr(Expr {
- kind: ExprKind::Closure(&Closure { fn_decl, .. }),
- ..
- }) = cx.tcx.hir().get(owner_id)
+ if let Node::Expr(
+ closure_expr @ Expr {
+ kind: ExprKind::Closure(closure),
+ ..
+ },
+ ) = cx.tcx.hir().get(owner_id)
{
- match fn_decl.output {
- FnRetTy::Return(ty) => binding_ty_auto_deref_stability(ty, precedence),
- FnRetTy::DefaultReturn(_) => Position::Other(precedence),
- }
+ closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
} else {
let output = cx
.tcx
- .fn_sig(cx.tcx.hir().local_def_id(owner_id))
- .skip_binder()
- .output();
- if !output.is_ref() {
- Position::Other(precedence)
- } else if output.has_placeholders() || output.has_opaque_types() {
- Position::ReborrowStable(precedence)
- } else {
- Position::DerefStable(precedence)
- }
+ .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output());
+ ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
},
)
},
+ ExprKind::Closure(closure) => Some(closure_result_position(
+ cx,
+ closure,
+ cx.typeck_results().expr_ty(parent),
+ precedence,
+ )),
ExprKind::Call(func, _) if func.hir_id == child_id => {
(child_id == e.hir_id).then_some(Position::Callee)
},
.map(|(hir_ty, ty)| match hir_ty {
// Type inference for closures can depend on how they're called. Only go by the explicit
// types here.
- Some(ty) => binding_ty_auto_deref_stability(ty, precedence),
- None => param_auto_deref_stability(ty.skip_binder(), precedence),
+ Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
+ None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
+ .position_for_arg(),
}),
ExprKind::MethodCall(_, args, _) => {
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
Position::MethodReceiver
}
} else {
- param_auto_deref_stability(cx.tcx.fn_sig(id).skip_binder().inputs()[i], precedence)
+ ty_auto_deref_stability(
+ cx,
+ cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
+ precedence,
+ )
+ .position_for_arg()
}
})
},
.find(|f| f.expr.hir_id == child_id)
.zip(variant)
.and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name))
- .map(|field| param_auto_deref_stability(cx.tcx.type_of(field.did), precedence))
+ .map(|field| {
+ ty_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence).position_for_arg()
+ })
},
ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
(position, adjustments)
}
+fn closure_result_position<'tcx>(
+ cx: &LateContext<'tcx>,
+ closure: &'tcx Closure<'_>,
+ ty: Ty<'tcx>,
+ precedence: i8,
+) -> Position {
+ match closure.fn_decl.output {
+ FnRetTy::Return(hir_ty) => {
+ if let Some(sig) = ty_sig(cx, ty)
+ && let Some(output) = sig.output()
+ {
+ binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
+ } else {
+ Position::Other(precedence)
+ }
+ },
+ FnRetTy::DefaultReturn(_) => Position::Other(precedence),
+ }
+}
+
// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
//
// e.g.
//
// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
// switching to auto-dereferencing.
-fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position {
+fn binding_ty_auto_deref_stability<'tcx>(
+ cx: &LateContext<'tcx>,
+ ty: &'tcx hir::Ty<'_>,
+ precedence: i8,
+ binder_args: &'tcx List<BoundVariableKind>,
+) -> Position {
let TyKind::Rptr(_, ty) = &ty.kind else {
return Position::Other(precedence);
};
{
Position::ReborrowStable(precedence)
} else {
- Position::DerefStable(precedence)
+ Position::DerefStable(
+ precedence,
+ cx.tcx
+ .erase_late_bound_regions(Binder::bind_with_vars(
+ cx.typeck_results().node_type(ty.ty.hir_id),
+ binder_args,
+ ))
+ .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+ )
}
},
- TyKind::Slice(_)
- | TyKind::Array(..)
- | TyKind::BareFn(_)
- | TyKind::Never
+ TyKind::Slice(_) => Position::DerefStable(precedence, false),
+ TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
+ TyKind::Never
| TyKind::Tup(_)
- | TyKind::Ptr(_)
- | TyKind::TraitObject(..)
- | TyKind::Path(_) => Position::DerefStable(precedence),
- TyKind::OpaqueDef(..)
- | TyKind::Infer
- | TyKind::Typeof(..)
- | TyKind::Err => Position::ReborrowStable(precedence),
+ | TyKind::Path(_) => Position::DerefStable(
+ precedence,
+ cx.tcx
+ .erase_late_bound_regions(Binder::bind_with_vars(
+ cx.typeck_results().node_type(ty.ty.hir_id),
+ binder_args,
+ ))
+ .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+ ),
+ TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
+ Position::ReborrowStable(precedence)
+ },
};
}
}
v.0
}
+struct TyPosition<'tcx> {
+ position: Position,
+ ty: Option<Ty<'tcx>>,
+}
+impl From<Position> for TyPosition<'_> {
+ fn from(position: Position) -> Self {
+ Self { position, ty: None }
+ }
+}
+impl<'tcx> TyPosition<'tcx> {
+ fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
+ Self {
+ position: Position::ReborrowStable(precedence),
+ ty: Some(ty),
+ }
+ }
+ fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
+ match (self.position, self.ty) {
+ (Position::ReborrowStable(precedence), Some(ty)) => {
+ Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env))
+ },
+ (position, _) => position,
+ }
+ }
+ fn position_for_arg(self) -> Position {
+ self.position
+ }
+}
+
// Checks whether a type is stable when switching to auto dereferencing,
-fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
+fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
let ty::Ref(_, mut ty, _) = *ty.kind() else {
- return Position::Other(precedence);
+ return Position::Other(precedence).into();
};
loop {
ty = ref_ty;
continue;
},
- ty::Infer(_)
- | ty::Error(_)
- | ty::Param(_)
- | ty::Bound(..)
- | ty::Opaque(..)
- | ty::Placeholder(_)
- | ty::Dynamic(..) => Position::ReborrowStable(precedence),
- ty::Adt(..) if ty.has_placeholders() || ty.has_param_types_or_consts() => {
- Position::ReborrowStable(precedence)
+ ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
+ ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
+ Position::ReborrowStable(precedence).into()
},
- ty::Adt(..)
- | ty::Bool
+ ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
+ Position::ReborrowStable(precedence).into()
+ },
+ ty::Adt(_, substs) if substs.has_param_types_or_consts() => {
+ TyPosition::new_deref_stable_for_result(precedence, ty)
+ },
+ ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
- | ty::Float(_)
- | ty::Foreign(_)
- | ty::Str
| ty::Array(..)
- | ty::Slice(..)
+ | ty::Float(_)
| ty::RawPtr(..)
+ | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
+ ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
+ ty::Adt(..)
+ | ty::Foreign(_)
| ty::FnDef(..)
- | ty::FnPtr(_)
- | ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
+ | ty::Closure(..)
| ty::Never
| ty::Tuple(_)
- | ty::Projection(_) => Position::DerefStable(precedence),
+ | ty::Projection(_) => Position::DerefStable(
+ precedence,
+ ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+ )
+ .into(),
};
}
}
diag.span_suggestion(data.span, "change this to", sugg, app);
});
},
- State::ExplicitDeref { deref_span_id } => {
- let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id
+ State::ExplicitDeref { mutability } => {
+ if matches!(
+ expr.kind,
+ ExprKind::Block(..)
+ | ExprKind::ConstBlock(_)
+ | ExprKind::If(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ ) && matches!(data.position, Position::DerefStable(_, true))
+ {
+ // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
+ return;
+ }
+
+ let (prefix, precedence) = if let Some(mutability) = mutability
&& !cx.typeck_results().expr_ty(expr).is_ref()
{
- (span, hir_id, PREC_PREFIX)
+ let prefix = match mutability {
+ Mutability::Not => "&",
+ Mutability::Mut => "&mut ",
+ };
+ (prefix, 0)
} else {
- (data.span, data.hir_id, data.position.precedence())
+ ("", data.position.precedence())
};
span_lint_hir_and_then(
cx,
EXPLICIT_AUTO_DEREF,
- hir_id,
- span,
+ data.hir_id,
+ data.span,
"deref which would be done by auto-deref",
|diag| {
let mut app = Applicability::MachineApplicable;
- let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, span.ctxt(), "..", &mut app);
+ let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
let sugg =
if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
- format!("({})", snip)
+ format!("{}({})", prefix, snip)
} else {
- snip.into()
+ format!("{}{}", prefix, snip)
};
- diag.span_suggestion(span, "try this", sugg, app);
+ diag.span_suggestion(data.span, "try this", sugg, app);
},
);
},
State::ExplicitDerefField { .. } => {
+ if matches!(
+ expr.kind,
+ ExprKind::Block(..)
+ | ExprKind::ConstBlock(_)
+ | ExprKind::If(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ ) && matches!(data.position, Position::DerefStable(_, true))
+ {
+ // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
+ return;
+ }
+
span_lint_hir_and_then(
cx,
EXPLICIT_AUTO_DEREF,
},
);
},
- State::Borrow | State::Reborrow { .. } => (),
+ State::Borrow { .. } | State::Reborrow { .. } => (),
}
}
--- /dev/null
+use clippy_utils::{diagnostics::span_lint, is_test_module_or_function};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::{Item, Pat, PatKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of disallowed names for variables, such
+ /// as `foo`.
+ ///
+ /// ### Why is this bad?
+ /// These names are usually placeholder names and should be
+ /// avoided.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let foo = 3.14;
+ /// ```
+ #[clippy::version = "pre 1.29.0"]
+ pub DISALLOWED_NAMES,
+ style,
+ "usage of a disallowed/placeholder name"
+}
+
+#[derive(Clone, Debug)]
+pub struct DisallowedNames {
+ disallow: FxHashSet<String>,
+ test_modules_deep: u32,
+}
+
+impl DisallowedNames {
+ pub fn new(disallow: FxHashSet<String>) -> Self {
+ Self {
+ disallow,
+ test_modules_deep: 0,
+ }
+ }
+
+ fn in_test_module(&self) -> bool {
+ self.test_modules_deep != 0
+ }
+}
+
+impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
+
+impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+ if is_test_module_or_function(cx.tcx, item) {
+ self.test_modules_deep = self.test_modules_deep.saturating_add(1);
+ }
+ }
+
+ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
+ // Check whether we are under the `test` attribute.
+ if self.in_test_module() {
+ return;
+ }
+
+ if let PatKind::Binding(.., ident, _) = pat.kind {
+ if self.disallow.contains(&ident.name.to_string()) {
+ span_lint(
+ cx,
+ DISALLOWED_NAMES,
+ ident.span,
+ &format!("use of a disallowed/placeholder name `{}`", ident.name),
+ );
+ }
+ }
+ }
+
+ fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+ if is_test_module_or_function(cx.tcx, item) {
+ self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
+ }
+ }
+}
}
}
},
- ExprKind::MethodCall(_, ref params, _) => {
- if params.len() == 2 {
- let param = ¶ms[1];
+ ExprKind::MethodCall(_, _, ref params, _) => {
+ if let [ref param] = params[..] {
if let ExprKind::Paren(_) = param.kind {
span_lint(cx, DOUBLE_PARENS, param.span, msg);
}
}
fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
- match cx.tcx.associated_item(method_def_id).container {
- ty::TraitContainer(def_id) => cx.tcx.def_path_str(def_id),
- ty::ImplContainer(def_id) => {
+ let assoc_item = cx.tcx.associated_item(method_def_id);
+ let def_id = assoc_item.container_id(cx.tcx);
+ match assoc_item.container {
+ ty::TraitContainer => cx.tcx.def_path_str(def_id),
+ ty::ImplContainer => {
let ty = cx.tcx.type_of(def_id);
match ty.kind() {
ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
+use clippy_utils::is_span_if;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
if_chain! {
if !first.span.from_expansion() && !second.span.from_expansion();
- if let ExprKind::If(cond_expr, ..) = &first.kind;
+ if matches!(first.kind, ExprKind::If(..));
if is_block(second) || is_if(second);
// Proc-macros can give weird spans. Make sure this is actually an `if`.
- if let Some(if_snip) = snippet_opt(cx, first.span.until(cond_expr.span));
- if if_snip.starts_with("if");
+ if is_span_if(cx, first.span);
// If there is a line break between the two expressions, don't lint.
// If there is a non-whitespace character, this span came from a proc-macro.
impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
if_chain! {
- if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
+ if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind;
if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind;
// check if the first part of the path is some integer primitive
if pathseg.ident.name.as_str() == "from_str_radix";
// check if the second argument is a primitive `10`
- if arguments.len() == 2;
- if let ExprKind::Lit(lit) = &arguments[1].kind;
+ if let ExprKind::Lit(lit) = &radix.kind;
if let rustc_ast::ast::LitKind::Int(10, _) = lit.node;
then {
- let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind {
+ let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
let ty = cx.typeck_results().expr_ty(expr);
if is_ty_stringish(cx, ty) {
expr
} else {
- &arguments[0]
+ &src
}
} else {
- &arguments[0]
+ &src
};
let sugg = Sugg::hir_with_applicability(
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span};
use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt;
-use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine};
+use rustc_trait_selection::traits::{self, FulfillmentError};
declare_clippy_lint! {
/// ### What it does
let span = decl.output.span();
let send_errors = cx.tcx.infer_ctxt().enter(|infcx| {
let cause = traits::ObligationCause::misc(span, hir_id);
- let mut fulfillment_cx = traits::FulfillmentContext::new();
- fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause);
- fulfillment_cx.select_all_or_error(&infcx)
+ traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait)
});
if !send_errors.is_empty() {
span_lint_and_then(
LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
LintId::of(approx_const::APPROX_CONSTANT),
LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
- LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
LintId::of(attrs::DEPRECATED_CFG_ATTR),
LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
- LintId::of(blacklisted_name::BLACKLISTED_NAME),
LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
- LintId::of(booleans::LOGIC_BUG),
LintId::of(booleans::NONMINIMAL_BOOL),
+ LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
LintId::of(casts::CAST_ABS_TO_UNSIGNED),
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(disallowed_methods::DISALLOWED_METHODS),
+ LintId::of(disallowed_names::DISALLOWED_NAMES),
LintId::of(disallowed_types::DISALLOWED_TYPES),
LintId::of(doc::MISSING_SAFETY_DOC),
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
LintId::of(matches::MATCH_STR_CASE_MISMATCH),
LintId::of(matches::NEEDLESS_MATCH),
LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
- LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
LintId::of(matches::SINGLE_MATCH),
LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
+ LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
LintId::of(precedence::PRECEDENCE),
LintId::of(ptr::CMP_NULL),
LintId::of(ptr::INVALID_NULL_PTR_USAGE),
LintId::of(attrs::DEPRECATED_SEMVER),
LintId::of(attrs::MISMATCHED_TARGET_OS),
LintId::of(attrs::USELESS_ATTRIBUTE),
- LintId::of(booleans::LOGIC_BUG),
+ LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
LintId::of(casts::CAST_REF_TO_MUT),
LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
LintId::of(copies::IFS_SAME_COND),
await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE,
await_holding_invalid::AWAIT_HOLDING_LOCK,
await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
- blacklisted_name::BLACKLISTED_NAME,
blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
bool_assert_comparison::BOOL_ASSERT_COMPARISON,
- booleans::LOGIC_BUG,
booleans::NONMINIMAL_BOOL,
+ booleans::OVERLY_COMPLEX_BOOL_EXPR,
borrow_as_ptr::BORROW_AS_PTR,
borrow_deref_ref::BORROW_DEREF_REF,
bytecount::NAIVE_BYTECOUNT,
derive::EXPL_IMPL_CLONE_ON_COPY,
derive::UNSAFE_DERIVE_DESERIALIZE,
disallowed_methods::DISALLOWED_METHODS,
+ disallowed_names::DISALLOWED_NAMES,
disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
disallowed_types::DISALLOWED_TYPES,
doc::DOC_MARKDOWN,
manual_assert::MANUAL_ASSERT,
manual_async_fn::MANUAL_ASYNC_FN,
manual_bits::MANUAL_BITS,
+ manual_instant_elapsed::MANUAL_INSTANT_ELAPSED,
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
manual_ok_or::MANUAL_OK_OR,
manual_rem_euclid::MANUAL_REM_EUCLID,
panic_unimplemented::UNIMPLEMENTED,
panic_unimplemented::UNREACHABLE,
partialeq_ne_impl::PARTIALEQ_NE_IMPL,
+ partialeq_to_none::PARTIALEQ_TO_NONE,
pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
LintId::of(future_not_send::FUTURE_NOT_SEND),
LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
+ LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
LintId::of(methods::ITER_WITH_DRAIN),
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
LintId::of(loops::EXPLICIT_ITER_LOOP),
LintId::of(macro_use::MACRO_USE_IMPORTS),
LintId::of(manual_assert::MANUAL_ASSERT),
+ LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED),
LintId::of(manual_ok_or::MANUAL_OK_OR),
LintId::of(matches::MATCH_BOOL),
LintId::of(matches::MATCH_ON_VEC_ITEMS),
LintId::of(as_underscore::AS_UNDERSCORE),
LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+ LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
LintId::of(create_dir::CREATE_DIR),
store.register_group(true, "clippy::style", Some("clippy_style"), vec![
LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
- LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
- LintId::of(blacklisted_name::BLACKLISTED_NAME),
LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
LintId::of(casts::FN_TO_NUMERIC_CAST),
LintId::of(dereference::NEEDLESS_BORROW),
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
LintId::of(disallowed_methods::DISALLOWED_METHODS),
+ LintId::of(disallowed_names::DISALLOWED_NAMES),
LintId::of(disallowed_types::DISALLOWED_TYPES),
LintId::of(doc::MISSING_SAFETY_DOC),
LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
LintId::of(operators::ASSIGN_OP_PATTERN),
LintId::of(operators::OP_REF),
LintId::of(operators::PTR_EQ),
+ LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
LintId::of(ptr::CMP_NULL),
LintId::of(ptr::PTR_ARG),
LintId::of(question_mark::QUESTION_MARK),
LintId::of(loops::EMPTY_LOOP),
LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
LintId::of(loops::MUT_RANGE_BOUND),
- LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
LintId::of(methods::NO_EFFECT_REPLACE),
LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
mod async_yields_async;
mod attrs;
mod await_holding_invalid;
-mod blacklisted_name;
mod blocks_in_if_conditions;
mod bool_assert_comparison;
mod booleans;
mod derivable_impls;
mod derive;
mod disallowed_methods;
+mod disallowed_names;
mod disallowed_script_idents;
mod disallowed_types;
mod doc;
mod manual_assert;
mod manual_async_fn;
mod manual_bits;
+mod manual_instant_elapsed;
mod manual_non_exhaustive;
mod manual_ok_or;
mod manual_rem_euclid;
mod panic_in_result_fn;
mod panic_unimplemented;
mod partialeq_ne_impl;
+mod partialeq_to_none;
mod pass_by_ref_or_value;
mod path_buf_push_overwrite;
mod pattern_type_mismatch;
},
};
- let TryConf { conf, errors } = utils::conf::read(&file_name);
+ let TryConf { conf, errors, warnings } = utils::conf::read(&file_name);
// all conf errors are non-fatal, we just use the default conf in case of error
for error in errors {
sess.err(&format!(
));
}
+ for warning in warnings {
+ sess.struct_warn(&format!(
+ "error reading Clippy's configuration file `{}`: {}",
+ file_name.display(),
+ format_error(warning)
+ ))
+ .emit();
+ }
+
conf
}
store.register_late_pass(|| Box::new(swap::Swap));
store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional));
store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default()));
- let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone())));
+ let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>();
+ store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
let too_many_arguments_threshold = conf.too_many_arguments_threshold;
let too_many_lines_threshold = conf.too_many_lines_threshold;
store.register_late_pass(move || {
store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default()));
+ store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed));
+ store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone));
// add lints here, do not remove this comment, it's used in `new_lint`
}
let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
if_chain! {
- if let ExprKind::MethodCall(method, len_args, _) = end.kind;
+ if let ExprKind::MethodCall(method, [recv], _) = end.kind;
if method.ident.name == sym::len;
- if len_args.len() == 1;
- if let Some(arg) = len_args.get(0);
- if path_to_local(arg) == path_to_local(base);
+ if path_to_local(recv) == path_to_local(base);
then {
if sugg.to_string() == end_str {
sugg::EMPTY.into()
fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
if_chain! {
- if let ExprKind::MethodCall(method, args, _) = expr.kind;
+ if let ExprKind::MethodCall(method, [arg], _) = expr.kind;
if method.ident.name == sym::clone;
- if args.len() == 1;
- if let Some(arg) = args.get(0);
then { arg } else { expr }
}
}
fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
if_chain! {
- if let ExprKind::MethodCall(method, len_args, _) = expr.kind;
- if len_args.len() == 1;
+ if let ExprKind::MethodCall(method, [recv], _) = expr.kind;
if method.ident.name == sym::len;
- if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind;
+ if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
if path.segments.len() == 1;
if path.segments[0].ident.name == var;
then {
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Lints subtraction between `Instant::now()` and another `Instant`.
+ ///
+ /// ### Why is this bad?
+ /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
+ /// as `Instant` subtraction saturates.
+ ///
+ /// `prev_instant.elapsed()` also more clearly signals intention.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::time::Instant;
+ /// let prev_instant = Instant::now();
+ /// let duration = Instant::now() - prev_instant;
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::time::Instant;
+ /// let prev_instant = Instant::now();
+ /// let duration = prev_instant.elapsed();
+ /// ```
+ #[clippy::version = "1.64.0"]
+ pub MANUAL_INSTANT_ELAPSED,
+ pedantic,
+ "subtraction between `Instant::now()` and previous `Instant`"
+}
+
+declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]);
+
+impl LateLintPass<'_> for ManualInstantElapsed {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+ if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind
+ && check_instant_now_call(cx, lhs)
+ && let ty_resolved = cx.typeck_results().expr_ty(rhs)
+ && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind()
+ && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT)
+ && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs)
+ {
+ span_lint_and_sugg(
+ cx,
+ MANUAL_INSTANT_ELAPSED,
+ expr.span,
+ "manual implementation of `Instant::elapsed`",
+ "try",
+ format!("{}.elapsed()", sugg.maybe_par()),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
+
+fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
+ if let ExprKind::Call(fn_expr, []) = expr_block.kind
+ && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
+ && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
+ {
+ true
+ } else {
+ false
+ }
+}
}
if_chain! {
- if let ExprKind::MethodCall(method_segment, args, _) = scrutinee.kind;
+ if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind;
if method_segment.ident.name == sym!(map_or);
- if args.len() == 3;
- let method_receiver = &args[0];
- let ty = cx.typeck_results().expr_ty(method_receiver);
+ let ty = cx.typeck_results().expr_ty(receiver);
if is_type_diagnostic_item(cx, ty, sym::Option);
- let or_expr = &args[1];
- if is_ok_wrapping(cx, &args[2]);
+ if is_ok_wrapping(cx, map_expr);
if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind;
if is_lang_ctor(cx, err_path, ResultErr);
- if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span);
+ if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span);
if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
if let Some(indent) = indent_of(cx, scrutinee.span);
then {
}
// check if this is a method call (e.g. x.foo())
- if let ExprKind::MethodCall(method, args, _) = e.kind {
+ if let ExprKind::MethodCall(method, [_, arg], _) = e.kind {
// only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
// Enum::Variant[2]))
- if method.ident.as_str() == "map_err" && args.len() == 2 {
+ if method.ident.name == sym!(map_err) {
// make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span
// fields
if let ExprKind::Closure(&Closure {
body,
fn_decl_span,
..
- }) = args[1].kind
+ }) = arg.kind
{
// check if this is by Reference (meaning there's no move statement)
if capture_clause == CaptureBy::Ref {
declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]);
fn is_unit_type(ty: Ty<'_>) -> bool {
- match ty.kind() {
- ty::Tuple(slice) => slice.is_empty(),
- ty::Never => true,
- _ => false,
- }
+ ty.is_unit() || ty.is_never()
}
fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
if is_lang_ctor(cx, qpath, LangItem::OptionSome);
if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
- if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
+ if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
if let ExprKind::Path(ref some_path) = e.kind;
- if is_lang_ctor(cx, some_path, LangItem::OptionSome) && args.len() == 1;
- if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
+ if is_lang_ctor(cx, some_path, LangItem::OptionSome);
+ if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
then {
return Some(rb)
mod try_err;
mod wild_in_or_pats;
-use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context};
-use clippy_utils::{higher, in_constant, meets_msrv, msrvs};
+use clippy_utils::source::{snippet_opt, walk_span_to_context};
+use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs};
use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
/// ```
#[clippy::version = "1.60.0"]
pub SIGNIFICANT_DROP_IN_SCRUTINEE,
- suspicious,
+ nursery,
"warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime"
}
let from_expansion = expr.span.from_expansion();
if let ExprKind::Match(ex, arms, source) = expr.kind {
- if source == MatchSource::Normal && !span_starts_with(cx, expr.span, "match") {
+ if source == MatchSource::Normal && !is_span_match(cx, expr.span) {
return;
}
if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) {
let mut pos = 0usize;
let mut iter = tokenize(&snip).map(|t| {
let start = pos;
- pos += t.len;
+ pos += t.len as usize;
(t.kind, start..pos)
});
// val,
// };
if_chain! {
- if let ExprKind::Call(match_fun, try_args) = scrutinee.kind;
+ if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind;
if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..));
- if let Some(try_arg) = try_args.get(0);
- if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
- if let Some(err_arg) = err_args.get(0);
+ if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind;
if let ExprKind::Path(ref err_fun_path) = err_fun.kind;
if is_lang_ctor(cx, err_fun_path, ResultErr);
if let Some(return_ty) = find_return_type(cx, &expr.kind);
}
if_chain! {
- if let ExprKind::Call(repl_func, repl_args) = src.kind;
- if repl_args.is_empty();
+ if let ExprKind::Call(repl_func, []) = src.kind;
if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
then {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
// Check that `expr` is a call to `mem::replace()`
- if let ExprKind::Call(func, func_args) = expr.kind;
+ if let ExprKind::Call(func, [dest, src]) = 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::mem_replace, def_id);
- if let [dest, src] = func_args;
then {
check_replace_option_with_none(cx, src, dest, expr.span);
check_replace_with_uninit(cx, src, dest, expr.span);
use clippy_utils::sugg;
use clippy_utils::ty::is_copy;
use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, adjustment::Adjust};
use rustc_span::symbol::{sym, Symbol};
{
return;
},
+ // ? is a Call, makes sure not to rec *x?, but rather (*x)?
+ ExprKind::Call(hir_callee, _) => matches!(
+ hir_callee.kind,
+ ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
+ ),
ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
| ExprKind::Field(..)
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
- Some((EXPECT_USED, "an Option", "None"))
+ Some((EXPECT_USED, "an Option", "None", ""))
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
- Some((EXPECT_USED, "a Result", "Err"))
+ Some((EXPECT_USED, "a Result", "Err", "an "))
} else {
None
};
return;
}
- if let Some((lint, kind, none_value)) = mess {
+ if let Some((lint, kind, none_value, none_prefix)) = mess {
span_lint_and_help(
cx,
lint,
expr.span,
- &format!("used `expect()` on `{}` value", kind,),
+ &format!("used `expect()` on `{kind}` value"),
None,
- &format!("if this value is an `{}`, it will panic", none_value,),
+ &format!("if this value is {none_prefix}`{none_value}`, it will panic"),
);
}
}
/// option.expect("more helpful message");
/// result.expect("more helpful message");
/// ```
+ ///
+ /// If [expect_used](#expect_used) is enabled, instead:
+ /// ```rust,ignore
+ /// # let option = Some(1);
+ /// # let result: Result<usize, ()> = Ok(1);
+ /// option?;
+ ///
+ /// // or
+ ///
+ /// result?;
+ /// ```
#[clippy::version = "1.45.0"]
pub UNWRAP_USED,
restriction,
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_in_test_function;
use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_in_test_function, is_lint_allowed};
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
-use super::UNWRAP_USED;
+use super::{EXPECT_USED, UNWRAP_USED};
/// lint use of `unwrap()` for `Option`s and `Result`s
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
- Some((UNWRAP_USED, "an Option", "None"))
+ Some((UNWRAP_USED, "an Option", "None", ""))
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
- Some((UNWRAP_USED, "a Result", "Err"))
+ Some((UNWRAP_USED, "a Result", "Err", "an "))
} else {
None
};
return;
}
- if let Some((lint, kind, none_value)) = mess {
+ if let Some((lint, kind, none_value, none_prefix)) = mess {
+ let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
+ format!(
+ "if you don't want to handle the `{none_value}` case gracefully, consider \
+ using `expect()` to provide a better panic message"
+ )
+ } else {
+ format!("if this value is {none_prefix}`{none_value}`, it will panic")
+ };
+
span_lint_and_help(
cx,
lint,
expr.span,
- &format!("used `unwrap()` on `{}` value", kind,),
+ &format!("used `unwrap()` on `{kind}` value"),
None,
- &format!(
- "if you don't want to handle the `{}` case gracefully, consider \
- using `expect()` to provide a better panic message",
- none_value,
- ),
+ &help,
);
}
}
use clippy_utils::diagnostics::span_lint;
use clippy_utils::qualify_min_const_fn::is_min_const_fn;
use clippy_utils::ty::has_drop;
-use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method};
+use clippy_utils::{
+ fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method,
+};
use rustc_hir as hir;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::intravisit::FnKind;
impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
fn check_fn(
&mut self,
- cx: &LateContext<'_>,
- kind: FnKind<'_>,
+ cx: &LateContext<'tcx>,
+ kind: FnKind<'tcx>,
_: &FnDecl<'_>,
- _: &Body<'_>,
+ body: &Body<'tcx>,
span: Span,
hir_id: HirId,
) {
FnKind::Method(_, sig, ..) => {
if trait_ref_of_method(cx, def_id).is_some()
|| already_const(sig.header)
- || method_accepts_dropable(cx, sig.decl.inputs)
+ || method_accepts_droppable(cx, sig.decl.inputs)
{
return;
}
}
}
+ if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
+ return;
+ }
+
let mir = cx.tcx.optimized_mir(def_id);
if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) {
/// Returns true if any of the method parameters is a type that implements `Drop`. The method
/// can't be made const then, because `drop` can't be const-evaluated.
-fn method_accepts_dropable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool {
+fn method_accepts_droppable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool {
// If any of the params are droppable, return true
param_tys.iter().any(|hir_ty| {
let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty);
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast;
+use clippy_utils::is_from_proc_macro;
+use rustc_ast::ast::{self, MetaItem, MetaItemKind};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty::DefIdTree;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::source_map::Span;
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
}
+ fn has_include(meta: Option<MetaItem>) -> bool {
+ if_chain! {
+ if let Some(meta) = meta;
+ if let MetaItemKind::List(list) = meta.kind;
+ if let Some(meta) = list.get(0);
+ if let Some(name) = meta.ident();
+ then {
+ name.name == sym::include
+ } else {
+ false
+ }
+ }
+ }
+
fn check_missing_docs_attrs(
&self,
cx: &LateContext<'_>,
return;
}
- let has_doc = attrs.iter().any(|a| a.doc_str().is_some());
+ let has_doc = attrs
+ .iter()
+ .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
if !has_doc {
span_lint(
cx,
let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
let attrs = cx.tcx.hir().attrs(it.hir_id());
- self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+ if !is_from_proc_macro(cx, it) {
+ self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+ }
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
- self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+ if !is_from_proc_macro(cx, trait_item) {
+ self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+ }
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
// If the method is an impl for a trait, don't doc.
- match cx.tcx.associated_item(impl_item.def_id).container {
- ty::TraitContainer(_) => return,
- ty::ImplContainer(cid) => {
- if cx.tcx.impl_trait_ref(cid).is_some() {
- return;
- }
- },
+ if let Some(cid) = cx.tcx.associated_item(impl_item.def_id).impl_container(cx.tcx) {
+ if cx.tcx.impl_trait_ref(cid).is_some() {
+ return;
+ }
+ } else {
+ return;
}
let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
- self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+ if !is_from_proc_macro(cx, impl_item) {
+ self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+ }
}
fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
if !sf.is_positional() {
let attrs = cx.tcx.hir().attrs(sf.hir_id);
- self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+ if !is_from_proc_macro(cx, sf) {
+ self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+ }
}
}
fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
let attrs = cx.tcx.hir().attrs(v.id);
- self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+ if !is_from_proc_macro(cx, v) {
+ self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+ }
}
}
match tit_.kind {
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
hir::TraitItemKind::Fn(..) => {
- if tit.defaultness.has_value() {
+ if cx.tcx.impl_defaultness(tit.id.def_id).has_value() {
// trait method with default body needs inline in case
// an impl is not provided
let desc = "a default trait method";
hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(_) => return,
};
- let trait_def_id = match cx.tcx.associated_item(impl_item.def_id).container {
- TraitContainer(cid) => Some(cid),
- ImplContainer(cid) => cx.tcx.impl_trait_ref(cid).map(|t| t.def_id),
+ let assoc_item = cx.tcx.associated_item(impl_item.def_id);
+ let container_id = assoc_item.container_id(cx.tcx);
+ let trait_def_id = match assoc_item.container {
+ TraitContainer => Some(container_id),
+ ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.def_id),
};
if let Some(trait_def_id) = trait_def_id {
impl EarlyLintPass for OptionEnvUnwrap {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if_chain! {
- if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind;
+ if let ExprKind::MethodCall(path_segment, receiver, _, _) = &expr.kind;
if matches!(path_segment.ident.name, sym::expect | sym::unwrap);
- if let ExprKind::Call(caller, _) = &args[0].kind;
+ if let ExprKind::Call(caller, _) = &receiver.kind;
if is_direct_expn_of(caller.span, "option_env").is_some();
then {
span_lint_and_help(
--- /dev/null
+use clippy_utils::{
+ diagnostics::span_lint_and_sugg, is_lang_ctor, peel_hir_expr_refs, peel_ref_operators, sugg,
+ ty::is_type_diagnostic_item,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ ///
+ /// Checks for binary comparisons to a literal `Option::None`.
+ ///
+ /// ### Why is this bad?
+ ///
+ /// A programmer checking if some `foo` is `None` via a comparison `foo == None`
+ /// is usually inspired from other programming languages (e.g. `foo is None`
+ /// in Python).
+ /// Checking if a value of type `Option<T>` is (not) equal to `None` in that
+ /// way relies on `T: PartialEq` to do the comparison, which is unneeded.
+ ///
+ /// ### Example
+ /// ```rust
+ /// fn foo(f: Option<u32>) -> &'static str {
+ /// if f != None { "yay" } else { "nay" }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn foo(f: Option<u32>) -> &'static str {
+ /// if f.is_some() { "yay" } else { "nay" }
+ /// }
+ /// ```
+ #[clippy::version = "1.64.0"]
+ pub PARTIALEQ_TO_NONE,
+ style,
+ "Binary comparison to `Option<T>::None` relies on `T: PartialEq`, which is unneeded"
+}
+declare_lint_pass!(PartialeqToNone => [PARTIALEQ_TO_NONE]);
+
+impl<'tcx> LateLintPass<'tcx> for PartialeqToNone {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+ // Skip expanded code, as we have no control over it anyway...
+ if e.span.from_expansion() {
+ return;
+ }
+
+ // If the expression is of type `Option`
+ let is_ty_option =
+ |expr: &Expr<'_>| is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr).peel_refs(), sym::Option);
+
+ // If the expression is a literal `Option::None`
+ let is_none_ctor = |expr: &Expr<'_>| {
+ matches!(&peel_hir_expr_refs(expr).0.kind,
+ ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone))
+ };
+
+ let mut applicability = Applicability::MachineApplicable;
+
+ if let ExprKind::Binary(op, left_side, right_side) = e.kind {
+ // All other comparisons (e.g. `>= None`) have special meaning wrt T
+ let is_eq = match op.node {
+ BinOpKind::Eq => true,
+ BinOpKind::Ne => false,
+ _ => return,
+ };
+
+ // We are only interested in comparisons between `Option` and a literal `Option::None`
+ let scrutinee = match (
+ is_none_ctor(left_side) && is_ty_option(right_side),
+ is_none_ctor(right_side) && is_ty_option(left_side),
+ ) {
+ (true, false) => right_side,
+ (false, true) => left_side,
+ _ => return,
+ };
+
+ // Peel away refs/derefs (as long as we don't cross manual deref impls), as
+ // autoref/autoderef will take care of those
+ let sugg = format!(
+ "{}.{}",
+ sugg::Sugg::hir_with_applicability(cx, peel_ref_operators(cx, scrutinee), "..", &mut applicability)
+ .maybe_par(),
+ if is_eq { "is_none()" } else { "is_some()" }
+ );
+
+ span_lint_and_sugg(
+ cx,
+ PARTIALEQ_TO_NONE,
+ e.span,
+ "binary comparison to literal `Option::None`",
+ if is_eq {
+ "use `Option::is_none()` instead"
+ } else {
+ "use `Option::is_some()` instead"
+ },
+ sugg,
+ applicability,
+ );
+ }
+ }
+}
impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
- if let ExprKind::MethodCall(path, args, _) = expr.kind;
+ if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind;
if path.ident.name == sym!(push);
- if args.len() == 2;
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf);
- if let Some(get_index_arg) = args.get(1);
+ if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf);
if let ExprKind::Lit(ref lit) = get_index_arg.kind;
if let LitKind::Str(ref path_lit, _) = lit.node;
if let pushed_path = Path::new(path_lit.as_str());
let mut arg = operand;
let mut all_odd = true;
- while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind {
+ while let ExprKind::MethodCall(path_segment, receiver, _, _) = &arg.kind {
let path_segment_str = path_segment.ident.name.as_str();
all_odd &= ALLOWED_ODD_FUNCTIONS
.iter()
.any(|odd_function| **odd_function == *path_segment_str);
- arg = args.first().expect("A method always has a receiver.");
+ arg = receiver;
}
if_chain! {
if_chain! {
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
if !is_else_clause(cx.tcx, expr);
- if let ExprKind::MethodCall(segment, args, _) = &cond.kind;
- if let Some(caller) = args.get(0);
+ if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind;
let caller_ty = cx.typeck_results().expr_ty(caller);
let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
if path.ident.as_str() == "zip";
if let [iter, zip_arg] = args;
// `.iter()` call
- if let ExprKind::MethodCall(iter_path, iter_args, _) = iter.kind;
+ if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind;
if iter_path.ident.name == sym::iter;
// range expression in `.zip()` call: `0..x.len()`
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
if is_integer_const(cx, start, 0);
// `.len()` call
- if let ExprKind::MethodCall(len_path, len_args, _) = end.kind;
- if len_path.ident.name == sym::len && len_args.len() == 1;
+ if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind;
+ if len_path.ident.name == sym::len;
// `.iter()` and `.len()` called on same `Path`
- if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind;
- if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
- if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
+ if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind;
+ if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind;
+ if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
then {
span_lint(cx,
RANGE_ZIP_WITH_LEN,
span,
&format!("it is more idiomatic to use `{}.iter().enumerate()`",
- snippet(cx, iter_args[0].span, "_"))
+ snippet(cx, iter_caller.span, "_"))
);
}
}
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_ast::visit as ast_visit;
if_chain! {
if let ast::ExprKind::Call(ref paren, _) = expr.kind;
if let ast::ExprKind::Paren(ref closure) = paren.kind;
- if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind;
+ if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind;
then {
let mut visitor = ReturnVisitor::new();
visitor.visit_expr(block);
"try not to call a closure in the expression where it is declared",
|diag| {
if decl.inputs.is_empty() {
- let mut app = Applicability::MachineApplicable;
- let hint =
- snippet_with_applicability(cx, block.span, "..", &mut app).into_owned();
- diag.span_suggestion(expr.span, "try doing something like", hint, app);
+ let app = Applicability::MachineApplicable;
+ let mut hint = Sugg::ast(cx, block, "..");
+
+ if r#async.is_async() {
+ // `async x` is a syntax error, so it becomes `async { x }`
+ if !matches!(block.kind, ast::ExprKind::Block(_, _)) {
+ hint = hint.blockify();
+ }
+
+ hint = hint.asyncify();
+ }
+
+ diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app);
}
},
);
impl<'tcx> LateLintPass<'tcx> for Regex {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
- if let ExprKind::Call(fun, args) = expr.kind;
+ if let ExprKind::Call(fun, [arg]) = expr.kind;
if let ExprKind::Path(ref qpath) = fun.kind;
- if args.len() == 1;
if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
then {
if match_def_path(cx, def_id, &paths::REGEX_NEW) ||
match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) {
- check_regex(cx, &args[0], true);
+ check_regex(cx, arg, true);
} else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) ||
match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) {
- check_regex(cx, &args[0], false);
+ check_regex(cx, arg, false);
} else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) {
- check_set(cx, &args[0], true);
+ check_set(cx, arg, true);
} else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) {
- check_set(cx, &args[0], false);
+ check_set(cx, arg, false);
}
}
}
#[rustfmt::skip]
pub static RENAMED_LINTS: &[(&str, &str)] = &[
+ ("clippy::blacklisted_name", "clippy::disallowed_names"),
("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
("clippy::box_vec", "clippy::box_collection"),
("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
("clippy::identity_conversion", "clippy::useless_conversion"),
("clippy::if_let_some_result", "clippy::match_result_ok"),
+ ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
("clippy::new_without_default_derive", "clippy::new_without_default"),
("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
("clippy::option_expect_used", "clippy::expect_used"),
/// Returns `true` if give expression is `repeat(0).take(...)`
fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
if_chain! {
- if let ExprKind::MethodCall(take_path, take_args, _) = expr.kind;
+ if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind;
if take_path.ident.name == sym!(take);
-
// Check that take is applied to `repeat(0)`
- if let Some(repeat_expr) = take_args.get(0);
- if self.is_repeat_zero(repeat_expr);
-
- if let Some(len_arg) = take_args.get(1);
-
+ if self.is_repeat_zero(recv);
then {
// Check that len expression is equals to `with_capacity` expression
if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintDetection> {
if_chain! {
- if let ExprKind::MethodCall(method_name, args, _) = &expr.kind;
- if let Some(slice) = &args.get(0);
+ if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind;
if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str());
if let Some(slice_type) = is_slice_of_primitives(cx, slice);
then {
- let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
+ let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type })
} else {
None
| (Unary(_, _), Unary(_, _))
| (Binary(_, _, _), Binary(_, _, _))
| (Tup(_), Tup(_))
- | (MethodCall(_, _, _), MethodCall(_, _, _))
+ | (MethodCall(_, _, _, _), MethodCall(_, _, _, _))
| (Call(_, _), Call(_, _))
| (ConstBlock(_), ConstBlock(_))
| (Array(_), Array(_))
if line.starts_with("/*") {
let src = src[line_start..line_starts.last().unwrap().to_usize() - offset].trim_start();
let mut tokens = tokenize(src);
- return src[..tokens.next().unwrap().len]
+ return src[..tokens.next().unwrap().len as usize]
.to_ascii_uppercase()
.contains("SAFETY:")
&& tokens.all(|t| t.kind == TokenKind::Whitespace);
let_unit_value::check(cx, local);
}
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
unit_cmp::check(cx, expr);
unit_arg::check(cx, expr);
}
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
use if_chain::if_chain;
use rustc_errors::Applicability;
use super::{utils, UNIT_ARG};
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if expr.span.from_expansion() {
return;
}
}
})
.collect::<Vec<_>>();
- if !args_to_recover.is_empty() {
+ if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
lint_unit_args(cx, expr, &args_to_recover);
}
},
declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
- if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind
+ if let ExprKind::MethodCall(name_ident, receiver, _, _) = &expr.kind
&& let method_name = name_ident.ident.name.as_str()
&& (method_name == "ceil" || method_name == "round" || method_name == "floor")
- && !args.is_empty()
- && let ExprKind::Lit(spanned) = &args[0].kind
+ && let ExprKind::Lit(spanned) = &receiver.kind
&& let LitKind::Float(symbol, ty) = spanned.kind {
let f = symbol.as_str().parse::<f64>().unwrap();
let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty {
}
}
- fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) {
+ fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) {
let segments = &poly.trait_ref.path.segments;
if_chain! {
ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e,
_ => return,
};
- if let ExprKind::Call(_, args) = e.kind {
- self.try_desugar_arm.push(args[0].hir_id);
+ if let ExprKind::Call(_, [arg, ..]) = e.kind {
+ self.try_desugar_arm.push(arg.hir_id);
}
},
- ExprKind::MethodCall(name, .., args, _) => {
+ ExprKind::MethodCall(name, .., [recv, ..], _) => {
if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(&args[0]);
+ let b = cx.typeck_results().expr_ty(recv);
if same_type_and_consts(a, b) {
- let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
+ let sugg = snippet_with_macro_callsite(cx, recv.span, "<expr>").to_string();
span_lint_and_sugg(
cx,
USELESS_CONVERSION,
}
}
let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(&args[0]);
+ let b = cx.typeck_results().expr_ty(recv);
if same_type_and_consts(a, b) {
- let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
+ let sugg = snippet(cx, recv.span, "<expr>").into_owned();
span_lint_and_sugg(
cx,
USELESS_CONVERSION,
if_chain! {
if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into;
let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(&args[0]);
+ let b = cx.typeck_results().expr_ty(recv);
if is_type_diagnostic_item(cx, a, sym::Result);
if let ty::Adt(_, substs) = a.kind();
if let Some(a_type) = substs.types().next();
}
},
- ExprKind::Call(path, args) => {
+ ExprKind::Call(path, [arg]) => {
if_chain! {
- if args.len() == 1;
if let ExprKind::Path(ref qpath) = path.kind;
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
then {
let a = cx.typeck_results().expr_ty(e);
- let b = cx.typeck_results().expr_ty(&args[0]);
+ let b = cx.typeck_results().expr_ty(arg);
if_chain! {
if match_def_path(cx, def_id, &paths::TRY_FROM);
if is_type_diagnostic_item(cx, a, sym::Result);
if same_type_and_consts(a, b);
then {
- let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
+ let sugg = Sugg::hir_with_macro_callsite(cx, arg, "<expr>").maybe_par();
let sugg_msg =
format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
span_lint_and_sugg(
"MinGW",
"CamelCase",
];
-const DEFAULT_BLACKLISTED_NAMES: &[&str] = &["foo", "baz", "quux"];
+const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
#[derive(Clone, Debug, Deserialize)]
pub struct TryConf {
pub conf: Conf,
pub errors: Vec<Box<dyn Error>>,
+ pub warnings: Vec<Box<dyn Error>>,
}
impl TryConf {
Self {
conf: Conf::default(),
errors: vec![Box::new(error)],
+ warnings: vec![],
}
}
}
impl Error for ConfError {}
-fn conf_error(s: String) -> Box<dyn Error> {
- Box::new(ConfError(s))
+fn conf_error(s: impl Into<String>) -> Box<dyn Error> {
+ Box::new(ConfError(s.into()))
}
macro_rules! define_Conf {
($(
$(#[doc = $doc:literal])+
- $(#[conf_deprecated($dep:literal)])?
+ $(#[conf_deprecated($dep:literal, $new_conf:ident)])?
($name:ident: $ty:ty = $default:expr),
)*) => {
/// Clippy lint configuration
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapAccess<'de> {
let mut errors = Vec::new();
+ let mut warnings = Vec::new();
$(let mut $name = None;)*
// could get `Field` here directly, but get `str` first for diagnostics
while let Some(name) = map.next_key::<&str>()? {
match Field::deserialize(name.into_deserializer())? {
$(Field::$name => {
- $(errors.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
+ $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
match map.next_value() {
Err(e) => errors.push(conf_error(e.to_string())),
Ok(value) => match $name {
Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))),
- None => $name = Some(value),
+ None => {
+ $name = Some(value);
+ // $new_conf is the same as one of the defined `$name`s, so
+ // this variable is defined in line 2 of this function.
+ $(match $new_conf {
+ Some(_) => errors.push(conf_error(concat!(
+ "duplicate field `", stringify!($new_conf),
+ "` (provided as `", stringify!($name), "`)"
+ ))),
+ None => $new_conf = $name.clone(),
+ })?
+ },
}
}
})*
}
}
let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* };
- Ok(TryConf { conf, errors })
+ Ok(TryConf { conf, errors, warnings })
}
}
///
/// The minimum rust version that the project supports
(msrv: Option<String> = None),
- /// Lint: BLACKLISTED_NAME.
+ /// DEPRECATED LINT: BLACKLISTED_NAME.
///
- /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses. The value
- /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
- /// default configuration of Clippy. By default any configuraction will replace the default value.
- (blacklisted_names: Vec<String> = super::DEFAULT_BLACKLISTED_NAMES.iter().map(ToString::to_string).collect()),
+ /// Use the Disallowed Names lint instead
+ #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)]
+ (blacklisted_names: Vec<String> = Vec::new()),
/// Lint: COGNITIVE_COMPLEXITY.
///
/// The maximum cognitive complexity a function can have
/// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
///
/// Use the Cognitive Complexity lint instead.
- #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")]
- (cyclomatic_complexity_threshold: Option<u64> = None),
+ #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
+ (cyclomatic_complexity_threshold: u64 = 25),
+ /// Lint: DISALLOWED_NAMES.
+ ///
+ /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
+ /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
+ /// default configuration of Clippy. By default any configuration will replace the default value.
+ (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
/// Lint: DOC_MARKDOWN.
///
/// The list of words this lint should not consider as identifiers needing ticks. The value
match toml::from_str::<TryConf>(&content) {
Ok(mut conf) => {
extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
- extend_vec_if_indicator_present(&mut conf.conf.blacklisted_names, DEFAULT_BLACKLISTED_NAMES);
+ extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
conf
},
cx,
};
let body_id = cx.tcx.hir().body_owned_by(
- impl_item_refs
- .iter()
- .find(|iiref| iiref.ident.as_str() == "get_lints")
- .expect("LintPass needs to implement get_lints")
- .id
- .hir_id(),
+ cx.tcx.hir().local_def_id(
+ impl_item_refs
+ .iter()
+ .find(|iiref| iiref.ident.as_str() == "get_lints")
+ .expect("LintPass needs to implement get_lints")
+ .id
+ .hir_id(),
+ ),
);
collector.visit_expr(&cx.tcx.hir().body(body_id).value);
}
item.span,
"this item has an invalid `clippy::version` attribute",
None,
- "please use a valid sematic version, see `doc/adding_lints.md`",
+ "please use a valid semantic version, see `doc/adding_lints.md`",
);
}
} else {
if_chain! {
// item validation
if is_lint_ref_type(cx, ty);
- // blacklist check
+ // disallow check
let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
// metadata extraction
if_chain! {
if is_deprecated_lint(cx, ty);
- // blacklist check
+ // disallow check
let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
// Metadata the little we can get from a deprecated lint
fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
if_chain! {
- if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind;
+ if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind;
if method_name.ident.as_str() == "read_to_end";
- if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
- let ty = cx.typeck_results().expr_ty(&exprs[0]);
+ if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind;
+ let ty = cx.typeck_results().expr_ty(recv);
if match_type(cx, ty, &paths::FILE);
then {
return true
};
match arg.position {
- ArgumentIs(n, _) | ArgumentImplicitlyIs(n) => {
+ ArgumentIs(n) | ArgumentImplicitlyIs(n) => {
if self.unnamed.len() <= n {
// Use a dummy span to mark all unseen arguments.
self.unnamed.resize_with(n, || vec![DUMMY_SP]);
}
}
},
- ArgumentNamed(n, _) => {
+ ArgumentNamed(n) => {
let n = Symbol::intern(n);
if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
match x.1.as_slice() {
[package]
name = "clippy_utils"
-version = "0.1.64"
+version = "0.1.65"
edition = "2021"
publish = false
(Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
(Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
(Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
- (MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
+ (MethodCall(lc, ls, la, _), MethodCall(rc, rs, ra, _)) => {
+ eq_path_seg(lc, rc) && eq_expr(ls, rs) && over(la, ra, |l, r| eq_expr(l, r))
+ },
(Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr),
(Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r),
(Lit(l), Lit(r)) => l.kind == r.kind,
--- /dev/null
+//! This module handles checking if the span given is from a proc-macro or not.
+//!
+//! Proc-macros are capable of setting the span of every token they output to a few possible spans.
+//! This includes spans we can detect easily as coming from a proc-macro (e.g. the call site
+//! or the def site), and spans we can't easily detect as such (e.g. the span of any token
+//! passed into the proc macro). This capability means proc-macros are capable of generating code
+//! with a span that looks like it was written by the user, but which should not be linted by clippy
+//! as it was generated by an external macro.
+//!
+//! That brings us to this module. The current approach is to determine a small bit of text which
+//! must exist at both the start and the end of an item (e.g. an expression or a path) assuming the
+//! code was written, and check if the span contains that text. Note this will only work correctly
+//! if the span is not from a `macro_rules` based macro.
+
+use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy};
+use rustc_hir::{
+ intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId,
+ Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, Node, QPath, TraitItem,
+ TraitItemKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
+};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
+use rustc_span::{Span, Symbol};
+use rustc_target::spec::abi::Abi;
+
+/// The search pattern to look for. Used by `span_matches_pat`
+#[derive(Clone, Copy)]
+pub enum Pat {
+ /// A single string.
+ Str(&'static str),
+ /// Any of the given strings.
+ MultiStr(&'static [&'static str]),
+ /// The string representation of the symbol.
+ Sym(Symbol),
+ /// Any decimal or hexadecimal digit depending on the location.
+ Num,
+}
+
+/// Checks if the start and the end of the span's text matches the patterns. This will return false
+/// if the span crosses multiple files or if source is not available.
+fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> bool {
+ let pos = sess.source_map().lookup_byte_offset(span.lo());
+ let Some(ref src) = pos.sf.src else {
+ return false;
+ };
+ let end = span.hi() - pos.sf.start_pos;
+ src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| {
+ // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas.
+ let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '(');
+ let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ',');
+ (match start_pat {
+ Pat::Str(text) => start_str.starts_with(text),
+ Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
+ Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
+ Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
+ } && match end_pat {
+ Pat::Str(text) => end_str.ends_with(text),
+ Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)),
+ Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
+ Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit),
+ })
+ })
+}
+
+/// Get the search patterns to use for the given literal
+fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) {
+ match lit {
+ LitKind::Str(_, StrStyle::Cooked) => (Pat::Str("\""), Pat::Str("\"")),
+ LitKind::Str(_, StrStyle::Raw(0)) => (Pat::Str("r"), Pat::Str("\"")),
+ LitKind::Str(_, StrStyle::Raw(_)) => (Pat::Str("r#"), Pat::Str("#")),
+ LitKind::ByteStr(_) => (Pat::Str("b\""), Pat::Str("\"")),
+ LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")),
+ LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")),
+ LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")),
+ LitKind::Int(_, LitIntType::Unsigned(UintTy::Usize)) => (Pat::Num, Pat::Str("usize")),
+ LitKind::Int(..) => (Pat::Num, Pat::Num),
+ LitKind::Float(..) => (Pat::Num, Pat::Str("")),
+ LitKind::Bool(true) => (Pat::Str("true"), Pat::Str("true")),
+ LitKind::Bool(false) => (Pat::Str("false"), Pat::Str("false")),
+ _ => (Pat::Str(""), Pat::Str("")),
+ }
+}
+
+/// Get the search patterns to use for the given path
+fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
+ match path {
+ QPath::Resolved(ty, path) => {
+ let start = if ty.is_some() {
+ Pat::Str("<")
+ } else {
+ path.segments
+ .first()
+ .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name))
+ };
+ let end = path.segments.last().map_or(Pat::Str(""), |seg| {
+ if seg.args.is_some() {
+ Pat::Str(">")
+ } else {
+ Pat::Sym(seg.ident.name)
+ }
+ });
+ (start, end)
+ },
+ QPath::TypeRelative(_, name) => (Pat::Str(""), Pat::Sym(name.ident.name)),
+ QPath::LangItem(..) => (Pat::Str(""), Pat::Str("")),
+ }
+}
+
+/// Get the search patterns to use for the given expression
+fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
+ match e.kind {
+ ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1),
+ ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")),
+ ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
+ ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
+ ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
+ ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
+ ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
+ ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
+ ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
+ ExprKind::Call(first, [.., last])
+ | ExprKind::MethodCall(_, [first, .., last], _)
+ | ExprKind::Binary(_, first, last)
+ | ExprKind::Tup([first, .., last])
+ | ExprKind::Assign(first, last, _)
+ | ExprKind::AssignOp(_, first, last) => (expr_search_pat(tcx, first).0, expr_search_pat(tcx, last).1),
+ ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat(tcx, e),
+ ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("")),
+ ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat(tcx, let_expr.init).1),
+ ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")),
+ ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")),
+ ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")),
+ ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")),
+ ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => {
+ (Pat::Str("for"), Pat::Str("}"))
+ },
+ ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")),
+ ExprKind::Match(e, _, MatchSource::TryDesugar) => (expr_search_pat(tcx, e).0, Pat::Str("?")),
+ ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => {
+ (expr_search_pat(tcx, e).0, Pat::Str("await"))
+ },
+ ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, &tcx.hir().body(body).value).1),
+ ExprKind::Block(
+ Block {
+ rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+ ..
+ },
+ None,
+ ) => (Pat::Str("unsafe"), Pat::Str("}")),
+ ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")),
+ ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)),
+ ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")),
+ ExprKind::Path(ref path) => qpath_search_pat(path),
+ ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1),
+ ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")),
+ ExprKind::Break(Destination { label: Some(name), .. }, None) => (Pat::Str("break"), Pat::Sym(name.ident.name)),
+ ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat(tcx, e).1),
+ ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")),
+ ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)),
+ ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")),
+ ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat(tcx, e).1),
+ ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")),
+ ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1),
+ _ => (Pat::Str(""), Pat::Str("")),
+ }
+}
+
+fn fn_header_search_pat(header: FnHeader) -> Pat {
+ if header.is_async() {
+ Pat::Str("async")
+ } else if header.is_const() {
+ Pat::Str("const")
+ } else if header.is_unsafe() {
+ Pat::Str("unsafe")
+ } else if header.abi != Abi::Rust {
+ Pat::Str("extern")
+ } else {
+ Pat::MultiStr(&["fn", "extern"])
+ }
+}
+
+fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
+ let (start_pat, end_pat) = match &item.kind {
+ ItemKind::ExternCrate(_) => (Pat::Str("extern"), Pat::Str(";")),
+ ItemKind::Static(..) => (Pat::Str("static"), Pat::Str(";")),
+ ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+ ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+ ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")),
+ ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")),
+ ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")),
+ ItemKind::Struct(VariantData::Struct(..), _) => (Pat::Str("struct"), Pat::Str("}")),
+ ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
+ ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
+ ItemKind::Trait(_, Unsafety::Unsafe, ..)
+ | ItemKind::Impl(Impl {
+ unsafety: Unsafety::Unsafe,
+ ..
+ }) => (Pat::Str("unsafe"), Pat::Str("}")),
+ ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
+ ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
+ ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")),
+ _ => return (Pat::Str(""), Pat::Str("")),
+ };
+ if item.vis_span.is_empty() {
+ (start_pat, end_pat)
+ } else {
+ (Pat::Str("pub"), end_pat)
+ }
+}
+
+fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) {
+ match &item.kind {
+ TraitItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+ TraitItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")),
+ TraitItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+ }
+}
+
+fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) {
+ let (start_pat, end_pat) = match &item.kind {
+ ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+ ImplItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")),
+ ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+ };
+ if item.vis_span.is_empty() {
+ (start_pat, end_pat)
+ } else {
+ (Pat::Str("pub"), end_pat)
+ }
+}
+
+fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) {
+ if def.vis_span.is_empty() {
+ if def.is_positional() {
+ (Pat::Str(""), Pat::Str(""))
+ } else {
+ (Pat::Sym(def.ident.name), Pat::Str(""))
+ }
+ } else {
+ (Pat::Str("pub"), Pat::Str(""))
+ }
+}
+
+fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) {
+ match v.data {
+ VariantData::Struct(..) => (Pat::Sym(v.ident.name), Pat::Str("}")),
+ VariantData::Tuple(..) => (Pat::Sym(v.ident.name), Pat::Str("")),
+ VariantData::Unit(..) => (Pat::Sym(v.ident.name), Pat::Sym(v.ident.name)),
+ }
+}
+
+fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) {
+ let (start_pat, end_pat) = match kind {
+ FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")),
+ FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")),
+ FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1),
+ };
+ let start_pat = match tcx.hir().get(hir_id) {
+ Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => {
+ if vis_span.is_empty() {
+ start_pat
+ } else {
+ Pat::Str("pub")
+ }
+ },
+ Node::TraitItem(_) => start_pat,
+ _ => Pat::Str(""),
+ };
+ (start_pat, end_pat)
+}
+
+pub trait WithSearchPat {
+ type Context: LintContext;
+ fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat);
+ fn span(&self) -> Span;
+}
+macro_rules! impl_with_search_pat {
+ ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => {
+ impl<'cx> WithSearchPat for $ty<'cx> {
+ type Context = $cx<'cx>;
+ #[allow(unused_variables)]
+ fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
+ $(let $tcx = cx.tcx;)?
+ $fn($($tcx,)? self)
+ }
+ fn span(&self) -> Span {
+ self.span
+ }
+ }
+ };
+}
+impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx));
+impl_with_search_pat!(LateContext: Item with item_search_pat);
+impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat);
+impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat);
+impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat);
+impl_with_search_pat!(LateContext: Variant with variant_search_pat);
+
+impl<'cx> WithSearchPat for (&FnKind<'cx>, &Body<'cx>, HirId, Span) {
+ type Context = LateContext<'cx>;
+
+ fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
+ fn_kind_pat(cx.tcx, self.0, self.1, self.2)
+ }
+
+ fn span(&self) -> Span {
+ self.3
+ }
+}
+
+/// Checks if the item likely came from a proc-macro.
+///
+/// This should be called after `in_external_macro` and the initial pattern matching of the ast as
+/// it is significantly slower than both of those.
+pub fn is_from_proc_macro<T: WithSearchPat>(cx: &T::Context, item: &T) -> bool {
+ let (start_pat, end_pat) = item.search_pat(cx);
+ !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat)
+}
+
+/// Checks if the span actually refers to a match expression
+pub fn is_span_match(cx: &impl LintContext, span: Span) -> bool {
+ span_matches_pat(cx.sess(), span, Pat::Str("match"), Pat::Str("}"))
+}
+
+/// Checks if the span actually refers to an if expression
+pub fn is_span_if(cx: &impl LintContext, span: Span) -> bool {
+ span_matches_pat(cx.sess(), span, Pat::Str("if"), Pat::Str("}"))
+}
let mut left_pos = 0;
let left = tokenize(&left)
.map(|t| {
- let end = left_pos + t.len;
+ let end = left_pos + t.len as usize;
let s = &left[left_pos..end];
left_pos = end;
(t, s)
let mut right_pos = 0;
let right = tokenize(&right)
.map(|t| {
- let end = right_pos + t.len;
+ let end = right_pos + t.len as usize;
let s = &right[right_pos..end];
right_pos = end;
(t, s)
pub mod ast_utils;
pub mod attrs;
+mod check_proc_macro;
pub mod comparisons;
pub mod consts;
pub mod diagnostics;
pub mod visitors;
pub use self::attrs::*;
+pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
pub use self::hir_utils::{
both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
};
fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) {
debug_assert!(lit_kind.is_numeric());
- lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| {
- let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length);
- (unsuffixed, Some(suffix))
- })
+ lit_suffix_length(lit_kind)
+ .and_then(|suffix_length| src.len().checked_sub(suffix_length))
+ .map_or((src, None), |split_pos| {
+ let (unsuffixed, suffix) = src.split_at(split_pos);
+ (unsuffixed, Some(suffix))
+ })
}
fn lit_suffix_length(lit_kind: &LitKind) -> Option<usize> {
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
+pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
+pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext};
use std::borrow::Cow;
-/// Checks if the span starts with the given text. This will return false if the span crosses
-/// multiple files or if source is not available.
-///
-/// This is used to check for proc macros giving unhelpful spans to things.
-pub fn span_starts_with<T: LintContext>(cx: &T, span: Span, text: &str) -> bool {
- fn helper(sm: &SourceMap, span: Span, text: &str) -> bool {
- let pos = sm.lookup_byte_offset(span.lo());
- let Some(ref src) = pos.sf.src else {
- return false;
- };
- let end = span.hi() - pos.sf.start_pos;
- src.get(pos.pos.0 as usize..end.0 as usize)
- // Expression spans can include wrapping parenthesis. Remove them first.
- .map_or(false, |s| s.trim_start_matches('(').starts_with(text))
- }
- helper(cx.sess().source_map(), span, text)
-}
-
/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
/// Also takes an `Option<String>` which can be put inside the braces.
pub fn expr_block<'a, T: LintContext>(
Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self)))
}
+ /// Convenience method to prefix the expression with the `async` keyword.
+ /// Can be used after `blockify` to create an async block.
+ pub fn asyncify(self) -> Sugg<'static> {
+ Sugg::NonParen(Cow::Owned(format!("async {}", self)))
+ }
+
/// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>`
/// suggestion.
pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
pub enum ExprFnSig<'tcx> {
Sig(Binder<'tcx, FnSig<'tcx>>, Option<DefId>),
Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>),
- Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>),
+ Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>, Option<DefId>),
}
impl<'tcx> ExprFnSig<'tcx> {
/// Gets the argument type at the given offset. This will return `None` when the index is out of
}
},
Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])),
- Self::Trait(inputs, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
+ Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
}
}
decl.and_then(|decl| decl.inputs.get(i)),
sig.input(0).map_bound(|ty| ty.tuple_fields()[i]),
)),
- Self::Trait(inputs, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
+ Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
}
}
pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> {
match self {
Self::Sig(sig, _) | Self::Closure(_, sig) => Some(sig.output()),
- Self::Trait(_, output) => output,
+ Self::Trait(_, output, _) => output,
}
}
pub fn predicates_id(&self) -> Option<DefId> {
- if let ExprFnSig::Sig(_, id) = *self { id } else { None }
+ if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self {
+ id
+ } else {
+ None
+ }
}
}
}
}
-fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
+/// If the type is function like, get the signature for it.
+pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
if ty.is_box() {
return ty_sig(cx, ty.boxed_ty());
}
Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
},
ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
- ty::Opaque(id, _) => ty_sig(cx, cx.tcx.type_of(id)),
+ ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)),
ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
ty::Dynamic(bounds, _) => {
let lang_items = cx.tcx.lang_items();
.projection_bounds()
.find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
.map(|p| p.map_bound(|p| p.term.ty().unwrap()));
- Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output))
+ Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
},
_ => None,
}
},
ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
- _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty)),
+ _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
},
- ty::Param(_) => sig_from_bounds(cx, ty),
+ ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None),
_ => None,
}
}
-fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
+fn sig_from_bounds<'tcx>(
+ cx: &LateContext<'tcx>,
+ ty: Ty<'tcx>,
+ predicates: &'tcx [Predicate<'tcx>],
+ predicates_id: Option<DefId>,
+) -> Option<ExprFnSig<'tcx>> {
let mut inputs = None;
let mut output = None;
let lang_items = cx.tcx.lang_items();
- for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) {
+ for pred in predicates {
match pred.kind().skip_binder() {
PredicateKind::Trait(p)
if (lang_items.fn_trait() == Some(p.def_id())
|| lang_items.fn_once_trait() == Some(p.def_id()))
&& p.self_ty() == ty =>
{
- if inputs.is_some() {
+ let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
+ if inputs.map_or(false, |inputs| i != inputs) {
// Multiple different fn trait impls. Is this even allowed?
return None;
}
- inputs = Some(pred.kind().rebind(p.trait_ref.substs.type_at(1)));
+ inputs = Some(i);
},
PredicateKind::Projection(p)
if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
}
}
- inputs.map(|ty| ExprFnSig::Trait(ty, output))
+ inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
}
fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
|| lang_items.fn_mut_trait() == Some(p.def_id())
|| lang_items.fn_once_trait() == Some(p.def_id())) =>
{
- if inputs.is_some() {
+ let i = pred
+ .map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
+ .subst(cx.tcx, ty.substs);
+
+ if inputs.map_or(false, |inputs| inputs != i) {
// Multiple different fn trait impls. Is this even allowed?
return None;
}
- inputs = Some(
- pred.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
- .subst(cx.tcx, ty.substs),
- );
+ inputs = Some(i);
},
PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => {
if output.is_some() {
}
}
- inputs.map(|ty| ExprFnSig::Trait(ty, output))
+ inputs.map(|ty| ExprFnSig::Trait(ty, output, None))
}
#[derive(Clone, Copy)]
[toolchain]
-channel = "nightly-2022-07-28"
+channel = "nightly-2022-08-11"
components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
- = help: please use a valid sematic version, see `doc/adding_lints.md`
+ = help: please use a valid semantic version, see `doc/adding_lints.md`
= note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this item has an invalid `clippy::version` attribute
LL | | }
| |_^
|
- = help: please use a valid sematic version, see `doc/adding_lints.md`
+ = help: please use a valid semantic version, see `doc/adding_lints.md`
= note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this lint is missing the `clippy::version` attribute or version value
-blacklisted-names = 42
+disallowed-names = 42
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `blacklisted-names`
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `disallowed-names`
error: aborting due to previous error
+++ /dev/null
-#[warn(clippy::blacklisted_name)]
-
-fn main() {
- // `foo` is part of the default configuration
- let foo = "bar";
- // `ducks` was unrightfully blacklisted
- let ducks = ["quack", "quack"];
- // `fox` is okay
- let fox = ["what", "does", "the", "fox", "say", "?"];
-}
+++ /dev/null
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_names.rs:5:9
- |
-LL | let foo = "bar";
- | ^^^
- |
- = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `ducks`
- --> $DIR/blacklisted_names.rs:7:9
- |
-LL | let ducks = ["quack", "quack"];
- | ^^^^^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-blacklisted-names = ["ducks", ".."]
+++ /dev/null
-#[warn(clippy::blacklisted_name)]
-
-fn main() {
- // `foo` is part of the default configuration
- let foo = "bar";
- // `ducks` was unrightfully blacklisted
- let ducks = ["quack", "quack"];
- // `fox` is okay
- let fox = ["what", "does", "the", "fox", "say", "?"];
-}
+++ /dev/null
-error: use of a blacklisted/placeholder name `ducks`
- --> $DIR/blacklisted_names.rs:7:9
- |
-LL | let ducks = ["quack", "quack"];
- | ^^^^^
- |
- = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: aborting due to previous error
-
+++ /dev/null
-blacklisted-names = ["ducks"]
-# that one is an error
-cyclomatic-complexity-threshold = 42
+# Expect errors from these deprecated configs
+cyclomatic-complexity-threshold = 2
+blacklisted-names = [ "..", "wibble" ]
# that one is white-listed
[third-party]
fn main() {}
+
+#[warn(clippy::cognitive_complexity)]
+fn cognitive_complexity() {
+ let x = vec![1, 2, 3];
+ for i in x {
+ if i == 1 {
+ println!("{}", i);
+ }
+ }
+}
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
-error: aborting due to previous error
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `blacklisted-names`. Please use `disallowed-names` instead
+
+error: the function has a cognitive complexity of (3/2)
+ --> $DIR/conf_deprecated_key.rs:4:4
+ |
+LL | fn cognitive_complexity() {
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
+ = help: you could split it up into multiple smaller functions
+
+error: aborting due to previous error; 2 warnings emitted
--- /dev/null
+disallowed-names = ["ducks", ".."]
--- /dev/null
+#[warn(clippy::disallowed_names)]
+
+fn main() {
+ // `foo` is part of the default configuration
+ let foo = "bar";
+ // `ducks` was unrightfully disallowed
+ let ducks = ["quack", "quack"];
+ // `fox` is okay
+ let fox = ["what", "does", "the", "fox", "say", "?"];
+}
--- /dev/null
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:5:9
+ |
+LL | let foo = "bar";
+ | ^^^
+ |
+ = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `ducks`
+ --> $DIR/disallowed_names.rs:7:9
+ |
+LL | let ducks = ["quack", "quack"];
+ | ^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+disallowed-names = ["ducks"]
--- /dev/null
+#[warn(clippy::disallowed_names)]
+
+fn main() {
+ // `foo` is part of the default configuration
+ let foo = "bar";
+ // `ducks` was unrightfully disallowed
+ let ducks = ["quack", "quack"];
+ // `fox` is okay
+ let fox = ["what", "does", "the", "fox", "say", "?"];
+}
--- /dev/null
+error: use of a disallowed/placeholder name `ducks`
+ --> $DIR/disallowed_names.rs:7:9
+ |
+LL | let ducks = ["quack", "quack"];
+ | ^^^^^
+ |
+ = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: aborting due to previous error
+
--- /dev/null
+cognitive-complexity-threshold = 2
+# This is the deprecated name for the same key
+cyclomatic-complexity-threshold = 3
+# Check we get duplication warning regardless of order
+cognitive-complexity-threshold = 4
--- /dev/null
+fn main() {}
--- /dev/null
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`)
+
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive-complexity-threshold`
+
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
| ^^^^^^^^^^^^^^
|
= note: `-D clippy::expect-used` implied by `-D warnings`
- = help: if this value is an `None`, it will panic
+ = help: if this value is `None`, it will panic
error: used `expect()` on `a Result` value
--> $DIR/expect_used.rs:11:13
+++ /dev/null
-blacklisted-names = ["toto", "tata", "titi"]
+++ /dev/null
-#![allow(dead_code)]
-#![allow(clippy::single_match)]
-#![allow(unused_variables)]
-#![warn(clippy::blacklisted_name)]
-
-fn test(toto: ()) {}
-
-fn main() {
- let toto = 42;
- let tata = 42;
- let titi = 42;
-
- let tatab = 42;
- let tatatataic = 42;
-
- match (42, Some(1337), Some(0)) {
- (toto, Some(tata), titi @ Some(_)) => (),
- _ => (),
- }
-}
+++ /dev/null
-error: use of a blacklisted/placeholder name `toto`
- --> $DIR/conf_french_blacklisted_name.rs:6:9
- |
-LL | fn test(toto: ()) {}
- | ^^^^
- |
- = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `toto`
- --> $DIR/conf_french_blacklisted_name.rs:9:9
- |
-LL | let toto = 42;
- | ^^^^
-
-error: use of a blacklisted/placeholder name `tata`
- --> $DIR/conf_french_blacklisted_name.rs:10:9
- |
-LL | let tata = 42;
- | ^^^^
-
-error: use of a blacklisted/placeholder name `titi`
- --> $DIR/conf_french_blacklisted_name.rs:11:9
- |
-LL | let titi = 42;
- | ^^^^
-
-error: use of a blacklisted/placeholder name `toto`
- --> $DIR/conf_french_blacklisted_name.rs:17:10
- |
-LL | (toto, Some(tata), titi @ Some(_)) => (),
- | ^^^^
-
-error: use of a blacklisted/placeholder name `tata`
- --> $DIR/conf_french_blacklisted_name.rs:17:21
- |
-LL | (toto, Some(tata), titi @ Some(_)) => (),
- | ^^^^
-
-error: use of a blacklisted/placeholder name `titi`
- --> $DIR/conf_french_blacklisted_name.rs:17:28
- |
-LL | (toto, Some(tata), titi @ Some(_)) => (),
- | ^^^^
-
-error: aborting due to 7 previous errors
-
--- /dev/null
+disallowed-names = ["toto", "tata", "titi"]
--- /dev/null
+#![allow(dead_code)]
+#![allow(clippy::single_match)]
+#![allow(unused_variables)]
+#![warn(clippy::disallowed_names)]
+
+fn test(toto: ()) {}
+
+fn main() {
+ let toto = 42;
+ let tata = 42;
+ let titi = 42;
+
+ let tatab = 42;
+ let tatatataic = 42;
+
+ match (42, Some(1337), Some(0)) {
+ (toto, Some(tata), titi @ Some(_)) => (),
+ _ => (),
+ }
+}
--- /dev/null
+error: use of a disallowed/placeholder name `toto`
+ --> $DIR/conf_french_disallowed_name.rs:6:9
+ |
+LL | fn test(toto: ()) {}
+ | ^^^^
+ |
+ = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `toto`
+ --> $DIR/conf_french_disallowed_name.rs:9:9
+ |
+LL | let toto = 42;
+ | ^^^^
+
+error: use of a disallowed/placeholder name `tata`
+ --> $DIR/conf_french_disallowed_name.rs:10:9
+ |
+LL | let tata = 42;
+ | ^^^^
+
+error: use of a disallowed/placeholder name `titi`
+ --> $DIR/conf_french_disallowed_name.rs:11:9
+ |
+LL | let titi = 42;
+ | ^^^^
+
+error: use of a disallowed/placeholder name `toto`
+ --> $DIR/conf_french_disallowed_name.rs:17:10
+ |
+LL | (toto, Some(tata), titi @ Some(_)) => (),
+ | ^^^^
+
+error: use of a disallowed/placeholder name `tata`
+ --> $DIR/conf_french_disallowed_name.rs:17:21
+ |
+LL | (toto, Some(tata), titi @ Some(_)) => (),
+ | ^^^^
+
+error: use of a disallowed/placeholder name `titi`
+ --> $DIR/conf_french_disallowed_name.rs:17:28
+ |
+LL | (toto, Some(tata), titi @ Some(_)) => (),
+ | ^^^^
+
+error: aborting due to 7 previous errors
+
cognitive-complexity-threshold
cyclomatic-complexity-threshold
disallowed-methods
+ disallowed-names
disallowed-types
doc-valid-idents
enable-raw-pointer-heuristic-for-send
let r: Result<Foo, Foo> = Ok(Foo);
assert!(r.is_ok());
+ // test ok with some messages
+ let r: Result<Foo, DebugFoo> = Ok(Foo);
+ assert!(r.is_ok(), "oops");
+
+ // test ok with unit error
+ let r: Result<Foo, ()> = Ok(Foo);
+ assert!(r.is_ok());
+
// test temporary ok
fn get_ok() -> Result<Foo, DebugFoo> {
Ok(Foo)
let r: Result<Foo, Foo> = Ok(Foo);
assert!(r.is_ok());
+ // test ok with some messages
+ let r: Result<Foo, DebugFoo> = Ok(Foo);
+ assert!(r.is_ok(), "oops");
+
+ // test ok with unit error
+ let r: Result<Foo, ()> = Ok(Foo);
+ assert!(r.is_ok());
+
// test temporary ok
fn get_ok() -> Result<Foo, DebugFoo> {
Ok(Foo)
= note: `-D clippy::assertions-on-result-states` implied by `-D warnings`
error: called `assert!` with `Result::is_ok`
- --> $DIR/assertions_on_result_states.rs:34:5
+ --> $DIR/assertions_on_result_states.rs:42:5
|
LL | assert!(get_ok().is_ok());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()`
error: called `assert!` with `Result::is_ok`
- --> $DIR/assertions_on_result_states.rs:37:5
+ --> $DIR/assertions_on_result_states.rs:45:5
|
LL | assert!(get_ok_macro!().is_ok());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()`
error: called `assert!` with `Result::is_ok`
- --> $DIR/assertions_on_result_states.rs:50:5
+ --> $DIR/assertions_on_result_states.rs:58:5
|
LL | assert!(r.is_ok());
| ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()`
error: called `assert!` with `Result::is_ok`
- --> $DIR/assertions_on_result_states.rs:56:9
+ --> $DIR/assertions_on_result_states.rs:64:9
|
LL | assert!(r.is_ok());
| ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()`
error: called `assert!` with `Result::is_err`
- --> $DIR/assertions_on_result_states.rs:64:5
+ --> $DIR/assertions_on_result_states.rs:72:5
|
LL | assert!(r.is_err());
| ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()`
+++ /dev/null
-#![allow(
- dead_code,
- clippy::similar_names,
- clippy::single_match,
- clippy::toplevel_ref_arg,
- unused_mut,
- unused_variables
-)]
-#![warn(clippy::blacklisted_name)]
-
-fn test(foo: ()) {}
-
-fn main() {
- let foo = 42;
- let baz = 42;
- let quux = 42;
- // Unlike these others, `bar` is actually considered an acceptable name.
- // Among many other legitimate uses, bar commonly refers to a period of time in music.
- // See https://github.com/rust-lang/rust-clippy/issues/5225.
- let bar = 42;
-
- let food = 42;
- let foodstuffs = 42;
- let bazaar = 42;
-
- match (42, Some(1337), Some(0)) {
- (foo, Some(baz), quux @ Some(_)) => (),
- _ => (),
- }
-}
-
-fn issue_1647(mut foo: u8) {
- let mut baz = 0;
- if let Some(mut quux) = Some(42) {}
-}
-
-fn issue_1647_ref() {
- let ref baz = 0;
- if let Some(ref quux) = Some(42) {}
-}
-
-fn issue_1647_ref_mut() {
- let ref mut baz = 0;
- if let Some(ref mut quux) = Some(42) {}
-}
-
-mod tests {
- fn issue_7305() {
- // `blacklisted_name` lint should not be triggered inside of the test code.
- let foo = 0;
-
- // Check that even in nested functions warning is still not triggered.
- fn nested() {
- let foo = 0;
- }
- }
-}
+++ /dev/null
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:11:9
- |
-LL | fn test(foo: ()) {}
- | ^^^
- |
- = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:14:9
- |
-LL | let foo = 42;
- | ^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:15:9
- |
-LL | let baz = 42;
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:16:9
- |
-LL | let quux = 42;
- | ^^^^
-
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:27:10
- |
-LL | (foo, Some(baz), quux @ Some(_)) => (),
- | ^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:27:20
- |
-LL | (foo, Some(baz), quux @ Some(_)) => (),
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:27:26
- |
-LL | (foo, Some(baz), quux @ Some(_)) => (),
- | ^^^^
-
-error: use of a blacklisted/placeholder name `foo`
- --> $DIR/blacklisted_name.rs:32:19
- |
-LL | fn issue_1647(mut foo: u8) {
- | ^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:33:13
- |
-LL | let mut baz = 0;
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:34:21
- |
-LL | if let Some(mut quux) = Some(42) {}
- | ^^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:38:13
- |
-LL | let ref baz = 0;
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:39:21
- |
-LL | if let Some(ref quux) = Some(42) {}
- | ^^^^
-
-error: use of a blacklisted/placeholder name `baz`
- --> $DIR/blacklisted_name.rs:43:17
- |
-LL | let ref mut baz = 0;
- | ^^^
-
-error: use of a blacklisted/placeholder name `quux`
- --> $DIR/blacklisted_name.rs:44:25
- |
-LL | if let Some(ref mut quux) = Some(42) {}
- | ^^^^
-
-error: aborting due to 14 previous errors
-
#![deny(clippy::borrowed_box)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
#![allow(unused_variables)]
#![allow(dead_code)]
// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure.
#![allow(clippy::declare_interior_mutable_const)]
+#![allow(unused_tuple_struct_fields)]
use std::sync::atomic::AtomicUsize;
#![allow(
clippy::boxed_local,
clippy::needless_pass_by_value,
- clippy::blacklisted_name,
+ clippy::disallowed_names,
unused
)]
let _ = a.unsigned_abs() as u32;
let _ = a.unsigned_abs() as u64;
let _ = a.unsigned_abs() as u128;
+
+ let _ = (x as i64 - y as i64).unsigned_abs() as u32;
}
let _ = a.abs() as u32;
let _ = a.abs() as u64;
let _ = a.abs() as u128;
+
+ let _ = (x as i64 - y as i64).abs() as u32;
}
LL | let _ = a.abs() as u128;
| ^^^^^^^ help: replace with: `a.unsigned_abs()`
-error: aborting due to 16 previous errors
+error: casting the result of `i64::abs()` to u32
+ --> $DIR/cast_abs_to_unsigned.rs:30:13
+ |
+LL | let _ = (x as i64 - y as i64).abs() as u32;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()`
+
+error: aborting due to 17 previous errors
ch.is_ascii()
}
-fn clone_on_copy() {
+fn clone_on_copy() -> Option<(i32)> {
42;
vec![1].clone(); // ok, not a Copy type
// Issue #5436
let mut vec = Vec::new();
vec.push(42);
+
+ // Issue #9277
+ let opt: &Option<i32> = &None;
+ let value = (*opt)?; // operator precedence needed (*opt)?
+ None
}
ch.is_ascii()
}
-fn clone_on_copy() {
+fn clone_on_copy() -> Option<(i32)> {
42.clone();
vec![1].clone(); // ok, not a Copy type
// Issue #5436
let mut vec = Vec::new();
vec.push(42.clone());
+
+ // Issue #9277
+ let opt: &Option<i32> = &None;
+ let value = opt.clone()?; // operator precedence needed (*opt)?
+ None
}
LL | vec.push(42.clone());
| ^^^^^^^^^^ help: try removing the `clone` call: `42`
-error: aborting due to 8 previous errors
+error: using `clone` on type `std::option::Option<i32>` which implements the `Copy` trait
+ --> $DIR/clone_on_copy.rs:77:17
+ |
+LL | let value = opt.clone()?; // operator precedence needed (*opt)?
+ | ^^^^^^^^^^^ help: try dereferencing it: `(*opt)`
+
+error: aborting due to 9 previous errors
#![allow(
unused_variables,
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::needless_pass_by_value,
dead_code
)]
#![warn(clippy::all)]
-#![allow(clippy::blacklisted_name, clippy::equatable_if_let)]
+#![allow(clippy::disallowed_names, clippy::equatable_if_let)]
#![allow(unused)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/3462
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
pub fn foo(bar: *const u8) {
println!("{:#p}", bar);
-// ignore-windows
// ignore-macos
#![feature(no_core, lang_items, start)]
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/def_id_nocore.rs:28:19
+ --> $DIR/def_id_nocore.rs:27:19
|
LL | pub fn as_ref(self) -> &'static str {
| ^^^^
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![allow(unused_imports, dead_code)]
#![deny(clippy::default_trait_access)]
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
use std::default;
use std::default::Default as D2;
use std::string;
..Default::default()
};
+ let _s21: String = with_span!(s Default::default());
+
println!(
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![allow(unused_imports, dead_code)]
#![deny(clippy::default_trait_access)]
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
use std::default;
use std::default::Default as D2;
use std::string;
..Default::default()
};
+ let _s21: String = with_span!(s Default::default());
+
println!(
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
error: calling `std::string::String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:11:22
+ --> $DIR/default_trait_access.rs:15:22
|
LL | let s1: String = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
|
note: the lint level is defined here
- --> $DIR/default_trait_access.rs:4:9
+ --> $DIR/default_trait_access.rs:5:9
|
LL | #![deny(clippy::default_trait_access)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: calling `std::string::String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:15:22
+ --> $DIR/default_trait_access.rs:19:22
|
LL | let s3: String = D2::default();
| ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: calling `std::string::String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:17:22
+ --> $DIR/default_trait_access.rs:21:22
|
LL | let s4: String = std::default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: calling `std::string::String::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:21:22
+ --> $DIR/default_trait_access.rs:25:22
|
LL | let s6: String = default::Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
error: calling `GenericDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:31:46
+ --> $DIR/default_trait_access.rs:35:46
|
LL | let s11: GenericDerivedDefault<String> = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()`
error: calling `TupleDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:37:36
+ --> $DIR/default_trait_access.rs:41:36
|
LL | let s14: TupleDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
error: calling `ArrayDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:39:36
+ --> $DIR/default_trait_access.rs:43:36
|
LL | let s15: ArrayDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
error: calling `TupleStructDerivedDefault::default()` is more clear than this expression
- --> $DIR/default_trait_access.rs:43:42
+ --> $DIR/default_trait_access.rs:47:42
|
LL | let s17: TupleStructDerivedDefault = Default::default();
| ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`
--- /dev/null
+#![allow(
+ dead_code,
+ clippy::similar_names,
+ clippy::single_match,
+ clippy::toplevel_ref_arg,
+ unused_mut,
+ unused_variables
+)]
+#![warn(clippy::disallowed_names)]
+
+fn test(foo: ()) {}
+
+fn main() {
+ let foo = 42;
+ let baz = 42;
+ let quux = 42;
+ // Unlike these others, `bar` is actually considered an acceptable name.
+ // Among many other legitimate uses, bar commonly refers to a period of time in music.
+ // See https://github.com/rust-lang/rust-clippy/issues/5225.
+ let bar = 42;
+
+ let food = 42;
+ let foodstuffs = 42;
+ let bazaar = 42;
+
+ match (42, Some(1337), Some(0)) {
+ (foo, Some(baz), quux @ Some(_)) => (),
+ _ => (),
+ }
+}
+
+fn issue_1647(mut foo: u8) {
+ let mut baz = 0;
+ if let Some(mut quux) = Some(42) {}
+}
+
+fn issue_1647_ref() {
+ let ref baz = 0;
+ if let Some(ref quux) = Some(42) {}
+}
+
+fn issue_1647_ref_mut() {
+ let ref mut baz = 0;
+ if let Some(ref mut quux) = Some(42) {}
+}
+
+mod tests {
+ fn issue_7305() {
+ // `disallowed_names` lint should not be triggered inside of the test code.
+ let foo = 0;
+
+ // Check that even in nested functions warning is still not triggered.
+ fn nested() {
+ let foo = 0;
+ }
+ }
+}
--- /dev/null
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:11:9
+ |
+LL | fn test(foo: ()) {}
+ | ^^^
+ |
+ = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:14:9
+ |
+LL | let foo = 42;
+ | ^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:15:9
+ |
+LL | let baz = 42;
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:16:9
+ |
+LL | let quux = 42;
+ | ^^^^
+
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:27:10
+ |
+LL | (foo, Some(baz), quux @ Some(_)) => (),
+ | ^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:27:20
+ |
+LL | (foo, Some(baz), quux @ Some(_)) => (),
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:27:26
+ |
+LL | (foo, Some(baz), quux @ Some(_)) => (),
+ | ^^^^
+
+error: use of a disallowed/placeholder name `foo`
+ --> $DIR/disallowed_names.rs:32:19
+ |
+LL | fn issue_1647(mut foo: u8) {
+ | ^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:33:13
+ |
+LL | let mut baz = 0;
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:34:21
+ |
+LL | if let Some(mut quux) = Some(42) {}
+ | ^^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:38:13
+ |
+LL | let ref baz = 0;
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:39:21
+ |
+LL | if let Some(ref quux) = Some(42) {}
+ | ^^^^
+
+error: use of a disallowed/placeholder name `baz`
+ --> $DIR/disallowed_names.rs:43:17
+ |
+LL | let ref mut baz = 0;
+ | ^^^
+
+error: use of a disallowed/placeholder name `quux`
+ --> $DIR/disallowed_names.rs:44:25
+ |
+LL | if let Some(ref mut quux) = Some(42) {}
+ | ^^^^
+
+error: aborting due to 14 previous errors
+
#![warn(clippy::diverging_sub_expression)]
-#![allow(clippy::match_same_arms, clippy::logic_bug)]
+#![allow(clippy::match_same_arms, clippy::overly_complex_bool_expr)]
#[allow(clippy::empty_loop)]
fn diverge() -> ! {
loop {}
// compile-flags: -Clink-arg=-nostartfiles
// ignore-macos
-// ignore-windows
#![warn(clippy::empty_loop)]
#![feature(lang_items, start, libc)]
error: empty `loop {}` wastes CPU cycles
- --> $DIR/empty_loop_no_std.rs:14:5
+ --> $DIR/empty_loop_no_std.rs:13:5
|
LL | loop {}
| ^^^^^^^
= help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
error: empty `loop {}` wastes CPU cycles
- --> $DIR/empty_loop_no_std.rs:26:5
+ --> $DIR/empty_loop_no_std.rs:25:5
|
LL | loop {}
| ^^^^^^^
| ^^^^^^^^^^^^^^
|
= note: `-D clippy::expect-used` implied by `-D warnings`
- = help: if this value is an `None`, it will panic
+ = help: if this value is `None`, it will panic
error: used `expect()` on `a Result` value
--> $DIR/expect.rs:10:13
let _ = if true { 42 } else { 42 };
}
- #[expect(clippy::logic_bug)]
+ #[expect(clippy::overly_complex_bool_expr)]
fn burger() {
let a = false;
let b = true;
let _ = if true { 33 } else { 42 };
}
- #[expect(clippy::logic_bug)]
+ #[expect(clippy::overly_complex_bool_expr)]
fn burger() {
let a = false;
let b = true;
error: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:130:14
|
-LL | #[expect(clippy::logic_bug)]
- | ^^^^^^^^^^^^^^^^^
+LL | #[expect(clippy::overly_complex_bool_expr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors
// run-rustfix
+#![feature(closure_lifetime_binder)]
#![warn(clippy::explicit_auto_deref)]
#![allow(
dead_code,
let s = String::new();
let _: &str = &s;
+ let _: &str = &{ String::new() };
+ let _: &str = &mut { String::new() };
let _ = &*s; // Don't lint. Inferred type would change.
let _: &_ = &*s; // Don't lint. Inferred type would change.
let s = &"str";
let _ = || return *s;
let _ = || -> &'static str { return s };
+
+ struct X;
+ struct Y(X);
+ impl core::ops::Deref for Y {
+ type Target = X;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ let _: &X = &*{ Y(X) };
+ let _: &X = &*match 0 {
+ #[rustfmt::skip]
+ 0 => { Y(X) },
+ _ => panic!(),
+ };
+ let _: &X = &*if true { Y(X) } else { panic!() };
+
+ fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
+ x
+ }
+
+ let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
+ fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
+ &**x
+ }
+
+ let x = String::new();
+ let _: *const str = &*x;
+
+ struct S7([u32; 1]);
+ impl core::ops::Deref for S7 {
+ type Target = [u32; 1];
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ let x = S7([0]);
+ let _: &[u32] = &*x;
+
+ let c1 = |_: &Vec<&u32>| {};
+ let x = &&vec![&1u32];
+ c1(x);
+ let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
+ if b {
+ return x;
+ }
+ x
+ };
}
// run-rustfix
+#![feature(closure_lifetime_binder)]
#![warn(clippy::explicit_auto_deref)]
#![allow(
dead_code,
let s = String::new();
let _: &str = &*s;
+ let _: &str = &*{ String::new() };
+ let _: &str = &mut *{ String::new() };
let _ = &*s; // Don't lint. Inferred type would change.
let _: &_ = &*s; // Don't lint. Inferred type would change.
let s = &"str";
let _ = || return *s;
let _ = || -> &'static str { return *s };
+
+ struct X;
+ struct Y(X);
+ impl core::ops::Deref for Y {
+ type Target = X;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ let _: &X = &*{ Y(X) };
+ let _: &X = &*match 0 {
+ #[rustfmt::skip]
+ 0 => { Y(X) },
+ _ => panic!(),
+ };
+ let _: &X = &*if true { Y(X) } else { panic!() };
+
+ fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
+ &**x
+ }
+
+ let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
+ fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
+ &**x
+ }
+
+ let x = String::new();
+ let _: *const str = &*x;
+
+ struct S7([u32; 1]);
+ impl core::ops::Deref for S7 {
+ type Target = [u32; 1];
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ let x = S7([0]);
+ let _: &[u32] = &*x;
+
+ let c1 = |_: &Vec<&u32>| {};
+ let x = &&vec![&1u32];
+ c1(*x);
+ let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
+ if b {
+ return *x;
+ }
+ *x
+ };
}
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:69:20
+ --> $DIR/explicit_auto_deref.rs:70:19
|
LL | let _: &str = &*s;
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
|
= note: `-D clippy::explicit-auto-deref` implied by `-D warnings`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:73:12
+ --> $DIR/explicit_auto_deref.rs:71:19
+ |
+LL | let _: &str = &*{ String::new() };
+ | ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:72:19
+ |
+LL | let _: &str = &mut *{ String::new() };
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:76:11
|
LL | f_str(&*s);
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:77:14
+ --> $DIR/explicit_auto_deref.rs:80:13
|
LL | f_str_t(&*s, &*s); // Don't lint second param.
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:80:25
+ --> $DIR/explicit_auto_deref.rs:83:24
|
LL | let _: &Box<i32> = &**b;
- | ^^^ help: try this: `b`
+ | ^^^^ help: try this: `&b`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:86:8
+ --> $DIR/explicit_auto_deref.rs:89:7
|
LL | c(&*s);
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:92:9
+ --> $DIR/explicit_auto_deref.rs:95:9
|
LL | &**x
| ^^^^ help: try this: `x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:96:11
+ --> $DIR/explicit_auto_deref.rs:99:11
|
LL | { &**x }
| ^^^^ help: try this: `x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:100:9
+ --> $DIR/explicit_auto_deref.rs:103:9
|
LL | &**{ x }
| ^^^^^^^^ help: try this: `{ x }`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:104:9
+ --> $DIR/explicit_auto_deref.rs:107:9
|
LL | &***x
| ^^^^^ help: try this: `x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:121:13
+ --> $DIR/explicit_auto_deref.rs:124:12
|
LL | f1(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:122:13
+ --> $DIR/explicit_auto_deref.rs:125:12
|
LL | f2(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:123:13
+ --> $DIR/explicit_auto_deref.rs:126:12
|
LL | f3(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:124:28
+ --> $DIR/explicit_auto_deref.rs:127:27
|
LL | f4.callable_str()(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:125:13
+ --> $DIR/explicit_auto_deref.rs:128:12
|
LL | f5(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:126:13
+ --> $DIR/explicit_auto_deref.rs:129:12
|
LL | f6(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:127:28
+ --> $DIR/explicit_auto_deref.rs:130:27
|
LL | f7.callable_str()(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:128:26
+ --> $DIR/explicit_auto_deref.rs:131:25
|
LL | f8.callable_t()(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:129:13
+ --> $DIR/explicit_auto_deref.rs:132:12
|
LL | f9(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:130:14
+ --> $DIR/explicit_auto_deref.rs:133:13
|
LL | f10(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:131:27
+ --> $DIR/explicit_auto_deref.rs:134:26
|
LL | f11.callable_t()(&*x);
- | ^^ help: try this: `x`
+ | ^^^ help: try this: `&x`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:135:17
+ --> $DIR/explicit_auto_deref.rs:138:16
|
LL | let _ = S1(&*s);
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:140:22
+ --> $DIR/explicit_auto_deref.rs:143:21
|
LL | let _ = S2 { s: &*s };
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:156:30
+ --> $DIR/explicit_auto_deref.rs:159:30
|
LL | let _ = Self::S1(&**s);
| ^^^^ help: try this: `s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:157:35
+ --> $DIR/explicit_auto_deref.rs:160:35
|
LL | let _ = Self::S2 { s: &**s };
| ^^^^ help: try this: `s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:160:21
+ --> $DIR/explicit_auto_deref.rs:163:20
|
LL | let _ = E1::S1(&*s);
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:161:26
+ --> $DIR/explicit_auto_deref.rs:164:25
|
LL | let _ = E1::S2 { s: &*s };
- | ^^ help: try this: `s`
+ | ^^^ help: try this: `&s`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:179:13
+ --> $DIR/explicit_auto_deref.rs:182:13
|
LL | let _ = (*b).foo;
| ^^^^ help: try this: `b`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:180:13
+ --> $DIR/explicit_auto_deref.rs:183:13
|
LL | let _ = (**b).foo;
| ^^^^^ help: try this: `b`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:195:19
+ --> $DIR/explicit_auto_deref.rs:198:19
|
LL | let _ = f_str(*ref_str);
| ^^^^^^^^ help: try this: `ref_str`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:197:19
+ --> $DIR/explicit_auto_deref.rs:200:19
|
LL | let _ = f_str(**ref_ref_str);
| ^^^^^^^^^^^^^ help: try this: `ref_ref_str`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:207:13
+ --> $DIR/explicit_auto_deref.rs:210:13
|
LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references
| ^^^^^^^^ help: try this: `ref_str`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:208:12
+ --> $DIR/explicit_auto_deref.rs:211:12
|
LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference
| ^^^^^^^^^^ help: try this: `ref_str`
error: deref which would be done by auto-deref
- --> $DIR/explicit_auto_deref.rs:217:41
+ --> $DIR/explicit_auto_deref.rs:220:41
|
LL | let _ = || -> &'static str { return *s };
| ^^ help: try this: `s`
-error: aborting due to 33 previous errors
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:239:9
+ |
+LL | &**x
+ | ^^^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:262:8
+ |
+LL | c1(*x);
+ | ^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:265:20
+ |
+LL | return *x;
+ | ^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+ --> $DIR/explicit_auto_deref.rs:267:9
+ |
+LL | *x
+ | ^^ help: try this: `x`
+
+error: aborting due to 39 previous errors
// run-rustfix
#![allow(
+ unused_tuple_struct_fields,
clippy::print_literal,
clippy::redundant_clone,
clippy::to_string_in_format_args,
// run-rustfix
#![allow(
+ unused_tuple_struct_fields,
clippy::print_literal,
clippy::redundant_clone,
clippy::to_string_in_format_args,
error: useless use of `format!`
- --> $DIR/format.rs:18:5
+ --> $DIR/format.rs:19:5
|
LL | format!("foo");
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
= note: `-D clippy::useless-format` implied by `-D warnings`
error: useless use of `format!`
- --> $DIR/format.rs:19:5
+ --> $DIR/format.rs:20:5
|
LL | format!("{{}}");
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:20:5
+ --> $DIR/format.rs:21:5
|
LL | format!("{{}} abc {{}}");
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:21:5
+ --> $DIR/format.rs:22:5
|
LL | / format!(
LL | | r##"foo {{}}
|
error: useless use of `format!`
- --> $DIR/format.rs:26:13
+ --> $DIR/format.rs:27:13
|
LL | let _ = format!("");
| ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
error: useless use of `format!`
- --> $DIR/format.rs:28:5
+ --> $DIR/format.rs:29:5
|
LL | format!("{}", "foo");
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:32:5
+ --> $DIR/format.rs:33:5
|
LL | format!("{:+}", "foo"); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:33:5
+ --> $DIR/format.rs:34:5
|
LL | format!("{:<}", "foo"); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:38:5
+ --> $DIR/format.rs:39:5
|
LL | format!("{}", arg);
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:42:5
+ --> $DIR/format.rs:43:5
|
LL | format!("{:+}", arg); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:43:5
+ --> $DIR/format.rs:44:5
|
LL | format!("{:<}", arg); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:70:5
+ --> $DIR/format.rs:71:5
|
LL | format!("{}", 42.to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:72:5
+ --> $DIR/format.rs:73:5
|
LL | format!("{}", x.display().to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:76:18
+ --> $DIR/format.rs:77:18
|
LL | let _ = Some(format!("{}", a + "bar"));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
error: useless use of `format!`
- --> $DIR/format.rs:80:22
+ --> $DIR/format.rs:81:22
|
LL | let _s: String = format!("{}", &*v.join("/n"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:86:13
+ --> $DIR/format.rs:87:13
|
LL | let _ = format!("{x}");
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:88:13
+ --> $DIR/format.rs:89:13
|
LL | let _ = format!("{y}", y = x);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:92:13
+ --> $DIR/format.rs:93:13
|
LL | let _ = format!("{abc}");
| ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:94:13
+ --> $DIR/format.rs:95:13
|
LL | let _ = format!("{xx}");
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
// run-rustfix
#![warn(clippy::from_iter_instead_of_collect)]
-#![allow(unused_imports)]
+#![allow(unused_imports, unused_tuple_struct_fields)]
use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
// run-rustfix
#![warn(clippy::from_iter_instead_of_collect)]
-#![allow(unused_imports)]
+#![allow(unused_imports, unused_tuple_struct_fields)]
use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
#![warn(clippy::if_same_then_else)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::eq_op,
clippy::never_loop,
clippy::no_effect,
#![warn(clippy::if_same_then_else)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::collapsible_else_if,
clippy::equatable_if_let,
clippy::collapsible_if,
};
let mut v = vec![1];
- if v.pop() == None {
+ if v.pop().is_none() {
// ok, functions
- } else if v.pop() == None {
+ } else if v.pop().is_none() {
}
if v.len() == 42 {
// aux-build:option_helpers.rs
#![warn(clippy::iter_skip_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
#![allow(clippy::iter_nth)]
#![allow(unused_mut, dead_code)]
// aux-build:option_helpers.rs
#![warn(clippy::iter_skip_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
#![allow(clippy::iter_nth)]
#![allow(unused_mut, dead_code)]
unused_variables,
unused_assignments,
clippy::similar_names,
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::branches_sharing_code,
clippy::needless_late_init
)]
+++ /dev/null
-#![feature(lint_reasons)]
-#![allow(unused, clippy::diverging_sub_expression)]
-#![warn(clippy::logic_bug)]
-
-fn main() {
- let a: bool = unimplemented!();
- let b: bool = unimplemented!();
- let c: bool = unimplemented!();
- let d: bool = unimplemented!();
- let e: bool = unimplemented!();
- let _ = a && b || a;
- let _ = !(a && b);
- let _ = false && a;
- // don't lint on cfgs
- let _ = cfg!(you_shall_not_not_pass) && a;
- let _ = a || !b || !c || !d || !e;
- let _ = !(a && b || c);
-}
-
-fn equality_stuff() {
- let a: i32 = unimplemented!();
- let b: i32 = unimplemented!();
- let _ = a == b && a != b;
- let _ = a < b && a >= b;
- let _ = a > b && a <= b;
- let _ = a > b && a == b;
-}
-
-fn check_expect() {
- let a: i32 = unimplemented!();
- let b: i32 = unimplemented!();
- #[expect(clippy::logic_bug)]
- let _ = a < b && a >= b;
-}
+++ /dev/null
-error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:11:13
- |
-LL | let _ = a && b || a;
- | ^^^^^^^^^^^ help: it would look like the following: `a`
- |
- = note: `-D clippy::logic-bug` implied by `-D warnings`
-help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:11:18
- |
-LL | let _ = a && b || a;
- | ^
-
-error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:13:13
- |
-LL | let _ = false && a;
- | ^^^^^^^^^^ help: it would look like the following: `false`
- |
-help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:13:22
- |
-LL | let _ = false && a;
- | ^
-
-error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:23:13
- |
-LL | let _ = a == b && a != b;
- | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false`
- |
-help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:23:13
- |
-LL | let _ = a == b && a != b;
- | ^^^^^^
-
-error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:24:13
- |
-LL | let _ = a < b && a >= b;
- | ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
- |
-help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:24:13
- |
-LL | let _ = a < b && a >= b;
- | ^^^^^
-
-error: this boolean expression contains a logic bug
- --> $DIR/logic_bug.rs:25:13
- |
-LL | let _ = a > b && a <= b;
- | ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
- |
-help: this expression can be optimized out by applying boolean operations to the outer expression
- --> $DIR/logic_bug.rs:25:13
- |
-LL | let _ = a > b && a <= b;
- | ^^^^^
-
-error: aborting due to 5 previous errors
-
let c = Some(2);
if !a.is_empty()
&& a.len() == 3
- && c != None
+ && c.is_some()
&& !a.is_empty()
&& a.len() == 3
&& !a.is_empty()
let c = Some(2);
if !a.is_empty()
&& a.len() == 3
- && c != None
+ && c.is_some()
&& !a.is_empty()
&& a.len() == 3
&& !a.is_empty()
let c = Some(2);
if !a.is_empty()
&& a.len() == 3
- && c != None
+ && c.is_some()
&& !a.is_empty()
&& a.len() == 3
&& !a.is_empty()
let c = Some(2);
if !a.is_empty()
&& a.len() == 3
- && c != None
+ && c.is_some()
&& !a.is_empty()
&& a.len() == 3
&& !a.is_empty()
--- /dev/null
+// run-rustfix
+#![warn(clippy::manual_instant_elapsed)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+
+use std::time::Instant;
+
+fn main() {
+ let prev_instant = Instant::now();
+
+ {
+ // don't influence
+ let another_instant = Instant::now();
+ }
+
+ let duration = prev_instant.elapsed();
+
+ // don't catch
+ let duration = prev_instant.elapsed();
+
+ Instant::now() - duration;
+
+ let ref_to_instant = &Instant::now();
+
+ (*ref_to_instant).elapsed(); // to ensure parens are added correctly
+}
--- /dev/null
+// run-rustfix
+#![warn(clippy::manual_instant_elapsed)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+
+use std::time::Instant;
+
+fn main() {
+ let prev_instant = Instant::now();
+
+ {
+ // don't influence
+ let another_instant = Instant::now();
+ }
+
+ let duration = Instant::now() - prev_instant;
+
+ // don't catch
+ let duration = prev_instant.elapsed();
+
+ Instant::now() - duration;
+
+ let ref_to_instant = &Instant::now();
+
+ Instant::now() - *ref_to_instant; // to ensure parens are added correctly
+}
--- /dev/null
+error: manual implementation of `Instant::elapsed`
+ --> $DIR/manual_instant_elapsed.rs:17:20
+ |
+LL | let duration = Instant::now() - prev_instant;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `prev_instant.elapsed()`
+ |
+ = note: `-D clippy::manual-instant-elapsed` implied by `-D warnings`
+
+error: manual implementation of `Instant::elapsed`
+ --> $DIR/manual_instant_elapsed.rs:26:5
+ |
+LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()`
+
+error: aborting due to 2 previous errors
+
// run-rustfix
#![warn(clippy::manual_ok_or)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
#![allow(clippy::redundant_closure)]
#![allow(dead_code)]
#![allow(unused_must_use)]
// run-rustfix
#![warn(clippy::manual_ok_or)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
#![allow(clippy::redundant_closure)]
#![allow(dead_code)]
#![allow(unused_must_use)]
#![warn(clippy::match_same_arms)]
-#![allow(clippy::blacklisted_name, clippy::diverging_sub_expression)]
+#![allow(clippy::disallowed_names, clippy::diverging_sub_expression)]
fn bar<T>(_: T) {}
fn foo() -> bool {
#![warn(clippy::all, clippy::pedantic)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::default_trait_access,
clippy::missing_docs_in_private_items,
clippy::missing_safety_doc,
#![warn(clippy::mismatching_type_param_order)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
fn main() {
struct Foo<A, B> {
+++ /dev/null
-#![warn(clippy::missing_docs_in_private_items)]
-
-fn main() {}
+++ /dev/null
-error: missing documentation for the crate
- --> $DIR/missing-doc-crate-missing.rs:1:1
- |
-LL | / #![warn(clippy::missing_docs_in_private_items)]
-LL | |
-LL | | fn main() {}
- | |____________^
- |
- = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
-
-error: aborting due to previous error
-
+++ /dev/null
-#![warn(clippy::missing_docs_in_private_items)]
-#![doc = include_str!("../../README.md")]
-
-fn main() {}
+++ /dev/null
-#![warn(clippy::missing_docs_in_private_items)]
-#![allow(dead_code)]
-#![feature(associated_type_defaults)]
-
-//! Some garbage docs for the crate here
-#![doc = "More garbage"]
-
-struct Foo {
- a: isize,
- b: isize,
-}
-
-pub struct PubFoo {
- pub a: isize,
- b: isize,
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-pub struct PubFoo2 {
- pub a: isize,
- pub c: isize,
-}
-
-/// dox
-pub trait A {
- /// dox
- fn foo(&self);
- /// dox
- fn foo_with_impl(&self) {}
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-trait B {
- fn foo(&self);
- fn foo_with_impl(&self) {}
-}
-
-pub trait C {
- fn foo(&self);
- fn foo_with_impl(&self) {}
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-pub trait D {
- fn dummy(&self) {}
-}
-
-/// dox
-pub trait E: Sized {
- type AssociatedType;
- type AssociatedTypeDef = Self;
-
- /// dox
- type DocumentedType;
- /// dox
- type DocumentedTypeDef = Self;
- /// dox
- fn dummy(&self) {}
-}
-
-impl Foo {
- pub fn new() -> Self {
- Foo { a: 0, b: 0 }
- }
- fn bar() {}
-}
-
-impl PubFoo {
- pub fn foo() {}
- /// dox
- pub fn foo1() {}
- #[must_use = "yep"]
- fn foo2() -> u32 {
- 1
- }
- #[allow(clippy::missing_docs_in_private_items)]
- pub fn foo3() {}
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-trait F {
- fn a();
- fn b(&self);
-}
-
-// should need to redefine documentation for implementations of traits
-impl F for Foo {
- fn a() {}
- fn b(&self) {}
-}
-
-fn main() {}
+++ /dev/null
-error: missing documentation for a struct
- --> $DIR/missing-doc-impl.rs:8:1
- |
-LL | / struct Foo {
-LL | | a: isize,
-LL | | b: isize,
-LL | | }
- | |_^
- |
- = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
-
-error: missing documentation for a struct field
- --> $DIR/missing-doc-impl.rs:9:5
- |
-LL | a: isize,
- | ^^^^^^^^
-
-error: missing documentation for a struct field
- --> $DIR/missing-doc-impl.rs:10:5
- |
-LL | b: isize,
- | ^^^^^^^^
-
-error: missing documentation for a struct
- --> $DIR/missing-doc-impl.rs:13:1
- |
-LL | / pub struct PubFoo {
-LL | | pub a: isize,
-LL | | b: isize,
-LL | | }
- | |_^
-
-error: missing documentation for a struct field
- --> $DIR/missing-doc-impl.rs:14:5
- |
-LL | pub a: isize,
- | ^^^^^^^^^^^^
-
-error: missing documentation for a struct field
- --> $DIR/missing-doc-impl.rs:15:5
- |
-LL | b: isize,
- | ^^^^^^^^
-
-error: missing documentation for a trait
- --> $DIR/missing-doc-impl.rs:38:1
- |
-LL | / pub trait C {
-LL | | fn foo(&self);
-LL | | fn foo_with_impl(&self) {}
-LL | | }
- | |_^
-
-error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:39:5
- |
-LL | fn foo(&self);
- | ^^^^^^^^^^^^^^
-
-error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:40:5
- |
-LL | fn foo_with_impl(&self) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for an associated type
- --> $DIR/missing-doc-impl.rs:50:5
- |
-LL | type AssociatedType;
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for an associated type
- --> $DIR/missing-doc-impl.rs:51:5
- |
-LL | type AssociatedTypeDef = Self;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:62:5
- |
-LL | / pub fn new() -> Self {
-LL | | Foo { a: 0, b: 0 }
-LL | | }
- | |_____^
-
-error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:65:5
- |
-LL | fn bar() {}
- | ^^^^^^^^^^^
-
-error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:69:5
- |
-LL | pub fn foo() {}
- | ^^^^^^^^^^^^^^^
-
-error: missing documentation for an associated function
- --> $DIR/missing-doc-impl.rs:73:5
- |
-LL | / fn foo2() -> u32 {
-LL | | 1
-LL | | }
- | |_____^
-
-error: aborting due to 15 previous errors
-
+++ /dev/null
-#![warn(clippy::missing_docs_in_private_items)]
-// When denying at the crate level, be sure to not get random warnings from the
-// injected intrinsics by the compiler.
-#![allow(dead_code)]
-//! Some garbage docs for the crate here
-#![doc = "More garbage"]
-
-use std::arch::global_asm;
-
-type Typedef = String;
-pub type PubTypedef = String;
-
-mod module_no_dox {}
-pub mod pub_module_no_dox {}
-
-/// dox
-pub fn foo() {}
-pub fn foo2() {}
-fn foo3() {}
-#[allow(clippy::missing_docs_in_private_items)]
-pub fn foo4() {}
-
-// It sure is nice if doc(hidden) implies allow(missing_docs), and that it
-// applies recursively
-#[doc(hidden)]
-mod a {
- pub fn baz() {}
- pub mod b {
- pub fn baz() {}
- }
-}
-
-enum Baz {
- BazA { a: isize, b: isize },
- BarB,
-}
-
-pub enum PubBaz {
- PubBazA { a: isize },
-}
-
-/// dox
-pub enum PubBaz2 {
- /// dox
- PubBaz2A {
- /// dox
- a: isize,
- },
-}
-
-#[allow(clippy::missing_docs_in_private_items)]
-pub enum PubBaz3 {
- PubBaz3A { b: isize },
-}
-
-#[doc(hidden)]
-pub fn baz() {}
-
-const FOO: u32 = 0;
-/// dox
-pub const FOO1: u32 = 0;
-#[allow(clippy::missing_docs_in_private_items)]
-pub const FOO2: u32 = 0;
-#[doc(hidden)]
-pub const FOO3: u32 = 0;
-pub const FOO4: u32 = 0;
-
-static BAR: u32 = 0;
-/// dox
-pub static BAR1: u32 = 0;
-#[allow(clippy::missing_docs_in_private_items)]
-pub static BAR2: u32 = 0;
-#[doc(hidden)]
-pub static BAR3: u32 = 0;
-pub static BAR4: u32 = 0;
-
-mod internal_impl {
- /// dox
- pub fn documented() {}
- pub fn undocumented1() {}
- pub fn undocumented2() {}
- fn undocumented3() {}
- /// dox
- pub mod globbed {
- /// dox
- pub fn also_documented() {}
- pub fn also_undocumented1() {}
- fn also_undocumented2() {}
- }
-}
-/// dox
-pub mod public_interface {
- pub use crate::internal_impl::documented as foo;
- pub use crate::internal_impl::globbed::*;
- pub use crate::internal_impl::undocumented1 as bar;
- pub use crate::internal_impl::{documented, undocumented2};
-}
-
-fn main() {}
-
-// Ensure global asm doesn't require documentation.
-global_asm! { "" }
+++ /dev/null
-error: missing documentation for a type alias
- --> $DIR/missing-doc.rs:10:1
- |
-LL | type Typedef = String;
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
-
-error: missing documentation for a type alias
- --> $DIR/missing-doc.rs:11:1
- |
-LL | pub type PubTypedef = String;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a module
- --> $DIR/missing-doc.rs:13:1
- |
-LL | mod module_no_dox {}
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a module
- --> $DIR/missing-doc.rs:14:1
- |
-LL | pub mod pub_module_no_dox {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
- --> $DIR/missing-doc.rs:18:1
- |
-LL | pub fn foo2() {}
- | ^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
- --> $DIR/missing-doc.rs:19:1
- |
-LL | fn foo3() {}
- | ^^^^^^^^^^^^
-
-error: missing documentation for an enum
- --> $DIR/missing-doc.rs:33:1
- |
-LL | / enum Baz {
-LL | | BazA { a: isize, b: isize },
-LL | | BarB,
-LL | | }
- | |_^
-
-error: missing documentation for a variant
- --> $DIR/missing-doc.rs:34:5
- |
-LL | BazA { a: isize, b: isize },
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:34:12
- |
-LL | BazA { a: isize, b: isize },
- | ^^^^^^^^
-
-error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:34:22
- |
-LL | BazA { a: isize, b: isize },
- | ^^^^^^^^
-
-error: missing documentation for a variant
- --> $DIR/missing-doc.rs:35:5
- |
-LL | BarB,
- | ^^^^
-
-error: missing documentation for an enum
- --> $DIR/missing-doc.rs:38:1
- |
-LL | / pub enum PubBaz {
-LL | | PubBazA { a: isize },
-LL | | }
- | |_^
-
-error: missing documentation for a variant
- --> $DIR/missing-doc.rs:39:5
- |
-LL | PubBazA { a: isize },
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:39:15
- |
-LL | PubBazA { a: isize },
- | ^^^^^^^^
-
-error: missing documentation for a constant
- --> $DIR/missing-doc.rs:59:1
- |
-LL | const FOO: u32 = 0;
- | ^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a constant
- --> $DIR/missing-doc.rs:66:1
- |
-LL | pub const FOO4: u32 = 0;
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a static
- --> $DIR/missing-doc.rs:68:1
- |
-LL | static BAR: u32 = 0;
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a static
- --> $DIR/missing-doc.rs:75:1
- |
-LL | pub static BAR4: u32 = 0;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a module
- --> $DIR/missing-doc.rs:77:1
- |
-LL | / mod internal_impl {
-LL | | /// dox
-LL | | pub fn documented() {}
-LL | | pub fn undocumented1() {}
-... |
-LL | | }
-LL | | }
- | |_^
-
-error: missing documentation for a function
- --> $DIR/missing-doc.rs:80:5
- |
-LL | pub fn undocumented1() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
- --> $DIR/missing-doc.rs:81:5
- |
-LL | pub fn undocumented2() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
- --> $DIR/missing-doc.rs:82:5
- |
-LL | fn undocumented3() {}
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
- --> $DIR/missing-doc.rs:87:9
- |
-LL | pub fn also_undocumented1() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: missing documentation for a function
- --> $DIR/missing-doc.rs:88:9
- |
-LL | fn also_undocumented2() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 24 previous errors
-
//! The .stderr output of this test should be empty. Otherwise it's a bug somewhere.
// aux-build:helper.rs
+// aux-build:../../auxiliary/proc_macro_with_span.rs
#![warn(clippy::missing_const_for_fn)]
#![feature(start)]
#![feature(custom_inner_attributes)]
extern crate helper;
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
struct Game;
byte.is_ascii_digit();
}
}
+
+with_span! {
+ span
+ fn dont_check_in_proc_macro() {}
+}
--- /dev/null
+// aux-build: proc_macro_with_span.rs
+
+#![warn(clippy::missing_docs_in_private_items)]
+// When denying at the crate level, be sure to not get random warnings from the
+// injected intrinsics by the compiler.
+#![allow(dead_code)]
+//! Some garbage docs for the crate here
+#![doc = "More garbage"]
+
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
+use std::arch::global_asm;
+
+type Typedef = String;
+pub type PubTypedef = String;
+
+mod module_no_dox {}
+pub mod pub_module_no_dox {}
+
+/// dox
+pub fn foo() {}
+pub fn foo2() {}
+fn foo3() {}
+#[allow(clippy::missing_docs_in_private_items)]
+pub fn foo4() {}
+
+// It sure is nice if doc(hidden) implies allow(missing_docs), and that it
+// applies recursively
+#[doc(hidden)]
+mod a {
+ pub fn baz() {}
+ pub mod b {
+ pub fn baz() {}
+ }
+}
+
+enum Baz {
+ BazA { a: isize, b: isize },
+ BarB,
+}
+
+pub enum PubBaz {
+ PubBazA { a: isize },
+}
+
+/// dox
+pub enum PubBaz2 {
+ /// dox
+ PubBaz2A {
+ /// dox
+ a: isize,
+ },
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub enum PubBaz3 {
+ PubBaz3A { b: isize },
+}
+
+#[doc(hidden)]
+pub fn baz() {}
+
+const FOO: u32 = 0;
+/// dox
+pub const FOO1: u32 = 0;
+#[allow(clippy::missing_docs_in_private_items)]
+pub const FOO2: u32 = 0;
+#[doc(hidden)]
+pub const FOO3: u32 = 0;
+pub const FOO4: u32 = 0;
+
+static BAR: u32 = 0;
+/// dox
+pub static BAR1: u32 = 0;
+#[allow(clippy::missing_docs_in_private_items)]
+pub static BAR2: u32 = 0;
+#[doc(hidden)]
+pub static BAR3: u32 = 0;
+pub static BAR4: u32 = 0;
+
+mod internal_impl {
+ /// dox
+ pub fn documented() {}
+ pub fn undocumented1() {}
+ pub fn undocumented2() {}
+ fn undocumented3() {}
+ /// dox
+ pub mod globbed {
+ /// dox
+ pub fn also_documented() {}
+ pub fn also_undocumented1() {}
+ fn also_undocumented2() {}
+ }
+}
+/// dox
+pub mod public_interface {
+ pub use crate::internal_impl::documented as foo;
+ pub use crate::internal_impl::globbed::*;
+ pub use crate::internal_impl::undocumented1 as bar;
+ pub use crate::internal_impl::{documented, undocumented2};
+}
+
+fn main() {}
+
+// Ensure global asm doesn't require documentation.
+global_asm! { "" }
+
+// Don't lint proc macro output with an unexpected span.
+with_span!(span pub struct FooPm { pub field: u32});
+with_span!(span pub struct FooPm2;);
+with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }});
+with_span!(span pub fn foo_pm() {});
+with_span!(span pub static FOO_PM: u32 = 0;);
+with_span!(span pub const FOO2_PM: u32 = 0;);
--- /dev/null
+error: missing documentation for a type alias
+ --> $DIR/missing_doc.rs:15:1
+ |
+LL | type Typedef = String;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: missing documentation for a type alias
+ --> $DIR/missing_doc.rs:16:1
+ |
+LL | pub type PubTypedef = String;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a module
+ --> $DIR/missing_doc.rs:18:1
+ |
+LL | mod module_no_dox {}
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a module
+ --> $DIR/missing_doc.rs:19:1
+ |
+LL | pub mod pub_module_no_dox {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+ --> $DIR/missing_doc.rs:23:1
+ |
+LL | pub fn foo2() {}
+ | ^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+ --> $DIR/missing_doc.rs:24:1
+ |
+LL | fn foo3() {}
+ | ^^^^^^^^^^^^
+
+error: missing documentation for an enum
+ --> $DIR/missing_doc.rs:38:1
+ |
+LL | / enum Baz {
+LL | | BazA { a: isize, b: isize },
+LL | | BarB,
+LL | | }
+ | |_^
+
+error: missing documentation for a variant
+ --> $DIR/missing_doc.rs:39:5
+ |
+LL | BazA { a: isize, b: isize },
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+ --> $DIR/missing_doc.rs:39:12
+ |
+LL | BazA { a: isize, b: isize },
+ | ^^^^^^^^
+
+error: missing documentation for a struct field
+ --> $DIR/missing_doc.rs:39:22
+ |
+LL | BazA { a: isize, b: isize },
+ | ^^^^^^^^
+
+error: missing documentation for a variant
+ --> $DIR/missing_doc.rs:40:5
+ |
+LL | BarB,
+ | ^^^^
+
+error: missing documentation for an enum
+ --> $DIR/missing_doc.rs:43:1
+ |
+LL | / pub enum PubBaz {
+LL | | PubBazA { a: isize },
+LL | | }
+ | |_^
+
+error: missing documentation for a variant
+ --> $DIR/missing_doc.rs:44:5
+ |
+LL | PubBazA { a: isize },
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+ --> $DIR/missing_doc.rs:44:15
+ |
+LL | PubBazA { a: isize },
+ | ^^^^^^^^
+
+error: missing documentation for a constant
+ --> $DIR/missing_doc.rs:64:1
+ |
+LL | const FOO: u32 = 0;
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a constant
+ --> $DIR/missing_doc.rs:71:1
+ |
+LL | pub const FOO4: u32 = 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a static
+ --> $DIR/missing_doc.rs:73:1
+ |
+LL | static BAR: u32 = 0;
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a static
+ --> $DIR/missing_doc.rs:80:1
+ |
+LL | pub static BAR4: u32 = 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a module
+ --> $DIR/missing_doc.rs:82:1
+ |
+LL | / mod internal_impl {
+LL | | /// dox
+LL | | pub fn documented() {}
+LL | | pub fn undocumented1() {}
+... |
+LL | | }
+LL | | }
+ | |_^
+
+error: missing documentation for a function
+ --> $DIR/missing_doc.rs:85:5
+ |
+LL | pub fn undocumented1() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+ --> $DIR/missing_doc.rs:86:5
+ |
+LL | pub fn undocumented2() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+ --> $DIR/missing_doc.rs:87:5
+ |
+LL | fn undocumented3() {}
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+ --> $DIR/missing_doc.rs:92:9
+ |
+LL | pub fn also_undocumented1() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for a function
+ --> $DIR/missing_doc.rs:93:9
+ |
+LL | fn also_undocumented2() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
+
--- /dev/null
+#![warn(clippy::missing_docs_in_private_items)]
+#![doc = include_str!("../../README.md")]
+
+fn main() {}
--- /dev/null
+#![warn(clippy::missing_docs_in_private_items)]
+
+fn main() {}
--- /dev/null
+error: missing documentation for the crate
+ --> $DIR/missing_doc_crate_missing.rs:1:1
+ |
+LL | / #![warn(clippy::missing_docs_in_private_items)]
+LL | |
+LL | | fn main() {}
+ | |____________^
+ |
+ = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: aborting due to previous error
+
--- /dev/null
+// aux-build: proc_macro_with_span.rs
+
+#![warn(clippy::missing_docs_in_private_items)]
+#![allow(dead_code)]
+#![feature(associated_type_defaults)]
+
+//! Some garbage docs for the crate here
+#![doc = "More garbage"]
+
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
+struct Foo {
+ a: isize,
+ b: isize,
+}
+
+pub struct PubFoo {
+ pub a: isize,
+ b: isize,
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub struct PubFoo2 {
+ pub a: isize,
+ pub c: isize,
+}
+
+/// dox
+pub trait A {
+ /// dox
+ fn foo(&self);
+ /// dox
+ fn foo_with_impl(&self) {}
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+trait B {
+ fn foo(&self);
+ fn foo_with_impl(&self) {}
+}
+
+pub trait C {
+ fn foo(&self);
+ fn foo_with_impl(&self) {}
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+pub trait D {
+ fn dummy(&self) {}
+}
+
+/// dox
+pub trait E: Sized {
+ type AssociatedType;
+ type AssociatedTypeDef = Self;
+
+ /// dox
+ type DocumentedType;
+ /// dox
+ type DocumentedTypeDef = Self;
+ /// dox
+ fn dummy(&self) {}
+}
+
+impl Foo {
+ pub fn new() -> Self {
+ Foo { a: 0, b: 0 }
+ }
+ fn bar() {}
+}
+
+impl PubFoo {
+ pub fn foo() {}
+ /// dox
+ pub fn foo1() {}
+ #[must_use = "yep"]
+ fn foo2() -> u32 {
+ 1
+ }
+ #[allow(clippy::missing_docs_in_private_items)]
+ pub fn foo3() {}
+}
+
+#[allow(clippy::missing_docs_in_private_items)]
+trait F {
+ fn a();
+ fn b(&self);
+}
+
+// should need to redefine documentation for implementations of traits
+impl F for Foo {
+ fn a() {}
+ fn b(&self) {}
+}
+
+fn main() {}
+
+// don't lint proc macro output
+with_span!(span
+ pub struct FooPm;
+ impl FooPm {
+ pub fn foo() {}
+ pub const fn bar() {}
+ pub const X: u32 = 0;
+ }
+);
--- /dev/null
+error: missing documentation for a struct
+ --> $DIR/missing_doc_impl.rs:13:1
+ |
+LL | / struct Foo {
+LL | | a: isize,
+LL | | b: isize,
+LL | | }
+ | |_^
+ |
+ = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
+
+error: missing documentation for a struct field
+ --> $DIR/missing_doc_impl.rs:14:5
+ |
+LL | a: isize,
+ | ^^^^^^^^
+
+error: missing documentation for a struct field
+ --> $DIR/missing_doc_impl.rs:15:5
+ |
+LL | b: isize,
+ | ^^^^^^^^
+
+error: missing documentation for a struct
+ --> $DIR/missing_doc_impl.rs:18:1
+ |
+LL | / pub struct PubFoo {
+LL | | pub a: isize,
+LL | | b: isize,
+LL | | }
+ | |_^
+
+error: missing documentation for a struct field
+ --> $DIR/missing_doc_impl.rs:19:5
+ |
+LL | pub a: isize,
+ | ^^^^^^^^^^^^
+
+error: missing documentation for a struct field
+ --> $DIR/missing_doc_impl.rs:20:5
+ |
+LL | b: isize,
+ | ^^^^^^^^
+
+error: missing documentation for a trait
+ --> $DIR/missing_doc_impl.rs:43:1
+ |
+LL | / pub trait C {
+LL | | fn foo(&self);
+LL | | fn foo_with_impl(&self) {}
+LL | | }
+ | |_^
+
+error: missing documentation for an associated function
+ --> $DIR/missing_doc_impl.rs:44:5
+ |
+LL | fn foo(&self);
+ | ^^^^^^^^^^^^^^
+
+error: missing documentation for an associated function
+ --> $DIR/missing_doc_impl.rs:45:5
+ |
+LL | fn foo_with_impl(&self) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated type
+ --> $DIR/missing_doc_impl.rs:55:5
+ |
+LL | type AssociatedType;
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated type
+ --> $DIR/missing_doc_impl.rs:56:5
+ |
+LL | type AssociatedTypeDef = Self;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated function
+ --> $DIR/missing_doc_impl.rs:67:5
+ |
+LL | / pub fn new() -> Self {
+LL | | Foo { a: 0, b: 0 }
+LL | | }
+ | |_____^
+
+error: missing documentation for an associated function
+ --> $DIR/missing_doc_impl.rs:70:5
+ |
+LL | fn bar() {}
+ | ^^^^^^^^^^^
+
+error: missing documentation for an associated function
+ --> $DIR/missing_doc_impl.rs:74:5
+ |
+LL | pub fn foo() {}
+ | ^^^^^^^^^^^^^^^
+
+error: missing documentation for an associated function
+ --> $DIR/missing_doc_impl.rs:78:5
+ |
+LL | / fn foo2() -> u32 {
+LL | | 1
+LL | | }
+ | |_____^
+
+error: aborting due to 15 previous errors
+
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![allow(
dead_code,
clippy::unusual_byte_groupings
)]
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
fn main() {
let fail14 = 2_i32;
let fail15 = 4_i64;
let ok38 = 124_64.0;
let _ = 1.123_45E1_f32;
+
+ let _ = with_span!(1 2_u32);
}
// run-rustfix
+// aux-build: proc_macro_with_span.rs
#![allow(
dead_code,
clippy::unusual_byte_groupings
)]
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
fn main() {
let fail14 = 2_32;
let fail15 = 4_64;
let ok38 = 124_64.0;
let _ = 1.12345E1_32;
+
+ let _ = with_span!(1 2_u32);
}
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:13:18
+ --> $DIR/mistyped_literal_suffix.rs:17:18
|
LL | let fail14 = 2_32;
| ^^^^ help: did you mean to write: `2_i32`
= note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:14:18
+ --> $DIR/mistyped_literal_suffix.rs:18:18
|
LL | let fail15 = 4_64;
| ^^^^ help: did you mean to write: `4_i64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:15:18
+ --> $DIR/mistyped_literal_suffix.rs:19:18
|
LL | let fail16 = 7_8; //
| ^^^ help: did you mean to write: `7_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:16:18
+ --> $DIR/mistyped_literal_suffix.rs:20:18
|
LL | let fail17 = 23_16; //
| ^^^^^ help: did you mean to write: `23_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:19:18
+ --> $DIR/mistyped_literal_suffix.rs:23:18
|
LL | let fail20 = 2__8; //
| ^^^^ help: did you mean to write: `2_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:20:18
+ --> $DIR/mistyped_literal_suffix.rs:24:18
|
LL | let fail21 = 4___16; //
| ^^^^^^ help: did you mean to write: `4_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:23:18
+ --> $DIR/mistyped_literal_suffix.rs:27:18
|
LL | let fail25 = 1E2_32;
| ^^^^^^ help: did you mean to write: `1E2_f32`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:24:18
+ --> $DIR/mistyped_literal_suffix.rs:28:18
|
LL | let fail26 = 43E7_64;
| ^^^^^^^ help: did you mean to write: `43E7_f64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:25:18
+ --> $DIR/mistyped_literal_suffix.rs:29:18
|
LL | let fail27 = 243E17_32;
| ^^^^^^^^^ help: did you mean to write: `243E17_f32`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:26:18
+ --> $DIR/mistyped_literal_suffix.rs:30:18
|
LL | let fail28 = 241251235E723_64;
| ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:30:18
+ --> $DIR/mistyped_literal_suffix.rs:34:18
|
LL | let fail30 = 127_8; // should be i8
| ^^^^^ help: did you mean to write: `127_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:31:18
+ --> $DIR/mistyped_literal_suffix.rs:35:18
|
LL | let fail31 = 240_8; // should be u8
| ^^^^^ help: did you mean to write: `240_u8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:33:18
+ --> $DIR/mistyped_literal_suffix.rs:37:18
|
LL | let fail33 = 0x1234_16;
| ^^^^^^^^^ help: did you mean to write: `0x1234_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:34:18
+ --> $DIR/mistyped_literal_suffix.rs:38:18
|
LL | let fail34 = 0xABCD_16;
| ^^^^^^^^^ help: did you mean to write: `0xABCD_u16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:36:18
+ --> $DIR/mistyped_literal_suffix.rs:40:18
|
LL | let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:42:13
+ --> $DIR/mistyped_literal_suffix.rs:46:13
|
LL | let _ = 1.12345E1_32;
| ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32`
unused_variables,
clippy::no_effect,
dead_code,
- clippy::blacklisted_name
+ clippy::disallowed_names
)]
fn main() {
let mut x = 0;
// run-rustfix
#![feature(never_type)]
-#![allow(unused_mut, clippy::redundant_allocation)]
+#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)]
#![warn(clippy::must_use_candidate)]
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
// run-rustfix
#![feature(never_type)]
-#![allow(unused_mut, clippy::redundant_allocation)]
+#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)]
#![warn(clippy::must_use_candidate)]
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
//run-rustfix
#![warn(clippy::init_numbered_fields)]
+#![allow(unused_tuple_struct_fields)]
#[derive(Default)]
struct TupleStruct(u32, u32, u8);
//run-rustfix
#![warn(clippy::init_numbered_fields)]
+#![allow(unused_tuple_struct_fields)]
#[derive(Default)]
struct TupleStruct(u32, u32, u8);
error: used a field initializer for a tuple struct
- --> $DIR/numbered_fields.rs:18:13
+ --> $DIR/numbered_fields.rs:19:13
|
LL | let _ = TupleStruct {
| _____________^
= note: `-D clippy::init-numbered-fields` implied by `-D warnings`
error: used a field initializer for a tuple struct
- --> $DIR/numbered_fields.rs:25:13
+ --> $DIR/numbered_fields.rs:26:13
|
LL | let _ = TupleStruct {
| _____________^
-#![allow(unused_variables, clippy::blacklisted_name)]
+#![allow(unused_variables, clippy::disallowed_names)]
#![warn(clippy::op_ref)]
use std::collections::HashSet;
use std::ops::{BitAnd, Mul};
// run-rustfix
#![warn(clippy::option_if_let_else)]
#![allow(
+ unused_tuple_struct_fields,
clippy::redundant_closure,
clippy::ref_option_ref,
clippy::equatable_if_let,
// run-rustfix
#![warn(clippy::option_if_let_else)]
#![allow(
+ unused_tuple_struct_fields,
clippy::redundant_closure,
clippy::ref_option_ref,
clippy::equatable_if_let,
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:11:5
+ --> $DIR/option_if_let_else.rs:12:5
|
LL | / if let Some(x) = string {
LL | | (true, x)
= note: `-D clippy::option-if-let-else` implied by `-D warnings`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:29:13
+ --> $DIR/option_if_let_else.rs:30:13
|
LL | let _ = if let Some(s) = *string { s.len() } else { 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:30:13
+ --> $DIR/option_if_let_else.rs:31:13
|
LL | let _ = if let Some(s) = &num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:31:13
+ --> $DIR/option_if_let_else.rs:32:13
|
LL | let _ = if let Some(s) = &mut num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:37:13
+ --> $DIR/option_if_let_else.rs:38:13
|
LL | let _ = if let Some(ref s) = num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:38:13
+ --> $DIR/option_if_let_else.rs:39:13
|
LL | let _ = if let Some(mut s) = num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:44:13
+ --> $DIR/option_if_let_else.rs:45:13
|
LL | let _ = if let Some(ref mut s) = num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:53:5
+ --> $DIR/option_if_let_else.rs:54:5
|
LL | / if let Some(x) = arg {
LL | | let y = x * x;
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:66:13
+ --> $DIR/option_if_let_else.rs:67:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
| |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:75:13
+ --> $DIR/option_if_let_else.rs:76:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:108:13
+ --> $DIR/option_if_let_else.rs:109:13
|
LL | / if let Some(idx) = s.find('.') {
LL | | vec![s[..idx].to_string(), s[idx..].to_string()]
| |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:132:13
+ --> $DIR/option_if_let_else.rs:133:13
|
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:141:13
+ --> $DIR/option_if_let_else.rs:142:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:169:13
+ --> $DIR/option_if_let_else.rs:170:13
|
LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:173:13
+ --> $DIR/option_if_let_else.rs:174:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
--- /dev/null
+#![feature(lint_reasons)]
+#![allow(unused, clippy::diverging_sub_expression)]
+#![warn(clippy::overly_complex_bool_expr)]
+
+fn main() {
+ let a: bool = unimplemented!();
+ let b: bool = unimplemented!();
+ let c: bool = unimplemented!();
+ let d: bool = unimplemented!();
+ let e: bool = unimplemented!();
+ let _ = a && b || a;
+ let _ = !(a && b);
+ let _ = false && a;
+ // don't lint on cfgs
+ let _ = cfg!(you_shall_not_not_pass) && a;
+ let _ = a || !b || !c || !d || !e;
+ let _ = !(a && b || c);
+}
+
+fn equality_stuff() {
+ let a: i32 = unimplemented!();
+ let b: i32 = unimplemented!();
+ let _ = a == b && a != b;
+ let _ = a < b && a >= b;
+ let _ = a > b && a <= b;
+ let _ = a > b && a == b;
+}
+
+fn check_expect() {
+ let a: i32 = unimplemented!();
+ let b: i32 = unimplemented!();
+ #[expect(clippy::overly_complex_bool_expr)]
+ let _ = a < b && a >= b;
+}
--- /dev/null
+error: this boolean expression contains a logic bug
+ --> $DIR/overly_complex_bool_expr.rs:11:13
+ |
+LL | let _ = a && b || a;
+ | ^^^^^^^^^^^ help: it would look like the following: `a`
+ |
+ = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings`
+help: this expression can be optimized out by applying boolean operations to the outer expression
+ --> $DIR/overly_complex_bool_expr.rs:11:18
+ |
+LL | let _ = a && b || a;
+ | ^
+
+error: this boolean expression contains a logic bug
+ --> $DIR/overly_complex_bool_expr.rs:13:13
+ |
+LL | let _ = false && a;
+ | ^^^^^^^^^^ help: it would look like the following: `false`
+ |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+ --> $DIR/overly_complex_bool_expr.rs:13:22
+ |
+LL | let _ = false && a;
+ | ^
+
+error: this boolean expression contains a logic bug
+ --> $DIR/overly_complex_bool_expr.rs:23:13
+ |
+LL | let _ = a == b && a != b;
+ | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false`
+ |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+ --> $DIR/overly_complex_bool_expr.rs:23:13
+ |
+LL | let _ = a == b && a != b;
+ | ^^^^^^
+
+error: this boolean expression contains a logic bug
+ --> $DIR/overly_complex_bool_expr.rs:24:13
+ |
+LL | let _ = a < b && a >= b;
+ | ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
+ |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+ --> $DIR/overly_complex_bool_expr.rs:24:13
+ |
+LL | let _ = a < b && a >= b;
+ | ^^^^^
+
+error: this boolean expression contains a logic bug
+ --> $DIR/overly_complex_bool_expr.rs:25:13
+ |
+LL | let _ = a > b && a <= b;
+ | ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
+ |
+help: this expression can be optimized out by applying boolean operations to the outer expression
+ --> $DIR/overly_complex_bool_expr.rs:25:13
+ |
+LL | let _ = a > b && a <= b;
+ | ^^^^^
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+// run-rustfix
+#![warn(clippy::partialeq_to_none)]
+
+struct Foobar;
+
+impl PartialEq<Option<()>> for Foobar {
+ fn eq(&self, _: &Option<()>) -> bool {
+ false
+ }
+}
+
+#[allow(dead_code)]
+fn foo(f: Option<u32>) -> &'static str {
+ if f.is_some() { "yay" } else { "nay" }
+}
+
+fn foobar() -> Option<()> {
+ None
+}
+
+fn bar() -> Result<(), ()> {
+ Ok(())
+}
+
+fn optref() -> &'static &'static Option<()> {
+ &&None
+}
+
+fn main() {
+ let x = Some(0);
+
+ let _ = x.is_none();
+ let _ = x.is_some();
+ let _ = x.is_none();
+ let _ = x.is_some();
+
+ if foobar().is_none() {}
+
+ if bar().ok().is_some() {}
+
+ let _ = Some(1 + 2).is_some();
+
+ let _ = { Some(0) }.is_none();
+
+ let _ = {
+ /*
+ This comment runs long
+ */
+ Some(1)
+ }.is_some();
+
+ // Should not trigger, as `Foobar` is not an `Option` and has no `is_none`
+ let _ = Foobar == None;
+
+ let _ = optref().is_none();
+ let _ = optref().is_some();
+ let _ = optref().is_none();
+ let _ = optref().is_some();
+
+ let x = Box::new(Option::<()>::None);
+ let _ = (*x).is_some();
+}
--- /dev/null
+// run-rustfix
+#![warn(clippy::partialeq_to_none)]
+
+struct Foobar;
+
+impl PartialEq<Option<()>> for Foobar {
+ fn eq(&self, _: &Option<()>) -> bool {
+ false
+ }
+}
+
+#[allow(dead_code)]
+fn foo(f: Option<u32>) -> &'static str {
+ if f != None { "yay" } else { "nay" }
+}
+
+fn foobar() -> Option<()> {
+ None
+}
+
+fn bar() -> Result<(), ()> {
+ Ok(())
+}
+
+fn optref() -> &'static &'static Option<()> {
+ &&None
+}
+
+fn main() {
+ let x = Some(0);
+
+ let _ = x == None;
+ let _ = x != None;
+ let _ = None == x;
+ let _ = None != x;
+
+ if foobar() == None {}
+
+ if bar().ok() != None {}
+
+ let _ = Some(1 + 2) != None;
+
+ let _ = { Some(0) } == None;
+
+ let _ = {
+ /*
+ This comment runs long
+ */
+ Some(1)
+ } != None;
+
+ // Should not trigger, as `Foobar` is not an `Option` and has no `is_none`
+ let _ = Foobar == None;
+
+ let _ = optref() == &&None;
+ let _ = &&None != optref();
+ let _ = **optref() == None;
+ let _ = &None != *optref();
+
+ let x = Box::new(Option::<()>::None);
+ let _ = None != *x;
+}
--- /dev/null
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:14:8
+ |
+LL | if f != None { "yay" } else { "nay" }
+ | ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()`
+ |
+ = note: `-D clippy::partialeq-to-none` implied by `-D warnings`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:32:13
+ |
+LL | let _ = x == None;
+ | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:33:13
+ |
+LL | let _ = x != None;
+ | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:34:13
+ |
+LL | let _ = None == x;
+ | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:35:13
+ |
+LL | let _ = None != x;
+ | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:37:8
+ |
+LL | if foobar() == None {}
+ | ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:39:8
+ |
+LL | if bar().ok() != None {}
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:41:13
+ |
+LL | let _ = Some(1 + 2) != None;
+ | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:43:13
+ |
+LL | let _ = { Some(0) } == None;
+ | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:45:13
+ |
+LL | let _ = {
+ | _____________^
+LL | | /*
+LL | | This comment runs long
+LL | | */
+LL | | Some(1)
+LL | | } != None;
+ | |_____________^
+ |
+help: use `Option::is_some()` instead
+ |
+LL ~ let _ = {
+LL + /*
+LL + This comment runs long
+LL + */
+LL + Some(1)
+LL ~ }.is_some();
+ |
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:55:13
+ |
+LL | let _ = optref() == &&None;
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:56:13
+ |
+LL | let _ = &&None != optref();
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:57:13
+ |
+LL | let _ = **optref() == None;
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:58:13
+ |
+LL | let _ = &None != *optref();
+ | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
+
+error: binary comparison to literal `Option::None`
+ --> $DIR/partialeq_to_none.rs:61:13
+ |
+LL | let _ = None != *x;
+ | ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()`
+
+error: aborting due to 15 previous errors
+
#![warn(clippy::rc_mutex)]
-#![allow(unused, clippy::blacklisted_name)]
+#![allow(unused, clippy::disallowed_names)]
use std::rc::Rc;
use std::sync::Mutex;
#![warn(clippy::all)]
-#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
-#![allow(unused_imports)]
+#![allow(clippy::boxed_local, clippy::disallowed_names)]
pub struct MyStruct;
foo: T,
}
-pub enum MyEnum {
- One,
- Two,
-}
-
mod outer_box {
- use crate::MyEnum;
use crate::MyStruct;
use crate::SubT;
use std::boxed::Box;
}
mod outer_rc {
- use crate::MyEnum;
use crate::MyStruct;
use crate::SubT;
use std::boxed::Box;
}
mod outer_arc {
- use crate::MyEnum;
use crate::MyStruct;
use crate::SubT;
use std::boxed::Box;
error: usage of `Box<Rc<T>>`
- --> $DIR/redundant_allocation.rs:25:30
+ --> $DIR/redundant_allocation.rs:17:30
|
LL | pub fn box_test6<T>(foo: Box<Rc<T>>) {}
| ^^^^^^^^^^
= help: consider using just `Box<T>` or `Rc<T>`
error: usage of `Box<Arc<T>>`
- --> $DIR/redundant_allocation.rs:27:30
+ --> $DIR/redundant_allocation.rs:19:30
|
LL | pub fn box_test7<T>(foo: Box<Arc<T>>) {}
| ^^^^^^^^^^^
= help: consider using just `Box<T>` or `Arc<T>`
error: usage of `Box<Rc<SubT<usize>>>`
- --> $DIR/redundant_allocation.rs:29:27
+ --> $DIR/redundant_allocation.rs:21:27
|
LL | pub fn box_test8() -> Box<Rc<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^
= help: consider using just `Box<SubT<usize>>` or `Rc<SubT<usize>>`
error: usage of `Box<Arc<T>>`
- --> $DIR/redundant_allocation.rs:33:30
+ --> $DIR/redundant_allocation.rs:25:30
|
LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
| ^^^^^^^^^^^
= help: consider using just `Box<T>` or `Arc<T>`
error: usage of `Box<Arc<SubT<T>>>`
- --> $DIR/redundant_allocation.rs:33:46
+ --> $DIR/redundant_allocation.rs:25:46
|
LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^^
= help: consider using just `Box<SubT<T>>` or `Arc<SubT<T>>`
error: usage of `Rc<Box<bool>>`
- --> $DIR/redundant_allocation.rs:46:24
+ --> $DIR/redundant_allocation.rs:37:24
|
LL | pub fn rc_test5(a: Rc<Box<bool>>) {}
| ^^^^^^^^^^^^^
= help: consider using just `Rc<bool>` or `Box<bool>`
error: usage of `Rc<Arc<bool>>`
- --> $DIR/redundant_allocation.rs:48:24
+ --> $DIR/redundant_allocation.rs:39:24
|
LL | pub fn rc_test7(a: Rc<Arc<bool>>) {}
| ^^^^^^^^^^^^^
= help: consider using just `Rc<bool>` or `Arc<bool>`
error: usage of `Rc<Box<SubT<usize>>>`
- --> $DIR/redundant_allocation.rs:50:26
+ --> $DIR/redundant_allocation.rs:41:26
|
LL | pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^
= help: consider using just `Rc<SubT<usize>>` or `Box<SubT<usize>>`
error: usage of `Rc<Arc<T>>`
- --> $DIR/redundant_allocation.rs:54:29
+ --> $DIR/redundant_allocation.rs:45:29
|
LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
| ^^^^^^^^^^
= help: consider using just `Rc<T>` or `Arc<T>`
error: usage of `Rc<Arc<SubT<T>>>`
- --> $DIR/redundant_allocation.rs:54:44
+ --> $DIR/redundant_allocation.rs:45:44
|
LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^
= help: consider using just `Rc<SubT<T>>` or `Arc<SubT<T>>`
error: usage of `Arc<Box<bool>>`
- --> $DIR/redundant_allocation.rs:67:25
+ --> $DIR/redundant_allocation.rs:57:25
|
LL | pub fn arc_test5(a: Arc<Box<bool>>) {}
| ^^^^^^^^^^^^^^
= help: consider using just `Arc<bool>` or `Box<bool>`
error: usage of `Arc<Rc<bool>>`
- --> $DIR/redundant_allocation.rs:69:25
+ --> $DIR/redundant_allocation.rs:59:25
|
LL | pub fn arc_test6(a: Arc<Rc<bool>>) {}
| ^^^^^^^^^^^^^
= help: consider using just `Arc<bool>` or `Rc<bool>`
error: usage of `Arc<Box<SubT<usize>>>`
- --> $DIR/redundant_allocation.rs:71:27
+ --> $DIR/redundant_allocation.rs:61:27
|
LL | pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^^
= help: consider using just `Arc<SubT<usize>>` or `Box<SubT<usize>>`
error: usage of `Arc<Rc<T>>`
- --> $DIR/redundant_allocation.rs:75:30
+ --> $DIR/redundant_allocation.rs:65:30
|
LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
| ^^^^^^^^^^
= help: consider using just `Arc<T>` or `Rc<T>`
error: usage of `Arc<Rc<SubT<T>>>`
- --> $DIR/redundant_allocation.rs:75:45
+ --> $DIR/redundant_allocation.rs:65:45
|
LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^
= help: consider using just `Arc<SubT<T>>` or `Rc<SubT<T>>`
error: usage of `Rc<Box<Box<dyn T>>>`
- --> $DIR/redundant_allocation.rs:97:27
+ --> $DIR/redundant_allocation.rs:87:27
|
LL | pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
| ^^^^^^^^^^^^^^^^^^^
= help: consider using just `Rc<Box<dyn T>>` or `Box<Box<dyn T>>`
error: usage of `Rc<Box<Box<str>>>`
- --> $DIR/redundant_allocation.rs:129:31
+ --> $DIR/redundant_allocation.rs:119:31
|
LL | pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
| ^^^^^^^^^^^^^^^^^
= help: consider using just `Rc<Box<str>>` or `Box<Box<str>>`
error: usage of `Rc<Box<Box<[usize]>>>`
- --> $DIR/redundant_allocation.rs:130:33
+ --> $DIR/redundant_allocation.rs:120:33
|
LL | pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^
= help: consider using just `Rc<Box<[usize]>>` or `Box<Box<[usize]>>`
error: usage of `Rc<Box<Box<Path>>>`
- --> $DIR/redundant_allocation.rs:131:32
+ --> $DIR/redundant_allocation.rs:121:32
|
LL | pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
| ^^^^^^^^^^^^^^^^^^
= help: consider using just `Rc<Box<Path>>` or `Box<Box<Path>>`
error: usage of `Rc<Box<Box<DynSized>>>`
- --> $DIR/redundant_allocation.rs:132:34
+ --> $DIR/redundant_allocation.rs:122:34
|
LL | pub fn test_rc_box_custom(_: Rc<Box<Box<DynSized>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^
// run-rustfix
#![warn(clippy::all)]
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(clippy::disallowed_names, unused_variables, dead_code)]
#![allow(unused_imports)]
pub struct MyStruct;
// run-rustfix
#![warn(clippy::all)]
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(clippy::disallowed_names, unused_variables, dead_code)]
#![allow(unused_imports)]
pub struct MyStruct;
// run-rustfix
+#![feature(async_closure)]
#![warn(clippy::redundant_closure_call)]
#![allow(unused)]
+async fn something() -> u32 {
+ 21
+}
+
+async fn something_else() -> u32 {
+ 2
+}
+
fn main() {
let a = 42;
+ let b = async {
+ let x = something().await;
+ let y = something_else().await;
+ x * y
+ };
+ let c = {
+ let x = 21;
+ let y = 2;
+ x * y
+ };
+ let d = async { something().await };
}
// run-rustfix
+#![feature(async_closure)]
#![warn(clippy::redundant_closure_call)]
#![allow(unused)]
+async fn something() -> u32 {
+ 21
+}
+
+async fn something_else() -> u32 {
+ 2
+}
+
fn main() {
let a = (|| 42)();
+ let b = (async || {
+ let x = something().await;
+ let y = something_else().await;
+ x * y
+ })();
+ let c = (|| {
+ let x = 21;
+ let y = 2;
+ x * y
+ })();
+ let d = (async || something().await)();
}
error: try not to call a closure in the expression where it is declared
- --> $DIR/redundant_closure_call_fixable.rs:7:13
+ --> $DIR/redundant_closure_call_fixable.rs:16:13
|
LL | let a = (|| 42)();
| ^^^^^^^^^ help: try doing something like: `42`
|
= note: `-D clippy::redundant-closure-call` implied by `-D warnings`
-error: aborting due to previous error
+error: try not to call a closure in the expression where it is declared
+ --> $DIR/redundant_closure_call_fixable.rs:17:13
+ |
+LL | let b = (async || {
+ | _____________^
+LL | | let x = something().await;
+LL | | let y = something_else().await;
+LL | | x * y
+LL | | })();
+ | |________^
+ |
+help: try doing something like
+ |
+LL ~ let b = async {
+LL + let x = something().await;
+LL + let y = something_else().await;
+LL + x * y
+LL ~ };
+ |
+
+error: try not to call a closure in the expression where it is declared
+ --> $DIR/redundant_closure_call_fixable.rs:22:13
+ |
+LL | let c = (|| {
+ | _____________^
+LL | | let x = 21;
+LL | | let y = 2;
+LL | | x * y
+LL | | })();
+ | |________^
+ |
+help: try doing something like
+ |
+LL ~ let c = {
+LL + let x = 21;
+LL + let y = 2;
+LL + x * y
+LL ~ };
+ |
+
+error: try not to call a closure in the expression where it is declared
+ --> $DIR/redundant_closure_call_fixable.rs:27:13
+ |
+LL | let d = (async || something().await)();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }`
+
+error: aborting due to 4 previous errors
// run-rustfix
+#![allow(clippy::disallowed_names)]
#![allow(clippy::blocks_in_if_conditions)]
#![allow(clippy::box_collection)]
#![allow(clippy::redundant_static_lifetimes)]
#![allow(clippy::for_loops_over_fallibles)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::match_result_ok)]
+#![allow(clippy::overly_complex_bool_expr)]
#![allow(clippy::new_without_default)]
#![allow(clippy::bind_instead_of_map)]
#![allow(clippy::expect_used)]
#![allow(temporary_cstring_as_ptr)]
#![allow(unknown_lints)]
#![allow(unused_labels)]
+#![warn(clippy::disallowed_names)]
#![warn(clippy::blocks_in_if_conditions)]
#![warn(clippy::blocks_in_if_conditions)]
#![warn(clippy::box_collection)]
#![warn(clippy::for_loops_over_fallibles)]
#![warn(clippy::useless_conversion)]
#![warn(clippy::match_result_ok)]
+#![warn(clippy::overly_complex_bool_expr)]
#![warn(clippy::new_without_default)]
#![warn(clippy::bind_instead_of_map)]
#![warn(clippy::expect_used)]
// run-rustfix
+#![allow(clippy::disallowed_names)]
#![allow(clippy::blocks_in_if_conditions)]
#![allow(clippy::box_collection)]
#![allow(clippy::redundant_static_lifetimes)]
#![allow(clippy::for_loops_over_fallibles)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::match_result_ok)]
+#![allow(clippy::overly_complex_bool_expr)]
#![allow(clippy::new_without_default)]
#![allow(clippy::bind_instead_of_map)]
#![allow(clippy::expect_used)]
#![allow(temporary_cstring_as_ptr)]
#![allow(unknown_lints)]
#![allow(unused_labels)]
+#![warn(clippy::blacklisted_name)]
#![warn(clippy::block_in_if_condition_expr)]
#![warn(clippy::block_in_if_condition_stmt)]
#![warn(clippy::box_vec)]
#![warn(clippy::for_loop_over_result)]
#![warn(clippy::identity_conversion)]
#![warn(clippy::if_let_some_result)]
+#![warn(clippy::logic_bug)]
#![warn(clippy::new_without_default_derive)]
#![warn(clippy::option_and_then_some)]
#![warn(clippy::option_expect_used)]
+error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
+ --> $DIR/rename.rs:38:9
+ |
+LL | #![warn(clippy::blacklisted_name)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
+ |
+ = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
- --> $DIR/rename.rs:36:9
+ --> $DIR/rename.rs:39:9
|
LL | #![warn(clippy::block_in_if_condition_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
- |
- = note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
- --> $DIR/rename.rs:37:9
+ --> $DIR/rename.rs:40:9
|
LL | #![warn(clippy::block_in_if_condition_stmt)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
- --> $DIR/rename.rs:38:9
+ --> $DIR/rename.rs:41:9
|
LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
- --> $DIR/rename.rs:39:9
+ --> $DIR/rename.rs:42:9
|
LL | #![warn(clippy::const_static_lifetime)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
- --> $DIR/rename.rs:40:9
+ --> $DIR/rename.rs:43:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
- --> $DIR/rename.rs:41:9
+ --> $DIR/rename.rs:44:9
|
LL | #![warn(clippy::disallowed_method)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
- --> $DIR/rename.rs:42:9
+ --> $DIR/rename.rs:45:9
|
LL | #![warn(clippy::disallowed_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
- --> $DIR/rename.rs:43:9
+ --> $DIR/rename.rs:46:9
|
LL | #![warn(clippy::eval_order_dependence)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
- --> $DIR/rename.rs:44:9
+ --> $DIR/rename.rs:47:9
|
LL | #![warn(clippy::for_loop_over_option)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
- --> $DIR/rename.rs:45:9
+ --> $DIR/rename.rs:48:9
|
LL | #![warn(clippy::for_loop_over_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
- --> $DIR/rename.rs:46:9
+ --> $DIR/rename.rs:49:9
|
LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
- --> $DIR/rename.rs:47:9
+ --> $DIR/rename.rs:50:9
|
LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
+error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
+ --> $DIR/rename.rs:51:9
+ |
+LL | #![warn(clippy::logic_bug)]
+ | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
+
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
- --> $DIR/rename.rs:48:9
+ --> $DIR/rename.rs:52:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
- --> $DIR/rename.rs:49:9
+ --> $DIR/rename.rs:53:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
- --> $DIR/rename.rs:50:9
+ --> $DIR/rename.rs:54:9
|
LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:51:9
+ --> $DIR/rename.rs:55:9
|
LL | #![warn(clippy::option_map_unwrap_or)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:52:9
+ --> $DIR/rename.rs:56:9
|
LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
- --> $DIR/rename.rs:53:9
+ --> $DIR/rename.rs:57:9
|
LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
- --> $DIR/rename.rs:54:9
+ --> $DIR/rename.rs:58:9
|
LL | #![warn(clippy::ref_in_deref)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
- --> $DIR/rename.rs:55:9
+ --> $DIR/rename.rs:59:9
|
LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
- --> $DIR/rename.rs:56:9
+ --> $DIR/rename.rs:60:9
|
LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
- --> $DIR/rename.rs:57:9
+ --> $DIR/rename.rs:61:9
|
LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
- --> $DIR/rename.rs:58:9
+ --> $DIR/rename.rs:62:9
|
LL | #![warn(clippy::single_char_push_str)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
- --> $DIR/rename.rs:59:9
+ --> $DIR/rename.rs:63:9
|
LL | #![warn(clippy::stutter)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
- --> $DIR/rename.rs:60:9
+ --> $DIR/rename.rs:64:9
|
LL | #![warn(clippy::to_string_in_display)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
- --> $DIR/rename.rs:61:9
+ --> $DIR/rename.rs:65:9
|
LL | #![warn(clippy::zero_width_space)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
- --> $DIR/rename.rs:62:9
+ --> $DIR/rename.rs:66:9
|
LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
- --> $DIR/rename.rs:63:9
+ --> $DIR/rename.rs:67:9
|
LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
- --> $DIR/rename.rs:64:9
+ --> $DIR/rename.rs:68:9
|
LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
- --> $DIR/rename.rs:65:9
+ --> $DIR/rename.rs:69:9
|
LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
- --> $DIR/rename.rs:66:9
+ --> $DIR/rename.rs:70:9
|
LL | #![warn(clippy::mem_discriminant_non_enum)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
- --> $DIR/rename.rs:67:9
+ --> $DIR/rename.rs:71:9
|
LL | #![warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
- --> $DIR/rename.rs:68:9
+ --> $DIR/rename.rs:72:9
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
- --> $DIR/rename.rs:69:9
+ --> $DIR/rename.rs:73:9
|
LL | #![warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
- --> $DIR/rename.rs:70:9
+ --> $DIR/rename.rs:74:9
|
LL | #![warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
-error: aborting due to 35 previous errors
+error: aborting due to 37 previous errors
}
let mut v = vec![1];
- if v.pop() == None {
+ if v.pop().is_none() {
//~ ERROR ifs same condition
- } else if v.pop() == None {
+ } else if v.pop().is_none() {
}
if v.len() == 42 {
error: this `if` has the same function call as a previous `if`
--> $DIR/same_functions_in_if_condition.rs:53:15
|
-LL | } else if v.pop() == None {
- | ^^^^^^^^^^^^^^^
+LL | } else if v.pop().is_none() {
+ | ^^^^^^^^^^^^^^^^^
|
note: same as this
--> $DIR/same_functions_in_if_condition.rs:51:8
|
-LL | if v.pop() == None {
- | ^^^^^^^^^^^^^^^
+LL | if v.pop().is_none() {
+ | ^^^^^^^^^^^^^^^^^
error: this `if` has the same function call as a previous `if`
--> $DIR/same_functions_in_if_condition.rs:58:15
// aux-build:option_helpers.rs
#![warn(clippy::skip_while_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
extern crate option_helpers;
use option_helpers::IteratorFalsePositives;
#![warn(clippy::all)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::no_effect,
clippy::redundant_clone,
redundant_semicolons,
#![warn(clippy::all)]
#![allow(
- clippy::blacklisted_name,
+ clippy::disallowed_names,
clippy::no_effect,
clippy::redundant_clone,
redundant_semicolons,
// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)"
#![deny(clippy::trivially_copy_pass_by_ref)]
-#![allow(clippy::blacklisted_name, clippy::redundant_field_names)]
+#![allow(clippy::disallowed_names, clippy::redundant_field_names)]
#[derive(Copy, Clone)]
struct Foo(u32);
+// aux-build: proc_macro_with_span.rs
+
#![warn(clippy::unit_arg)]
#![allow(
clippy::no_effect,
clippy::or_fun_call,
clippy::needless_question_mark,
clippy::self_named_constructors,
- clippy::let_unit_value
+ clippy::let_unit_value,
+ clippy::never_loop
)]
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
use std::fmt::Debug;
fn foo<T: Debug>(t: T) {
fn taking_multiple_units(a: (), b: ()) {}
+fn proc_macro() {
+ with_span!(span taking_multiple_units(unsafe { (); }, 'x: loop { break 'x (); }));
+}
+
fn main() {
bad();
ok();
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:57:5
+ --> $DIR/unit_arg.rs:63:5
|
LL | / foo({
LL | | 1;
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:60:5
+ --> $DIR/unit_arg.rs:66:5
|
LL | foo(foo(1));
| ^^^^^^^^^^^
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:61:5
+ --> $DIR/unit_arg.rs:67:5
|
LL | / foo({
LL | | foo(1);
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:66:5
+ --> $DIR/unit_arg.rs:72:5
|
LL | / b.bar({
LL | | 1;
|
error: passing unit values to a function
- --> $DIR/unit_arg.rs:69:5
+ --> $DIR/unit_arg.rs:75:5
|
LL | taking_multiple_units(foo(0), foo(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
error: passing unit values to a function
- --> $DIR/unit_arg.rs:70:5
+ --> $DIR/unit_arg.rs:76:5
|
LL | / taking_multiple_units(foo(0), {
LL | | foo(1);
|
error: passing unit values to a function
- --> $DIR/unit_arg.rs:74:5
+ --> $DIR/unit_arg.rs:80:5
|
LL | / taking_multiple_units(
LL | | {
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:85:13
+ --> $DIR/unit_arg.rs:91:13
|
LL | None.or(Some(foo(2)));
| ^^^^^^^^^^^^
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:88:5
+ --> $DIR/unit_arg.rs:94:5
|
LL | foo(foo(()));
| ^^^^^^^^^^^^
|
error: passing a unit value to a function
- --> $DIR/unit_arg.rs:125:5
+ --> $DIR/unit_arg.rs:131:5
|
LL | Some(foo(1))
| ^^^^^^^^^^^^
// run-rustfix
#![warn(clippy::unreadable_literal)]
+#![allow(unused_tuple_struct_fields)]
struct Foo(u64);
// run-rustfix
#![warn(clippy::unreadable_literal)]
+#![allow(unused_tuple_struct_fields)]
struct Foo(u64);
error: digits of hex or binary literal not grouped by four
- --> $DIR/unreadable_literal.rs:25:9
+ --> $DIR/unreadable_literal.rs:26:9
|
LL | 0x1_234_567,
| ^^^^^^^^^^^ help: consider: `0x0123_4567`
= note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:33:17
+ --> $DIR/unreadable_literal.rs:34:17
|
LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
| ^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
= note: `-D clippy::unreadable-literal` implied by `-D warnings`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:33:31
+ --> $DIR/unreadable_literal.rs:34:31
|
LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
| ^^^^^^^^^^^^^^^^ help: consider: `0x1234_5678_usize`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:33:49
+ --> $DIR/unreadable_literal.rs:34:49
|
LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
| ^^^^^^^^^^ help: consider: `123_456_f32`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:33:61
+ --> $DIR/unreadable_literal.rs:34:61
|
LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
| ^^^^^^^^^^^^ help: consider: `1.234_567_f32`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:35:20
+ --> $DIR/unreadable_literal.rs:36:20
|
LL | let _bad_sci = 1.123456e1;
| ^^^^^^^^^^ help: consider: `1.123_456e1`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:37:18
+ --> $DIR/unreadable_literal.rs:38:18
|
LL | let _fail1 = 0xabcdef;
| ^^^^^^^^ help: consider: `0x00ab_cdef`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:38:23
+ --> $DIR/unreadable_literal.rs:39:23
|
LL | let _fail2: u32 = 0xBAFEBAFE;
| ^^^^^^^^^^ help: consider: `0xBAFE_BAFE`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:39:18
+ --> $DIR/unreadable_literal.rs:40:18
|
LL | let _fail3 = 0xabcdeff;
| ^^^^^^^^^ help: consider: `0x0abc_deff`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:40:24
+ --> $DIR/unreadable_literal.rs:41:24
|
LL | let _fail4: i128 = 0xabcabcabcabcabcabc;
| ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc`
error: long literal lacking separators
- --> $DIR/unreadable_literal.rs:41:18
+ --> $DIR/unreadable_literal.rs:42:18
|
LL | let _fail5 = 1.100300400;
| ^^^^^^^^^^^ help: consider: `1.100_300_400`
--- /dev/null
+#![warn(clippy::unwrap_used, clippy::expect_used)]
+
+fn main() {
+ Some(3).unwrap();
+ Some(3).expect("Hello world!");
+
+ let a: Result<i32, i32> = Ok(3);
+ a.unwrap();
+ a.expect("Hello world!");
+}
--- /dev/null
+error: used `unwrap()` on `an Option` value
+ --> $DIR/unwrap_expect_used.rs:4:5
+ |
+LL | Some(3).unwrap();
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::unwrap-used` implied by `-D warnings`
+ = help: if this value is `None`, it will panic
+
+error: used `expect()` on `an Option` value
+ --> $DIR/unwrap_expect_used.rs:5:5
+ |
+LL | Some(3).expect("Hello world!");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::expect-used` implied by `-D warnings`
+ = help: if this value is `None`, it will panic
+
+error: used `unwrap()` on `a Result` value
+ --> $DIR/unwrap_expect_used.rs:8:5
+ |
+LL | a.unwrap();
+ | ^^^^^^^^^^
+ |
+ = help: if this value is an `Err`, it will panic
+
+error: used `expect()` on `a Result` value
+ --> $DIR/unwrap_expect_used.rs:9:5
+ |
+LL | a.expect("Hello world!");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: if this value is an `Err`, it will panic
+
+error: aborting due to 4 previous errors
+
#![feature(rustc_private)]
#![warn(clippy::all)]
-#![allow(clippy::blacklisted_name, clippy::eq_op)]
+#![allow(clippy::disallowed_names, clippy::eq_op)]
#![warn(clippy::used_underscore_binding)]
#[macro_use]
lazy_static = "1.0"
walkdir = "2"
glob = "0.3.0"
+lazycell = "1.3.0"
[target.'cfg(unix)'.dependencies]
libc = "0.2"
use std::ffi::OsString;
use std::fmt;
use std::path::{Path, PathBuf};
+use std::process::Command;
use std::str::FromStr;
use crate::util::PathBufExt;
+use lazycell::LazyCell;
use test::ColorConfig;
#[derive(Clone, Copy, PartialEq, Debug)]
/// Whether to rerun tests even if the inputs are unchanged.
pub force_rerun: bool,
+
+ pub target_cfg: LazyCell<TargetCfg>,
}
impl Config {
!self.target.ends_with("-fuchsia")
})
}
+
+ fn target_cfg(&self) -> &TargetCfg {
+ self.target_cfg.borrow_with(|| TargetCfg::new(&self.rustc_path, &self.target))
+ }
+
+ pub fn matches_arch(&self, arch: &str) -> bool {
+ self.target_cfg().arch == arch ||
+ // Shorthand for convenience. The arch for
+ // asmjs-unknown-emscripten is actually wasm32.
+ (arch == "asmjs" && self.target.starts_with("asmjs")) ||
+ // Matching all the thumb variants as one can be convenient.
+ // (thumbv6m, thumbv7em, thumbv7m, etc.)
+ (arch == "thumb" && self.target.starts_with("thumb"))
+ }
+
+ pub fn matches_os(&self, os: &str) -> bool {
+ self.target_cfg().os == os
+ }
+
+ pub fn matches_env(&self, env: &str) -> bool {
+ self.target_cfg().env == env
+ }
+
+ pub fn matches_abi(&self, abi: &str) -> bool {
+ self.target_cfg().abi == abi
+ }
+
+ pub fn matches_family(&self, family: &str) -> bool {
+ self.target_cfg().families.iter().any(|f| f == family)
+ }
+
+ pub fn is_big_endian(&self) -> bool {
+ self.target_cfg().endian == Endian::Big
+ }
+
+ pub fn get_pointer_width(&self) -> u32 {
+ *&self.target_cfg().pointer_width
+ }
+
+ pub fn has_asm_support(&self) -> bool {
+ static ASM_SUPPORTED_ARCHS: &[&str] = &[
+ "x86", "x86_64", "arm", "aarch64", "riscv32",
+ "riscv64",
+ // These targets require an additional asm_experimental_arch feature.
+ // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
+ ];
+ ASM_SUPPORTED_ARCHS.contains(&self.target_cfg().arch.as_str())
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct TargetCfg {
+ arch: String,
+ os: String,
+ env: String,
+ abi: String,
+ families: Vec<String>,
+ pointer_width: u32,
+ endian: Endian,
+}
+
+#[derive(Eq, PartialEq, Clone, Debug)]
+pub enum Endian {
+ Little,
+ Big,
+}
+
+impl TargetCfg {
+ fn new(rustc_path: &Path, target: &str) -> TargetCfg {
+ let output = match Command::new(rustc_path)
+ .arg("--print=cfg")
+ .arg("--target")
+ .arg(target)
+ .output()
+ {
+ Ok(output) => output,
+ Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", rustc_path),
+ };
+ if !output.status.success() {
+ panic!(
+ "error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}",
+ rustc_path,
+ String::from_utf8(output.stdout).unwrap(),
+ String::from_utf8(output.stderr).unwrap(),
+ );
+ }
+ let print_cfg = String::from_utf8(output.stdout).unwrap();
+ let mut arch = None;
+ let mut os = None;
+ let mut env = None;
+ let mut abi = None;
+ let mut families = Vec::new();
+ let mut pointer_width = None;
+ let mut endian = None;
+ for line in print_cfg.lines() {
+ if let Some((name, value)) = line.split_once('=') {
+ let value = value.trim_matches('"');
+ match name {
+ "target_arch" => arch = Some(value),
+ "target_os" => os = Some(value),
+ "target_env" => env = Some(value),
+ "target_abi" => abi = Some(value),
+ "target_family" => families.push(value.to_string()),
+ "target_pointer_width" => pointer_width = Some(value.parse().unwrap()),
+ "target_endian" => {
+ endian = Some(match value {
+ "little" => Endian::Little,
+ "big" => Endian::Big,
+ s => panic!("unexpected {s}"),
+ })
+ }
+ _ => {}
+ }
+ }
+ }
+ TargetCfg {
+ arch: arch.unwrap().to_string(),
+ os: os.unwrap().to_string(),
+ env: env.unwrap().to_string(),
+ abi: abi.unwrap().to_string(),
+ families,
+ pointer_width: pointer_width.unwrap(),
+ endian: endian.unwrap(),
+ }
+ }
}
#[derive(Debug, Clone)]
let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap();
+ let matches_pointer_width = || {
+ name.strip_suffix("bit")
+ .and_then(|width| width.parse::<u32>().ok())
+ .map(|width| self.get_pointer_width() == width)
+ .unwrap_or(false)
+ };
+
+ // If something is ignored for emscripten, it likely also needs to be
+ // ignored for wasm32-unknown-unknown.
+ // `wasm32-bare` is an alias to refer to just wasm32-unknown-unknown
+ // (in contrast to `wasm32` which also matches non-bare targets like
+ // asmjs-unknown-emscripten).
+ let matches_wasm32_alias = || {
+ self.target == "wasm32-unknown-unknown" && matches!(name, "emscripten" | "wasm32-bare")
+ };
+
let is_match = name == "test" ||
self.target == name || // triple
- util::matches_os(&self.target, name) || // target
- util::matches_env(&self.target, name) || // env
+ self.matches_os(name) ||
+ self.matches_env(name) ||
+ self.matches_abi(name) ||
+ self.matches_family(name) ||
self.target.ends_with(name) || // target and env
- name == util::get_arch(&self.target) || // architecture
- name == util::get_pointer_width(&self.target) || // pointer width
+ self.matches_arch(name) ||
+ matches_wasm32_alias() ||
+ matches_pointer_width() ||
name == self.stage_id.split('-').next().unwrap() || // stage
name == self.channel || // channel
(self.target != self.host && name == "cross-compile") ||
- (name == "endian-big" && util::is_big_endian(&self.target)) ||
+ (name == "endian-big" && self.is_big_endian()) ||
(self.remote_test_client.is_some() && name == "remote") ||
match self.compare_mode {
Some(CompareMode::Polonius) => name == "compare-mode-polonius",
let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
- let has_asm_support = util::has_asm_support(&config.target);
+ let has_asm_support = config.has_asm_support();
let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target);
let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
"--suite=ui",
"--compile-lib-path=",
"--run-lib-path=",
- "--rustc-path=",
"--python=",
"--jsondocck-path=",
"--src-base=",
"--target=x86_64-unknown-linux-gnu",
"--channel=nightly",
];
- let args = args.iter().map(ToString::to_string).collect();
+ let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
+ args.push("--rustc-path".to_string());
+ // This is a subtle/fragile thing. On rust-lang CI, there is no global
+ // `rustc`, and Cargo doesn't offer a convenient way to get the path to
+ // `rustc`. Fortunately bootstrap sets `RUSTC` for us, which is pointing
+ // to the stage0 compiler.
+ //
+ // Otherwise, if you are running compiletests's tests manually, you
+ // probably don't have `RUSTC` set, in which case this falls back to the
+ // global rustc. If your global rustc is too far out of sync with stage0,
+ // then this may cause confusing errors. Or if for some reason you don't
+ // have rustc in PATH, that would also fail.
+ args.push(std::env::var("RUSTC").unwrap_or_else(|_| {
+ eprintln!(
+ "warning: RUSTC not set, using global rustc (are you not running via bootstrap?)"
+ );
+ "rustc".to_string()
+ }));
crate::parse_config(args)
}
#[test]
fn asm_support() {
- let mut config = config();
-
- config.target = "avr-unknown-gnu-atmega328".to_owned();
- assert!(check_ignore(&config, "// needs-asm-support"));
-
- config.target = "i686-unknown-netbsd".to_owned();
- assert!(!check_ignore(&config, "// needs-asm-support"));
+ let asms = [
+ ("avr-unknown-gnu-atmega328", false),
+ ("i686-unknown-netbsd", true),
+ ("riscv32gc-unknown-linux-gnu", true),
+ ("riscv64imac-unknown-none-elf", true),
+ ("x86_64-unknown-linux-gnu", true),
+ ("i686-unknown-netbsd", true),
+ ];
+ for (target, has_asm) in asms {
+ let mut config = config();
+ config.target = target.to_string();
+ assert_eq!(config.has_asm_support(), has_asm);
+ assert_eq!(check_ignore(&config, "// needs-asm-support"), !has_asm)
+ }
}
#[test]
let config = config();
parse_rs(&config, "// revisions: rpass1 rpass1");
}
+
+#[test]
+fn ignore_arch() {
+ let archs = [
+ ("x86_64-unknown-linux-gnu", "x86_64"),
+ ("i686-unknown-linux-gnu", "x86"),
+ ("nvptx64-nvidia-cuda", "nvptx64"),
+ ("asmjs-unknown-emscripten", "wasm32"),
+ ("asmjs-unknown-emscripten", "asmjs"),
+ ("thumbv7m-none-eabi", "thumb"),
+ ];
+ for (target, arch) in archs {
+ let mut config = config();
+ config.target = target.to_string();
+ assert!(config.matches_arch(arch), "{target} {arch}");
+ assert!(check_ignore(&config, &format!("// ignore-{arch}")));
+ }
+}
+
+#[test]
+fn matches_os() {
+ let oss = [
+ ("x86_64-unknown-linux-gnu", "linux"),
+ ("x86_64-fortanix-unknown-sgx", "unknown"),
+ ("wasm32-unknown-unknown", "unknown"),
+ ("x86_64-unknown-none", "none"),
+ ];
+ for (target, os) in oss {
+ let mut config = config();
+ config.target = target.to_string();
+ assert!(config.matches_os(os), "{target} {os}");
+ assert!(check_ignore(&config, &format!("// ignore-{os}")));
+ }
+}
+
+#[test]
+fn matches_env() {
+ let envs = [
+ ("x86_64-unknown-linux-gnu", "gnu"),
+ ("x86_64-fortanix-unknown-sgx", "sgx"),
+ ("arm-unknown-linux-musleabi", "musl"),
+ ];
+ for (target, env) in envs {
+ let mut config = config();
+ config.target = target.to_string();
+ assert!(config.matches_env(env), "{target} {env}");
+ assert!(check_ignore(&config, &format!("// ignore-{env}")));
+ }
+}
+
+#[test]
+fn matches_abi() {
+ let abis = [
+ ("aarch64-apple-ios-macabi", "macabi"),
+ ("x86_64-unknown-linux-gnux32", "x32"),
+ ("arm-unknown-linux-gnueabi", "eabi"),
+ ];
+ for (target, abi) in abis {
+ let mut config = config();
+ config.target = target.to_string();
+ assert!(config.matches_abi(abi), "{target} {abi}");
+ assert!(check_ignore(&config, &format!("// ignore-{abi}")));
+ }
+}
+
+#[test]
+fn is_big_endian() {
+ let endians = [
+ ("x86_64-unknown-linux-gnu", false),
+ ("bpfeb-unknown-none", true),
+ ("m68k-unknown-linux-gnu", true),
+ ("aarch64_be-unknown-linux-gnu", true),
+ ("powerpc64-unknown-linux-gnu", true),
+ ];
+ for (target, is_big) in endians {
+ let mut config = config();
+ config.target = target.to_string();
+ assert_eq!(config.is_big_endian(), is_big, "{target} {is_big}");
+ assert_eq!(check_ignore(&config, "// ignore-endian-big"), is_big);
+ }
+}
+
+#[test]
+fn pointer_width() {
+ let widths = [
+ ("x86_64-unknown-linux-gnu", 64),
+ ("i686-unknown-linux-gnu", 32),
+ ("arm64_32-apple-watchos", 32),
+ ("msp430-none-elf", 16),
+ ];
+ for (target, width) in widths {
+ let mut config = config();
+ config.target = target.to_string();
+ assert_eq!(config.get_pointer_width(), width, "{target} {width}");
+ assert_eq!(check_ignore(&config, "// ignore-16bit"), width == 16);
+ assert_eq!(check_ignore(&config, "// ignore-32bit"), width == 32);
+ assert_eq!(check_ignore(&config, "// ignore-64bit"), width == 64);
+ }
+}
+
+#[test]
+fn wasm_special() {
+ let ignores = [
+ ("wasm32-unknown-unknown", "emscripten", true),
+ ("wasm32-unknown-unknown", "wasm32", true),
+ ("wasm32-unknown-unknown", "wasm32-bare", true),
+ ("wasm32-unknown-unknown", "wasm64", false),
+ ("asmjs-unknown-emscripten", "emscripten", true),
+ ("asmjs-unknown-emscripten", "wasm32", true),
+ ("asmjs-unknown-emscripten", "wasm32-bare", false),
+ ("wasm32-unknown-emscripten", "emscripten", true),
+ ("wasm32-unknown-emscripten", "wasm32", true),
+ ("wasm32-unknown-emscripten", "wasm32-bare", false),
+ ("wasm32-wasi", "emscripten", false),
+ ("wasm32-wasi", "wasm32", true),
+ ("wasm32-wasi", "wasm32-bare", false),
+ ("wasm32-wasi", "wasi", true),
+ ("wasm64-unknown-unknown", "emscripten", false),
+ ("wasm64-unknown-unknown", "wasm32", false),
+ ("wasm64-unknown-unknown", "wasm32-bare", false),
+ ("wasm64-unknown-unknown", "wasm64", true),
+ ];
+ for (target, pattern, ignore) in ignores {
+ let mut config = config();
+ config.target = target.to_string();
+ assert_eq!(
+ check_ignore(&config, &format!("// ignore-{pattern}")),
+ ignore,
+ "{target} {pattern}"
+ );
+ }
+}
+
+#[test]
+fn families() {
+ let families = [
+ ("x86_64-unknown-linux-gnu", "unix"),
+ ("x86_64-pc-windows-gnu", "windows"),
+ ("wasm32-unknown-unknown", "wasm"),
+ ("wasm32-unknown-emscripten", "wasm"),
+ ("wasm32-unknown-emscripten", "unix"),
+ ];
+ for (target, family) in families {
+ let mut config = config();
+ config.target = target.to_string();
+ assert!(config.matches_family(family));
+ let other = if family == "windows" { "unix" } else { "windows" };
+ assert!(!config.matches_family(other));
+ assert!(check_ignore(&config, &format!("// ignore-{family}")));
+ assert!(!check_ignore(&config, &format!("// ignore-{other}")));
+ }
+}
use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, TestPaths};
use crate::util::logv;
use getopts::Options;
+use lazycell::LazyCell;
use std::env;
use std::ffi::OsString;
use std::fs;
npm: matches.opt_str("npm"),
force_rerun: matches.opt_present("force-rerun"),
+
+ target_cfg: LazyCell::new(),
}
}
fn configure_gdb(config: &Config) -> Option<Config> {
config.gdb_version?;
- if util::matches_env(&config.target, "msvc") {
+ if config.matches_env("msvc") {
return None;
}
use crate::header::TestProps;
use crate::json;
use crate::read2::read2_abbreviated;
-use crate::util::get_pointer_width;
use crate::util::{logv, PathBufExt};
use crate::ColorConfig;
use regex::{Captures, Regex};
output_kind: TestOutput,
explicit_format: bool,
) -> usize {
- let stderr_bits = format!("{}.stderr", get_pointer_width(&self.config.target));
+ let stderr_bits = format!("{}bit.stderr", self.config.get_pointer_width());
let (stderr_kind, stdout_kind) = match output_kind {
TestOutput::Compile => (
{
let mut bit_width = String::new();
if test_file_contents.lines().any(|l| l == "// EMIT_MIR_FOR_EACH_BIT_WIDTH") {
- bit_width = format!(".{}", get_pointer_width(&self.config.target));
+ bit_width = format!(".{}bit", self.config.get_pointer_width());
}
if self.config.bless {
#[cfg(test)]
mod tests;
-/// Conversion table from triple OS name to Rust SYSNAME
-const OS_TABLE: &[(&str, &str)] = &[
- ("android", "android"),
- ("androideabi", "android"),
- ("cuda", "cuda"),
- ("darwin", "macos"),
- ("dragonfly", "dragonfly"),
- ("emscripten", "emscripten"),
- ("freebsd", "freebsd"),
- ("fuchsia", "fuchsia"),
- ("haiku", "haiku"),
- ("hermit", "hermit"),
- ("illumos", "illumos"),
- ("ios", "ios"),
- ("l4re", "l4re"),
- ("linux", "linux"),
- ("mingw32", "windows"),
- ("none", "none"),
- ("netbsd", "netbsd"),
- ("openbsd", "openbsd"),
- ("redox", "redox"),
- ("sgx", "sgx"),
- ("solaris", "solaris"),
- ("watchos", "watchos"),
- ("win32", "windows"),
- ("windows", "windows"),
- ("vxworks", "vxworks"),
-];
-
-const ARCH_TABLE: &[(&str, &str)] = &[
- ("aarch64", "aarch64"),
- ("aarch64_be", "aarch64"),
- ("amd64", "x86_64"),
- ("arm", "arm"),
- ("arm64", "aarch64"),
- ("armv4t", "arm"),
- ("armv5te", "arm"),
- ("armv7", "arm"),
- ("armv7s", "arm"),
- ("asmjs", "asmjs"),
- ("avr", "avr"),
- ("bpfeb", "bpf"),
- ("bpfel", "bpf"),
- ("hexagon", "hexagon"),
- ("i386", "x86"),
- ("i586", "x86"),
- ("i686", "x86"),
- ("m68k", "m68k"),
- ("mips", "mips"),
- ("mips64", "mips64"),
- ("mips64el", "mips64"),
- ("mipsisa32r6", "mips"),
- ("mipsisa32r6el", "mips"),
- ("mipsisa64r6", "mips64"),
- ("mipsisa64r6el", "mips64"),
- ("mipsel", "mips"),
- ("mipsisa32r6", "mips"),
- ("mipsisa32r6el", "mips"),
- ("mipsisa64r6", "mips64"),
- ("mipsisa64r6el", "mips64"),
- ("msp430", "msp430"),
- ("nvptx64", "nvptx64"),
- ("powerpc", "powerpc"),
- ("powerpc64", "powerpc64"),
- ("powerpc64le", "powerpc64"),
- ("riscv64gc", "riscv64"),
- ("s390x", "s390x"),
- ("sparc", "sparc"),
- ("sparc64", "sparc64"),
- ("sparcv9", "sparc64"),
- ("thumbv6m", "thumb"),
- ("thumbv7em", "thumb"),
- ("thumbv7m", "thumb"),
- ("wasm32", "wasm32"),
- ("x86_64", "x86_64"),
- ("xcore", "xcore"),
-];
-
pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
"aarch64-apple-darwin",
"aarch64-fuchsia",
pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"];
-const BIG_ENDIAN: &[&str] = &[
- "aarch64_be",
- "armebv7r",
- "mips",
- "mips64",
- "mipsisa32r6",
- "mipsisa64r6",
- "powerpc",
- "powerpc64",
- "s390x",
- "sparc",
- "sparc64",
- "sparcv9",
-];
-
-static ASM_SUPPORTED_ARCHS: &[&str] = &[
- "x86", "x86_64", "arm", "aarch64", "riscv32",
- "riscv64",
- // These targets require an additional asm_experimental_arch feature.
- // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
-];
-
-pub fn has_asm_support(triple: &str) -> bool {
- ASM_SUPPORTED_ARCHS.contains(&get_arch(triple))
-}
-
-pub fn matches_os(triple: &str, name: &str) -> bool {
- // For the wasm32 bare target we ignore anything also ignored on emscripten
- // and then we also recognize `wasm32-bare` as the os for the target
- if triple == "wasm32-unknown-unknown" {
- return name == "emscripten" || name == "wasm32-bare";
- }
- let triple: Vec<_> = triple.split('-').collect();
- for &(triple_os, os) in OS_TABLE {
- if triple.contains(&triple_os) {
- return os == name;
- }
- }
- panic!("Cannot determine OS from triple");
-}
-
-/// Determine the architecture from `triple`
-pub fn get_arch(triple: &str) -> &'static str {
- let triple: Vec<_> = triple.split('-').collect();
- for &(triple_arch, arch) in ARCH_TABLE {
- if triple.contains(&triple_arch) {
- return arch;
- }
- }
- panic!("Cannot determine Architecture from triple");
-}
-
-/// Determine the endianness from `triple`
-pub fn is_big_endian(triple: &str) -> bool {
- let triple_arch = triple.split('-').next().unwrap();
- BIG_ENDIAN.contains(&triple_arch)
-}
-
-pub fn matches_env(triple: &str, name: &str) -> bool {
- if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false }
-}
-
-pub fn get_pointer_width(triple: &str) -> &'static str {
- if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32"))
- || triple.starts_with("s390x")
- {
- "64bit"
- } else if triple.starts_with("avr") {
- "16bit"
- } else {
- "32bit"
- }
-}
-
pub fn make_new_path(path: &str) -> String {
assert!(cfg!(windows));
// Windows just uses PATH as the library search path, so we have to
use super::*;
-#[test]
-#[should_panic(expected = "Cannot determine Architecture from triple")]
-fn test_get_arch_failure() {
- get_arch("abc");
-}
-
-#[test]
-fn test_get_arch() {
- assert_eq!("x86_64", get_arch("x86_64-unknown-linux-gnu"));
- assert_eq!("x86_64", get_arch("amd64"));
- assert_eq!("nvptx64", get_arch("nvptx64-nvidia-cuda"));
-}
-
-#[test]
-#[should_panic(expected = "Cannot determine OS from triple")]
-fn test_matches_os_failure() {
- matches_os("abc", "abc");
-}
-
-#[test]
-fn test_matches_os() {
- assert!(matches_os("x86_64-unknown-linux-gnu", "linux"));
- assert!(matches_os("wasm32-unknown-unknown", "emscripten"));
- assert!(matches_os("wasm32-unknown-unknown", "wasm32-bare"));
- assert!(!matches_os("wasm32-unknown-unknown", "windows"));
- assert!(matches_os("thumbv6m0-none-eabi", "none"));
- assert!(matches_os("riscv32imc-unknown-none-elf", "none"));
- assert!(matches_os("nvptx64-nvidia-cuda", "cuda"));
- assert!(matches_os("x86_64-fortanix-unknown-sgx", "sgx"));
-}
-
-#[test]
-fn is_big_endian_test() {
- assert!(!is_big_endian("no"));
- assert!(is_big_endian("sparc-unknown-unknown"));
-}
-
#[test]
fn path_buf_with_extra_extension_test() {
assert_eq!(
[dependencies]
walkdir = "2"
+rayon = "1.5"
+use rayon::iter::{ParallelBridge, ParallelIterator};
use std::env;
use std::path::Path;
use std::process::{Command, Output};
// Returns the number of files read and the number of errors.
fn find_all_html_files(dir: &Path) -> (usize, usize) {
- let mut files_read = 0;
- let mut errors = 0;
-
- for entry in walkdir::WalkDir::new(dir).into_iter().filter_entry(|e| {
- e.depth() != 1
- || e.file_name()
- .to_str()
- .map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
- .unwrap_or(false)
- }) {
- let entry = entry.expect("failed to read file");
- if !entry.file_type().is_file() {
- continue;
- }
- let entry = entry.path();
- if entry.extension().and_then(|s| s.to_str()) == Some("html") {
- errors += check_html_file(&entry);
- files_read += 1;
- }
- }
- (files_read, errors)
+ walkdir::WalkDir::new(dir)
+ .into_iter()
+ .filter_entry(|e| {
+ e.depth() != 1
+ || e.file_name()
+ .to_str()
+ .map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
+ .unwrap_or(false)
+ })
+ .par_bridge()
+ .map(|entry| {
+ let entry = entry.expect("failed to read file");
+ if !entry.file_type().is_file() {
+ return (0, 0);
+ }
+ let entry = entry.path();
+ // (Number of files processed, number of errors)
+ if entry.extension().and_then(|s| s.to_str()) == Some("html") {
+ (1, check_html_file(&entry))
+ } else {
+ (0, 0)
+ }
+ })
+ .reduce(|| (0, 0), |a, b| (a.0 + b.0, a.1 + b.1))
}
/// Default `tidy` command for macOS is too old that it does not have `mute-id` and `mute` options.
-Subproject commit b938529fb8ed8f7b5b374282ffc3ffa74c313111
+Subproject commit 39ee5747153bf13324870c4a912acbf1f9bfde3f
-Subproject commit fcf1f94c9ab2acc18cfd4368a4aeb38e77da9649
+Subproject commit 4d8b0a19986a4daab37287a5b5fe2da0775d1873
Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
-->
-**rust-analyzer version**: (eg. output of "Rust Analyzer: Show RA Version" command)
+**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via <kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>)
**rustc version**: (eg. output of `rustc -V`)
git config --global user.email "runner@gha.local"
git config --global user.name "Github Action"
rm Cargo.lock
+ # Fix names for crates that were published before switch to kebab-case.
+ cargo workspaces rename --from base-db base_db
+ cargo workspaces rename --from hir-def hir_def
+ cargo workspaces rename --from hir-expand hir_expand
+ cargo workspaces rename --from hir-ty hir_ty
+ cargo workspaces rename --from ide-assists ide_assists
+ cargo workspaces rename --from ide-completion ide_completion
+ cargo workspaces rename --from ide-db ide_db
+ cargo workspaces rename --from ide-diagnostics ide_diagnostics
+ cargo workspaces rename --from ide-ssr ide_ssr
+ cargo workspaces rename --from proc-macro-api proc_macro_api
+ cargo workspaces rename --from proc-macro-srv proc_macro_srv
+ cargo workspaces rename --from project-model project_model
+ cargo workspaces rename --from test-utils test_utils
+ cargo workspaces rename --from text-edit text_edit
cargo workspaces rename ra_ap_%n
find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} +
- # Fix names for crates that were published before switch to kebab-case.
- find crates -name 'Cargo.toml' -exec sed -i "s/ra_ap_base-db/ra_ap_base_db/g; s/ra_ap_hir-def/ra_ap_hir_def/g; s/ra_ap_hir-expand/ra_ap_hir_expand/g; s/ra_ap_hir-ty/ra_ap_hir_ty/g; s/ra_ap_ide-assists/ra_ap_ide_assists/g; s/ra_ap_ide-completion/ra_ap_ide_completion/g; s/ra_ap_ide-db/ra_ap_ide_db/g; s/ra_ap_ide-diagnostics/ra_ap_ide_diagnostics/g; s/ra_ap_ide-ssr/ra_ap_ide_ssr/g; s/ra_ap_proc-macro-api/ra_ap_proc_macro_api/g; s/ra_ap_proc-macro-srv/ra_ap_proc_macro_srv/g; s/ra_ap_project-model/ra_ap_project_model/g; s/ra_ap_test-utils/ra_ap_test_utils/g; s/ra_ap_text-edit/ra_ap_text_edit/g" {} +
cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH
FETCH_DEPTH: 0 # pull in the tags for the version string
MACOSX_DEPLOYMENT_TARGET: 10.15
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
+ CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
jobs:
dist:
- os: ubuntu-18.04
target: aarch64-unknown-linux-gnu
code-target: linux-arm64
+ - os: ubuntu-18.04
+ target: arm-unknown-linux-gnueabihf
+ code-target: linux-armhf
- os: macos-11
target: x86_64-apple-darwin
code-target: darwin-x64
node-version: 14.x
- name: Update apt repositories
- if: matrix.target == 'aarch64-unknown-linux-gnu'
+ if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
run: sudo apt-get update
- - name: Install target toolchain
+ - name: Install AArch64 target toolchain
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: sudo apt-get install gcc-aarch64-linux-gnu
+ - name: Install ARM target toolchain
+ if: matrix.target == 'arm-unknown-linux-gnueabihf'
+ run: sudo apt-get install gcc-arm-linux-gnueabihf
+
- name: Dist
run: cargo xtask dist --client-patch-version ${{ github.run_number }}
with:
name: dist-aarch64-unknown-linux-gnu
path: dist
+ - uses: actions/download-artifact@v1
+ with:
+ name: dist-arm-unknown-linux-gnueabihf
+ path: dist
- uses: actions/download-artifact@v1
with:
name: dist-x86_64-pc-windows-msvc
## License
-Rust analyzer is primarily distributed under the terms of both the MIT
+rust-analyzer is primarily distributed under the terms of both the MIT
license and the Apache License (Version 2.0).
See LICENSE-APACHE and LICENSE-MIT for details.
// XXX: drop order is significant
sender: Sender<Restart>,
_thread: jod_thread::JoinHandle,
+ id: usize,
}
impl FlycheckHandle {
.name("Flycheck".to_owned())
.spawn(move || actor.run(receiver))
.expect("failed to spawn thread");
- FlycheckHandle { sender, _thread: thread }
+ FlycheckHandle { id, sender, _thread: thread }
}
/// Schedule a re-start of the cargo check worker.
pub fn update(&self) {
self.sender.send(Restart).unwrap();
}
+
+ pub fn id(&self) -> usize {
+ self.id
+ }
}
pub enum Message {
/// Request adding a diagnostic with fixes included to a file
- AddDiagnostic { workspace_root: AbsPathBuf, diagnostic: Diagnostic },
+ AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic },
/// Request check progress notification to client
Progress {
impl fmt::Debug for Message {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- Message::AddDiagnostic { workspace_root, diagnostic } => f
+ Message::AddDiagnostic { id, workspace_root, diagnostic } => f
.debug_struct("AddDiagnostic")
+ .field("id", id)
.field("workspace_root", workspace_root)
.field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
.finish(),
}
}
Event::CheckEvent(None) => {
- tracing::debug!("flycheck finished");
+ tracing::debug!(flycheck_id = self.id, "flycheck finished");
// Watcher finished
let cargo_handle = self.cargo_handle.take().unwrap();
CargoMessage::Diagnostic(msg) => {
self.send(Message::AddDiagnostic {
+ id: self.id,
workspace_root: self.workspace_root.clone(),
diagnostic: msg,
});
pub(crate) fn merge(&self, other: Self) -> Self {
// FIXME: This needs to fixup `AttrId`s
- match (&self.entries, &other.entries) {
+ match (&self.entries, other.entries) {
(None, None) => Self::EMPTY,
- (Some(entries), None) | (None, Some(entries)) => {
- Self { entries: Some(entries.clone()) }
- }
+ (None, entries @ Some(_)) => Self { entries },
+ (Some(entries), None) => Self { entries: Some(entries.clone()) },
(Some(a), Some(b)) => {
- Self { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
+ let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1);
+ Self {
+ entries: Some(
+ a.iter()
+ .cloned()
+ .chain(b.iter().map(|it| {
+ let mut it = it.clone();
+ it.id.ast_index += last_ast_index;
+ it
+ }))
+ .collect(),
+ ),
+ }
}
}
}
if let GenericDefId::TraitId(id) = *self {
let trait_ref = id.lookup(db).source(db).value;
let idx = idx_iter.next().unwrap();
- params.insert(idx, Either::Right(trait_ref))
+ params.insert(idx, Either::Right(trait_ref));
}
if let Some(generic_params_list) = generic_params_list {
use base_db::CrateId;
use hir_expand::{name::Name, AstId, MacroCallId};
+use itertools::Itertools;
use once_cell::sync::Lazy;
use profile::Count;
use rustc_hash::{FxHashMap, FxHashSet};
impl ItemScope {
pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
// FIXME: shadowing
- let keys: FxHashSet<_> = self
- .types
+ self.types
.keys()
.chain(self.values.keys())
.chain(self.macros.keys())
.chain(self.unresolved.iter())
- .collect();
-
- keys.into_iter().map(move |name| (name, self.get(name)))
+ .sorted()
+ .unique()
+ .map(move |name| (name, self.get(name)))
}
pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
//! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`).
//!
//! The `ItemTree` for the currently open file can be displayed by using the VS Code command
-//! "Rust Analyzer: Debug ItemTree".
+//! "rust-analyzer: Debug ItemTree".
//!
//! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many
//! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name
};
let mut res = ReachedFixedPoint::Yes;
macros.retain(|directive| {
- let resolver2 = |path| {
+ let resolver = |path| {
let resolved_res = self.def_map.resolve_path_fp_with_macro(
self.db,
ResolveMode::Other,
.take_macros()
.map(|it| (it, macro_id_to_def_id(self.db, it)))
};
- let resolver = |path| resolver2(path).map(|(_, it)| it);
+ let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
match &directive.kind {
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
ast_id,
*expand_to,
self.def_map.krate,
- &resolver,
+ &resolver_def_id,
&mut |_err| (),
);
if let Ok(Ok(call_id)) = call_id {
*derive_attr,
*derive_pos as u32,
self.def_map.krate,
- &resolver2,
+ &resolver,
);
if let Ok((macro_id, def_id, call_id)) = id {
}
}
- let def = match resolver(path.clone()) {
+ let def = match resolver_def_id(path.clone()) {
Some(def) if def.is_attribute() => def,
_ => return true,
};
true
});
// Attribute resolution can add unresolved macro invocations, so concatenate the lists.
- self.unresolved_macros.extend(macros);
+ macros.extend(mem::take(&mut self.unresolved_macros));
+ self.unresolved_macros = macros;
for (module_id, depth, container, macro_call_id) in resolved {
self.collect_macro_expansion(module_id, macro_call_id, depth, container);
let resolver = variant_id.module(db).resolver(db);
let mut res = ArenaMap::default();
for (field_id, field_data) in var_data.fields().iter() {
- res.insert(field_id, field_data.visibility.resolve(db, &resolver))
+ res.insert(field_id, field_data.visibility.resolve(db, &resolver));
}
Arc::new(res)
}
use mbe::{SyntheticToken, SyntheticTokenId, TokenMap};
use rustc_hash::FxHashMap;
use syntax::{
- ast::{self, AstNode},
+ ast::{self, AstNode, HasLoopBody},
match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
};
use tt::Subtree;
]);
}
},
+ ast::WhileExpr(it) => {
+ if it.condition().is_none() {
+ // insert placeholder token after the while token
+ let while_token = match it.while_token() {
+ Some(t) => t,
+ None => continue,
+ };
+ append.insert(while_token.into(), vec![
+ SyntheticToken {
+ kind: SyntaxKind::IDENT,
+ text: "__ra_fixup".into(),
+ range: end_range,
+ id: EMPTY_ID,
+ },
+ ]);
+ }
+ if it.loop_body().is_none() {
+ append.insert(node.clone().into(), vec![
+ SyntheticToken {
+ kind: SyntaxKind::L_CURLY,
+ text: "{".into(),
+ range: end_range,
+ id: EMPTY_ID,
+ },
+ SyntheticToken {
+ kind: SyntaxKind::R_CURLY,
+ text: "}".into(),
+ range: end_range,
+ id: EMPTY_ID,
+ },
+ ]);
+ }
+ },
+ ast::LoopExpr(it) => {
+ if it.loop_body().is_none() {
+ append.insert(node.clone().into(), vec![
+ SyntheticToken {
+ kind: SyntaxKind::L_CURLY,
+ text: "{".into(),
+ range: end_range,
+ id: EMPTY_ID,
+ },
+ SyntheticToken {
+ kind: SyntaxKind::R_CURLY,
+ text: "}".into(),
+ range: end_range,
+ id: EMPTY_ID,
+ },
+ ]);
+ }
+ },
// FIXME: foo::
- // FIXME: for, loop, match etc.
+ // FIXME: for, match etc.
_ => (),
}
}
// the {} gets parsed as the condition, I think?
expect![[r#"
fn foo () {if {} {}}
+"#]],
+ )
+ }
+
+ #[test]
+ fn fixup_while_1() {
+ check(
+ r#"
+fn foo() {
+ while
+}
+"#,
+ expect![[r#"
+fn foo () {while __ra_fixup {}}
+"#]],
+ )
+ }
+
+ #[test]
+ fn fixup_while_2() {
+ check(
+ r#"
+fn foo() {
+ while foo
+}
+"#,
+ expect![[r#"
+fn foo () {while foo {}}
+"#]],
+ )
+ }
+ #[test]
+ fn fixup_while_3() {
+ check(
+ r#"
+fn foo() {
+ while {}
+}
+"#,
+ expect![[r#"
+fn foo () {while __ra_fixup {}}
+"#]],
+ )
+ }
+
+ #[test]
+ fn fixup_loop() {
+ check(
+ r#"
+fn foo() {
+ loop
+}
+"#,
+ expect![[r#"
+fn foo () {loop {}}
"#]],
)
}
bitor,
bitxor_assign,
bitxor,
+ branch,
deref_mut,
deref,
div_assign,
not,
owned_box,
partial_ord,
+ poll,
r#fn,
rem_assign,
rem,
fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
fn strip_references(&self) -> &Ty;
+ fn strip_reference(&self) -> &Ty;
/// If this is a `dyn Trait`, returns that trait.
fn dyn_trait(&self) -> Option<TraitId>;
t
}
+ fn strip_reference(&self) -> &Ty {
+ self.as_reference().map_or(self, |(ty, _, _)| ty)
+ }
+
fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
match self.kind(Interner) {
TyKind::OpaqueType(opaque_ty_id, subst) => {
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
};
use hir_def::{
- expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp},
+ expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp},
generics::TypeOrConstParamData,
path::{GenericArg, GenericArgs},
resolver::resolver_for_expr,
- ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup,
+ ConstParamId, FieldId, ItemContainerId, Lookup,
};
-use hir_expand::name::{name, Name};
+use hir_expand::name::Name;
use stdx::always;
use syntax::ast::RangeOp;
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
},
mapping::{from_chalk, ToChalk},
- method_resolution::{self, VisibleFromModule},
+ method_resolution::{self, lang_names_for_bin_op, VisibleFromModule},
primitive::{self, UintTy},
static_lifetime, to_chalk_trait_id,
utils::{generics, Generics},
let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
let rhs_ty = self.table.new_type_var();
- let func = self.resolve_binop_method(op);
+ let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
+ self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
+ });
let func = match func {
Some(func) => func,
None => {
},
})
}
-
- fn resolve_binop_method(&self, op: BinaryOp) -> Option<FunctionId> {
- let (name, lang_item) = match op {
- BinaryOp::LogicOp(_) => return None,
- BinaryOp::ArithOp(aop) => match aop {
- ArithOp::Add => (name!(add), name!(add)),
- ArithOp::Mul => (name!(mul), name!(mul)),
- ArithOp::Sub => (name!(sub), name!(sub)),
- ArithOp::Div => (name!(div), name!(div)),
- ArithOp::Rem => (name!(rem), name!(rem)),
- ArithOp::Shl => (name!(shl), name!(shl)),
- ArithOp::Shr => (name!(shr), name!(shr)),
- ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
- ArithOp::BitOr => (name!(bitor), name!(bitor)),
- ArithOp::BitAnd => (name!(bitand), name!(bitand)),
- },
- BinaryOp::Assignment { op: Some(aop) } => match aop {
- ArithOp::Add => (name!(add_assign), name!(add_assign)),
- ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
- ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
- ArithOp::Div => (name!(div_assign), name!(div_assign)),
- ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
- ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
- ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
- ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
- ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
- ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
- },
- BinaryOp::CmpOp(cop) => match cop {
- CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
- CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
- CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
- (name!(le), name!(partial_ord))
- }
- CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
- (name!(lt), name!(partial_ord))
- }
- CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
- (name!(ge), name!(partial_ord))
- }
- CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
- (name!(gt), name!(partial_ord))
- }
- },
- BinaryOp::Assignment { op: None } => return None,
- };
-
- let trait_ = self.resolve_lang_item(lang_item)?.as_trait()?;
-
- self.db.trait_data(trait_).method_by_name(&name)
- }
}
let ctx =
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
for (field_id, field_data) in var_data.fields().iter() {
- res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)))
+ res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
}
Arc::new(res)
}
}
}
-pub fn inherent_impl_crates_query(
+pub(crate) fn inherent_impl_crates_query(
db: &dyn HirDatabase,
krate: CrateId,
fp: TyFingerprint,
}
}
+pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> {
+ use hir_expand::name;
+ use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering};
+ Some(match op {
+ BinaryOp::LogicOp(_) => return None,
+ BinaryOp::ArithOp(aop) => match aop {
+ ArithOp::Add => (name!(add), name!(add)),
+ ArithOp::Mul => (name!(mul), name!(mul)),
+ ArithOp::Sub => (name!(sub), name!(sub)),
+ ArithOp::Div => (name!(div), name!(div)),
+ ArithOp::Rem => (name!(rem), name!(rem)),
+ ArithOp::Shl => (name!(shl), name!(shl)),
+ ArithOp::Shr => (name!(shr), name!(shr)),
+ ArithOp::BitXor => (name!(bitxor), name!(bitxor)),
+ ArithOp::BitOr => (name!(bitor), name!(bitor)),
+ ArithOp::BitAnd => (name!(bitand), name!(bitand)),
+ },
+ BinaryOp::Assignment { op: Some(aop) } => match aop {
+ ArithOp::Add => (name!(add_assign), name!(add_assign)),
+ ArithOp::Mul => (name!(mul_assign), name!(mul_assign)),
+ ArithOp::Sub => (name!(sub_assign), name!(sub_assign)),
+ ArithOp::Div => (name!(div_assign), name!(div_assign)),
+ ArithOp::Rem => (name!(rem_assign), name!(rem_assign)),
+ ArithOp::Shl => (name!(shl_assign), name!(shl_assign)),
+ ArithOp::Shr => (name!(shr_assign), name!(shr_assign)),
+ ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)),
+ ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)),
+ ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)),
+ },
+ BinaryOp::CmpOp(cop) => match cop {
+ CmpOp::Eq { negated: false } => (name!(eq), name!(eq)),
+ CmpOp::Eq { negated: true } => (name!(ne), name!(eq)),
+ CmpOp::Ord { ordering: Ordering::Less, strict: false } => {
+ (name!(le), name!(partial_ord))
+ }
+ CmpOp::Ord { ordering: Ordering::Less, strict: true } => {
+ (name!(lt), name!(partial_ord))
+ }
+ CmpOp::Ord { ordering: Ordering::Greater, strict: false } => {
+ (name!(ge), name!(partial_ord))
+ }
+ CmpOp::Ord { ordering: Ordering::Greater, strict: true } => {
+ (name!(gt), name!(partial_ord))
+ }
+ },
+ BinaryOp::Assignment { op: None } => return None,
+ })
+}
+
/// Look up the method with the given name.
pub(crate) fn lookup_method(
ty: &Canonical<Ty>,
self.derived(self.ty.strip_references().clone())
}
+ pub fn strip_reference(&self) -> Type {
+ self.derived(self.ty.strip_reference().clone())
+ }
+
pub fn is_unknown(&self) -> bool {
self.ty.is_unknown()
}
self.imp.resolve_type(ty)
}
+ pub fn resolve_trait(&self, trait_: &ast::Path) -> Option<Trait> {
+ self.imp.resolve_trait(trait_)
+ }
+
// FIXME: Figure out a nice interface to inspect adjustments
pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
self.imp.is_implicit_reborrow(expr)
self.imp.resolve_method_call(call).map(Function::from)
}
+ pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
+ self.imp.resolve_await_to_poll(await_expr).map(Function::from)
+ }
+
+ pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
+ self.imp.resolve_prefix_expr(prefix_expr).map(Function::from)
+ }
+
+ pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
+ self.imp.resolve_index_expr(index_expr).map(Function::from)
+ }
+
+ pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
+ self.imp.resolve_bin_expr(bin_expr).map(Function::from)
+ }
+
+ pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
+ self.imp.resolve_try_expr(try_expr).map(Function::from)
+ }
+
pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
self.imp.resolve_method_call_as_callable(call)
}
}
fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
- self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(|it| it.value)
+ self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(
+ |InFile { file_id, value }| {
+ self.cache(find_root(value.syntax()), file_id);
+ value
+ },
+ )
}
fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
}
+ fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
+ let analyze = self.analyze(path.syntax())?;
+ let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id);
+ let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
+ let hir_path = Path::from_src(path.clone(), &ctx)?;
+ match analyze
+ .resolver
+ .resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())?
+ {
+ TypeNs::TraitId(id) => Some(Trait { id }),
+ _ => None,
+ }
+ }
+
fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
}
self.analyze(call.syntax())?.resolve_method_call(self.db, call)
}
+ fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
+ self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
+ }
+
+ fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<FunctionId> {
+ self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr)
+ }
+
+ fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<FunctionId> {
+ self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr)
+ }
+
+ fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<FunctionId> {
+ self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr)
+ }
+
+ fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<FunctionId> {
+ self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
+ }
+
fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
}
Lookup, ModuleDefId, VariantId,
};
use hir_expand::{
- builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name::AsName, HirFileId, InFile,
+ builtin_fn_macro::BuiltinFnLikeExpander,
+ hygiene::Hygiene,
+ name,
+ name::{AsName, Name},
+ HirFileId, InFile,
};
use hir_ty::{
diagnostics::{
record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
UnsafeExpr,
},
- method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution,
- TyExt, TyKind, TyLoweringContext,
+ method_resolution::{self, lang_names_for_bin_op},
+ Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
+ TyLoweringContext,
};
use itertools::Itertools;
use smallvec::SmallVec;
) -> Option<FunctionId> {
let expr_id = self.expr_id(db, &call.clone().into())?;
let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
- let f_in_impl = self.resolve_impl_method(db, f_in_trait, &substs);
- f_in_impl.or(Some(f_in_trait))
+
+ Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs))
+ }
+
+ pub(crate) fn resolve_await_to_poll(
+ &self,
+ db: &dyn HirDatabase,
+ await_expr: &ast::AwaitExpr,
+ ) -> Option<FunctionId> {
+ let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?;
+
+ let op_fn = db
+ .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
+ .as_function()?;
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ }
+
+ pub(crate) fn resolve_prefix_expr(
+ &self,
+ db: &dyn HirDatabase,
+ prefix_expr: &ast::PrefixExpr,
+ ) -> Option<FunctionId> {
+ let lang_item_name = match prefix_expr.op_kind()? {
+ ast::UnaryOp::Deref => name![deref],
+ ast::UnaryOp::Not => name![not],
+ ast::UnaryOp::Neg => name![neg],
+ };
+ let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
+
+ let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ }
+
+ pub(crate) fn resolve_index_expr(
+ &self,
+ db: &dyn HirDatabase,
+ index_expr: &ast::IndexExpr,
+ ) -> Option<FunctionId> {
+ let base_ty = self.ty_of_expr(db, &index_expr.base()?.into())?;
+ let index_ty = self.ty_of_expr(db, &index_expr.index()?.into())?;
+
+ let lang_item_name = name![index];
+
+ let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
+ .push(base_ty.clone())
+ .push(index_ty.clone())
+ .build();
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ }
+
+ pub(crate) fn resolve_bin_expr(
+ &self,
+ db: &dyn HirDatabase,
+ binop_expr: &ast::BinExpr,
+ ) -> Option<FunctionId> {
+ let op = binop_expr.op_kind()?;
+ let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
+ let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
+
+ let op_fn = lang_names_for_bin_op(op)
+ .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
+ let substs =
+ hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
+
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ }
+
+ pub(crate) fn resolve_try_expr(
+ &self,
+ db: &dyn HirDatabase,
+ try_expr: &ast::TryExpr,
+ ) -> Option<FunctionId> {
+ let ty = self.ty_of_expr(db, &try_expr.expr()?.into())?;
+
+ let op_fn =
+ db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
+ let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
+
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
}
pub(crate) fn resolve_field(
let fun_data = db.function_data(func);
method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name)
}
+
+ fn resolve_impl_method_or_trait_def(
+ &self,
+ db: &dyn HirDatabase,
+ func: FunctionId,
+ substs: &Substitution,
+ ) -> FunctionId {
+ self.resolve_impl_method(db, func, substs).unwrap_or(func)
+ }
+
+ fn lang_trait_fn(
+ &self,
+ db: &dyn HirDatabase,
+ lang_trait: &Name,
+ method_name: &Name,
+ ) -> Option<FunctionId> {
+ db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
+ .method_by_name(method_name)
+ }
+
+ fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
+ self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, &expr)?)
+ }
}
fn scope_for(
// pub struct Baz;
// }
//
-// use foo::{Baz, Bar};
+// use foo::{Bar, Baz};
//
// fn qux(bar: Bar, baz: Baz) {}
// ```
pub fn f() {}
}
-use foo::{Baz, Bar, f};
+use foo::{Bar, Baz, f};
fn qux(bar: Bar, baz: Baz) {
f();
pub fn f() {}
}
-use foo::{Baz, Bar, f};
+use foo::{Bar, Baz, f};
fn qux(bar: Bar, baz: Baz) {
f();
}
}
-use foo::{bar::{Baz, Bar, f}, baz::*};
+use foo::{bar::{Bar, Baz, f}, baz::*};
fn qux(bar: Bar, baz: Baz) {
f();
use foo::{
bar::{*, f},
- baz::{g, qux::{q, h}}
+ baz::{g, qux::{h, q}}
};
fn qux(bar: Bar, baz: Baz) {
-use hir::{HasSource, InFile};
+use hir::{HasSource, HirDisplay, InFile};
use ide_db::assists::{AssistId, AssistKind};
use syntax::{
- ast::{self, edit::IndentLevel},
- AstNode, TextSize,
+ ast::{self, make, HasArgList},
+ match_ast, AstNode, SyntaxNode,
};
use crate::assist_context::{AssistContext, Assists};
// }
// ```
pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
- let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
- let path = path_expr.path()?;
+ let path: ast::Path = ctx.find_node_at_offset()?;
+ let parent = path_parent(&path)?;
if ctx.sema.resolve_path(&path).is_some() {
// No need to generate anything if the path resolves
ctx.sema.resolve_path(&path.qualifier()?)
{
let target = path.syntax().text_range();
- return add_variant_to_accumulator(acc, ctx, target, e, &name_ref);
+ return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, parent);
}
None
}
+#[derive(Debug)]
+enum PathParent {
+ PathExpr(ast::PathExpr),
+ RecordExpr(ast::RecordExpr),
+ PathPat(ast::PathPat),
+ UseTree(ast::UseTree),
+}
+
+impl PathParent {
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ PathParent::PathExpr(it) => it.syntax(),
+ PathParent::RecordExpr(it) => it.syntax(),
+ PathParent::PathPat(it) => it.syntax(),
+ PathParent::UseTree(it) => it.syntax(),
+ }
+ }
+
+ fn make_field_list(&self, ctx: &AssistContext<'_>) -> Option<ast::FieldList> {
+ let scope = ctx.sema.scope(self.syntax())?;
+
+ match self {
+ PathParent::PathExpr(it) => {
+ if let Some(call_expr) = it.syntax().parent().and_then(ast::CallExpr::cast) {
+ make_tuple_field_list(call_expr, ctx, &scope)
+ } else {
+ None
+ }
+ }
+ PathParent::RecordExpr(it) => make_record_field_list(it, ctx, &scope),
+ PathParent::UseTree(_) | PathParent::PathPat(_) => None,
+ }
+ }
+}
+
+fn path_parent(path: &ast::Path) -> Option<PathParent> {
+ let parent = path.syntax().parent()?;
+
+ match_ast! {
+ match parent {
+ ast::PathExpr(it) => Some(PathParent::PathExpr(it)),
+ ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)),
+ ast::PathPat(it) => Some(PathParent::PathPat(it)),
+ ast::UseTree(it) => Some(PathParent::UseTree(it)),
+ _ => None
+ }
+ }
+}
+
fn add_variant_to_accumulator(
acc: &mut Assists,
ctx: &AssistContext<'_>,
target: syntax::TextRange,
adt: hir::Enum,
name_ref: &ast::NameRef,
+ parent: PathParent,
) -> Option<()> {
let db = ctx.db();
let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?;
- let enum_indent = IndentLevel::from_node(&enum_node.syntax());
-
- let variant_list = enum_node.variant_list()?;
- let offset = variant_list.syntax().text_range().end() - TextSize::of('}');
- let empty_enum = variant_list.variants().next().is_none();
acc.add(
AssistId("generate_enum_variant", AssistKind::Generate),
target,
|builder| {
builder.edit_file(file_id.original_file(db));
- let text = format!(
- "{maybe_newline}{indent_1}{name},\n{enum_indent}",
- maybe_newline = if empty_enum { "\n" } else { "" },
- indent_1 = IndentLevel(1),
- name = name_ref,
- enum_indent = enum_indent
- );
- builder.insert(offset, text)
+ let node = builder.make_mut(enum_node);
+ let variant = make_variant(ctx, name_ref, parent);
+ node.variant_list().map(|it| it.add_variant(variant.clone_for_update()));
},
)
}
+fn make_variant(
+ ctx: &AssistContext<'_>,
+ name_ref: &ast::NameRef,
+ parent: PathParent,
+) -> ast::Variant {
+ let field_list = parent.make_field_list(ctx);
+ make::variant(make::name(&name_ref.text()), field_list)
+}
+
+fn make_record_field_list(
+ record: &ast::RecordExpr,
+ ctx: &AssistContext<'_>,
+ scope: &hir::SemanticsScope<'_>,
+) -> Option<ast::FieldList> {
+ let fields = record.record_expr_field_list()?.fields();
+ let record_fields = fields.map(|field| {
+ let name = name_from_field(&field);
+
+ let ty = field
+ .expr()
+ .and_then(|it| expr_ty(ctx, it, scope))
+ .unwrap_or_else(make::ty_placeholder);
+
+ make::record_field(None, name, ty)
+ });
+ Some(make::record_field_list(record_fields).into())
+}
+
+fn name_from_field(field: &ast::RecordExprField) -> ast::Name {
+ let text = match field.name_ref() {
+ Some(it) => it.to_string(),
+ None => name_from_field_shorthand(field).unwrap_or("unknown".to_string()),
+ };
+ make::name(&text)
+}
+
+fn name_from_field_shorthand(field: &ast::RecordExprField) -> Option<String> {
+ let path = match field.expr()? {
+ ast::Expr::PathExpr(path_expr) => path_expr.path(),
+ _ => None,
+ }?;
+ Some(path.as_single_name_ref()?.to_string())
+}
+
+fn make_tuple_field_list(
+ call_expr: ast::CallExpr,
+ ctx: &AssistContext<'_>,
+ scope: &hir::SemanticsScope<'_>,
+) -> Option<ast::FieldList> {
+ let args = call_expr.arg_list()?.args();
+ let tuple_fields = args.map(|arg| {
+ let ty = expr_ty(ctx, arg, &scope).unwrap_or_else(make::ty_placeholder);
+ make::tuple_field(None, ty)
+ });
+ Some(make::tuple_field_list(tuple_fields).into())
+}
+
+fn expr_ty(
+ ctx: &AssistContext<'_>,
+ arg: ast::Expr,
+ scope: &hir::SemanticsScope<'_>,
+) -> Option<ast::Type> {
+ let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?;
+ let text = ty.display_source_code(ctx.db(), scope.module().into()).ok()?;
+ Some(make::ty(&text))
+}
+
#[cfg(test)]
mod tests {
use crate::tests::{check_assist, check_assist_not_applicable};
fn main() {
m::Foo::Baz
}
+",
+ )
+ }
+
+ #[test]
+ fn associated_single_element_tuple() {
+ check_assist(
+ generate_enum_variant,
+ r"
+enum Foo {}
+fn main() {
+ Foo::Bar$0(true)
+}
+",
+ r"
+enum Foo {
+ Bar(bool),
+}
+fn main() {
+ Foo::Bar(true)
+}
+",
+ )
+ }
+
+ #[test]
+ fn associated_single_element_tuple_unknown_type() {
+ check_assist(
+ generate_enum_variant,
+ r"
+enum Foo {}
+fn main() {
+ Foo::Bar$0(x)
+}
+",
+ r"
+enum Foo {
+ Bar(_),
+}
+fn main() {
+ Foo::Bar(x)
+}
+",
+ )
+ }
+
+ #[test]
+ fn associated_multi_element_tuple() {
+ check_assist(
+ generate_enum_variant,
+ r"
+struct Struct {}
+enum Foo {}
+fn main() {
+ Foo::Bar$0(true, x, Struct {})
+}
+",
+ r"
+struct Struct {}
+enum Foo {
+ Bar(bool, _, Struct),
+}
+fn main() {
+ Foo::Bar(true, x, Struct {})
+}
+",
+ )
+ }
+
+ #[test]
+ fn associated_record() {
+ check_assist(
+ generate_enum_variant,
+ r"
+enum Foo {}
+fn main() {
+ Foo::$0Bar { x: true }
+}
+",
+ r"
+enum Foo {
+ Bar { x: bool },
+}
+fn main() {
+ Foo::Bar { x: true }
+}
+",
+ )
+ }
+
+ #[test]
+ fn associated_record_unknown_type() {
+ check_assist(
+ generate_enum_variant,
+ r"
+enum Foo {}
+fn main() {
+ Foo::$0Bar { x: y }
+}
+",
+ r"
+enum Foo {
+ Bar { x: _ },
+}
+fn main() {
+ Foo::Bar { x: y }
+}
+",
+ )
+ }
+
+ #[test]
+ fn associated_record_field_shorthand() {
+ check_assist(
+ generate_enum_variant,
+ r"
+enum Foo {}
+fn main() {
+ let x = true;
+ Foo::$0Bar { x }
+}
+",
+ r"
+enum Foo {
+ Bar { x: bool },
+}
+fn main() {
+ let x = true;
+ Foo::Bar { x }
+}
+",
+ )
+ }
+
+ #[test]
+ fn associated_record_field_shorthand_unknown_type() {
+ check_assist(
+ generate_enum_variant,
+ r"
+enum Foo {}
+fn main() {
+ Foo::$0Bar { x }
+}
+",
+ r"
+enum Foo {
+ Bar { x: _ },
+}
+fn main() {
+ Foo::Bar { x }
+}
+",
+ )
+ }
+
+ #[test]
+ fn associated_record_field_multiple_fields() {
+ check_assist(
+ generate_enum_variant,
+ r"
+struct Struct {}
+enum Foo {}
+fn main() {
+ Foo::$0Bar { x, y: x, s: Struct {} }
+}
+",
+ r"
+struct Struct {}
+enum Foo {
+ Bar { x: _, y: _, s: Struct },
+}
+fn main() {
+ Foo::Bar { x, y: x, s: Struct {} }
+}
+",
+ )
+ }
+
+ #[test]
+ fn use_tree() {
+ check_assist(
+ generate_enum_variant,
+ r"
+//- /main.rs
+mod foo;
+use foo::Foo::Bar$0;
+
+//- /foo.rs
+enum Foo {}
+",
+ r"
+enum Foo {
+ Bar,
+}
+",
+ )
+ }
+
+ #[test]
+ fn not_applicable_for_path_type() {
+ check_assist_not_applicable(
+ generate_enum_variant,
+ r"
+enum Foo {}
+impl Foo::Bar$0 {}
+",
+ )
+ }
+
+ #[test]
+ fn path_pat() {
+ check_assist(
+ generate_enum_variant,
+ r"
+enum Foo {}
+fn foo(x: Foo) {
+ match x {
+ Foo::Bar$0 =>
+ }
+}
+",
+ r"
+enum Foo {
+ Bar,
+}
+fn foo(x: Foo) {
+ match x {
+ Foo::Bar =>
+ }
+}
",
)
}
imports::insert_use::remove_path_if_in_use_stmt,
path_transform::PathTransform,
search::{FileReference, SearchScope},
- syntax_helpers::node_ext::expr_as_name_ref,
+ syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
RootDatabase,
};
use itertools::{izip, Itertools};
params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
CallInfo { node, arguments, generic_arg_list }: &CallInfo,
) -> ast::Expr {
- let body = fn_body.clone_for_update();
+ let body = if sema.hir_file_for(fn_body.syntax()).is_macro() {
+ cov_mark::hit!(inline_call_defined_in_macro);
+ if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) {
+ body
+ } else {
+ fn_body.clone_for_update()
+ }
+ } else {
+ fn_body.clone_for_update()
+ };
let usages_for_locals = |local| {
Definition::Local(local)
.usages(sema)
x
}) + foo()
}
+"#,
+ )
+ }
+
+ #[test]
+ fn inline_call_defined_in_macro() {
+ cov_mark::check!(inline_call_defined_in_macro);
+ check_assist(
+ inline_call,
+ r#"
+macro_rules! define_foo {
+ () => { fn foo() -> u32 {
+ let x = 0;
+ x
+ } };
+}
+define_foo!();
+fn bar() -> u32 {
+ foo$0()
+}
+"#,
+ r#"
+macro_rules! define_foo {
+ () => { fn foo() -> u32 {
+ let x = 0;
+ x
+ } };
+}
+define_foo!();
+fn bar() -> u32 {
+ {
+ let x = 0;
+ x
+ }
+}
"#,
)
}
pub struct Baz;
}
-use foo::{Baz, Bar};
+use foo::{Bar, Baz};
fn qux(bar: Bar, baz: Baz) {}
"#####,
) {
if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
cov_mark::hit!(enum_variant_pattern_path);
- self.add_variant_pat(ctx, pat_ctx, variant, local_name);
+ self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name);
return;
}
&mut self,
ctx: &CompletionContext<'_>,
pattern_ctx: &PatternContext,
+ path_ctx: Option<&PathCompletionCtx>,
variant: hir::Variant,
local_name: Option<hir::Name>,
) {
self.add_opt(render_variant_pat(
RenderContext::new(ctx),
pattern_ctx,
+ path_ctx,
variant,
local_name.clone(),
None,
path: hir::ModPath,
) {
let path = Some(&path);
- self.add_opt(render_variant_pat(RenderContext::new(ctx), pattern_ctx, variant, None, path));
+ self.add_opt(render_variant_pat(
+ RenderContext::new(ctx),
+ pattern_ctx,
+ None,
+ variant,
+ None,
+ path,
+ ));
}
pub(crate) fn add_struct_pat(
});
acc.add_nameref_keywords_with_colon(ctx);
}
- Qualified::Infer | Qualified::With { .. } => {}
+ Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
}
let attributes = annotated_item_kind.and_then(|kind| {
});
acc.add_nameref_keywords_with_colon(ctx);
}
- Qualified::Infer | Qualified::With { .. } => {}
+ Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
}
}
acc: &mut Completions,
ctx: &CompletionContext<'_>,
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
- &ExprCtx {
+ expr_ctx: &ExprCtx,
+) {
+ let _p = profile::span("complete_expr_path");
+ if !ctx.qualifier_ctx.none() {
+ return;
+ }
+
+ let &ExprCtx {
in_block_expr,
in_loop_body,
after_if_expr,
ref impl_,
in_match_guard,
..
- }: &ExprCtx,
-) {
- let _p = profile::span("complete_expr_path");
- if !ctx.qualifier_ctx.none() {
- return;
- }
+ } = expr_ctx;
let wants_mut_token =
ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
};
match qualified {
- Qualified::Infer => ctx
+ Qualified::TypeAnchor { ty: None, trait_: None } => ctx
.traits_in_scope()
.iter()
.flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
.for_each(|item| add_assoc_item(acc, item)),
+ Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
+ trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
+ }
+ Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
+ if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+ cov_mark::hit!(completes_variant_through_alias);
+ acc.add_enum_variants(ctx, path_ctx, e);
+ }
+
+ ctx.iterate_path_candidates(&ty, |item| {
+ add_assoc_item(acc, item);
+ });
+
+ // Iterate assoc types separately
+ ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+ if let hir::AssocItem::TypeAlias(ty) = item {
+ acc.add_type_alias(ctx, ty)
+ }
+ None::<()>
+ });
+ }
Qualified::With { resolution: None, .. } => {}
Qualified::With { resolution: Some(resolution), .. } => {
// Add associated types on type parameters and `Self`.
}
}
}
- ctx.process_all_names(&mut |name, def| {
- if scope_def_applicable(def) {
- acc.add_path_resolution(ctx, path_ctx, name, def);
+ ctx.process_all_names(&mut |name, def| match def {
+ ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => {
+ let assocs = t.items_with_supertraits(ctx.db);
+ match &*assocs {
+ // traits with no assoc items are unusable as expressions since
+ // there is no associated item path that can be constructed with them
+ [] => (),
+ // FIXME: Render the assoc item with the trait qualified
+ &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def),
+ // FIXME: Append `::` to the thing here, since a trait on its own won't work
+ [..] => acc.add_path_resolution(ctx, path_ctx, name, def),
+ }
}
+ _ if scope_def_applicable(def) => acc.add_path_resolution(ctx, path_ctx, name, def),
+ _ => (),
});
if is_func_update.is_none() {
});
acc.add_nameref_keywords_with_colon(ctx);
}
- Qualified::Infer | Qualified::No | Qualified::With { .. } => {}
+ Qualified::TypeAnchor { .. } | Qualified::No | Qualified::With { .. } => {}
}
}
hir::ModuleDef::Variant(variant)
if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
{
- acc.add_variant_pat(ctx, pattern_ctx, variant, Some(name.clone()));
+ acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone()));
true
}
hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
acc.add_nameref_keywords_with_colon(ctx);
}
- Qualified::Infer | Qualified::With { .. } => {}
+ Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
}
}
};
match qualified {
- Qualified::Infer => ctx
+ Qualified::TypeAnchor { ty: None, trait_: None } => ctx
.traits_in_scope()
.iter()
.flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
.for_each(|item| add_assoc_item(acc, item)),
+ Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
+ trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
+ }
+ Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
+ ctx.iterate_path_candidates(&ty, |item| {
+ add_assoc_item(acc, item);
+ });
+
+ // Iterate assoc types separately
+ ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+ if let hir::AssocItem::TypeAlias(ty) = item {
+ acc.add_type_alias(ctx, ty)
+ }
+ None::<()>
+ });
+ }
Qualified::With { resolution: None, .. } => {}
Qualified::With { resolution: Some(resolution), .. } => {
// Add associated types on type parameters and `Self`.
});
acc.add_nameref_keywords_with_colon(ctx);
}
- Qualified::Infer | Qualified::With { resolution: None, .. } => {}
+ Qualified::TypeAnchor { .. } | Qualified::With { resolution: None, .. } => {}
}
}
acc.add_super_keyword(ctx, *super_chain_len);
}
- Qualified::Absolute | Qualified::Infer | Qualified::With { .. } => {}
+ Qualified::Absolute | Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
Qualified::No => {
if !has_in_token {
cov_mark::hit!(kw_completion_in);
super_chain_len: Option<usize>,
},
/// <_>::
- Infer,
+ TypeAnchor {
+ ty: Option<hir::Type>,
+ trait_: Option<hir::Trait>,
+ },
/// Whether the path is an absolute path
Absolute,
}
}
/// Calculate the expected type and name of the cursor position.
- fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
+ fn expected_type_and_name(
+ &self,
+ name_like: &ast::NameLike,
+ ) -> (Option<Type>, Option<NameOrNameRef>) {
let mut node = match self.token.parent() {
Some(it) => it,
None => return (None, None),
};
+
+ let strip_refs = |mut ty: Type| match name_like {
+ ast::NameLike::NameRef(n) => {
+ let p = match n.syntax().parent() {
+ Some(it) => it,
+ None => return ty,
+ };
+ let top_syn = match_ast! {
+ match p {
+ ast::FieldExpr(e) => e
+ .syntax()
+ .ancestors()
+ .map_while(ast::FieldExpr::cast)
+ .last()
+ .map(|it| it.syntax().clone()),
+ ast::PathSegment(e) => e
+ .syntax()
+ .ancestors()
+ .skip(1)
+ .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
+ .find_map(ast::PathExpr::cast)
+ .map(|it| it.syntax().clone()),
+ _ => None
+ }
+ };
+ let top_syn = match top_syn {
+ Some(it) => it,
+ None => return ty,
+ };
+ for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) {
+ cov_mark::hit!(expected_type_fn_param_ref);
+ ty = ty.strip_reference();
+ }
+ ty
+ }
+ _ => ty,
+ };
+
loop {
break match_ast! {
match node {
self.token.clone(),
).map(|ap| {
let name = ap.ident().map(NameOrNameRef::Name);
- let ty = if has_ref(&self.token) {
- cov_mark::hit!(expected_type_fn_param_ref);
- ap.ty.remove_ref()
- } else {
- Some(ap.ty)
- };
- (ty, name)
+
+ let ty = strip_refs(ap.ty);
+ (Some(ty), name)
})
.unwrap_or((None, None))
},
return None;
}
- (self.expected_type, self.expected_name) = self.expected_type_and_name();
-
// Overwrite the path kind for derives
if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
if let Some(ast::NameLike::NameRef(name_ref)) =
return Some(analysis);
}
};
+ (self.expected_type, self.expected_name) = self.expected_type_and_name(&name_like);
let analysis = match name_like {
ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime(
Self::classify_lifetime(&self.sema, original_file, lifetime)?,
has_call_parens: false,
has_macro_bang: false,
qualified: Qualified::No,
- parent: path.parent_path(),
+ parent: None,
path: path.clone(),
kind: PathKind::Item { kind: ItemListKind::SourceFile },
has_type_args: false,
PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
};
+ let mut kind_macro_call = |it: ast::MacroCall| {
+ path_ctx.has_macro_bang = it.excl_token().is_some();
+ let parent = it.syntax().parent()?;
+ // Any path in an item list will be treated as a macro call by the parser
+ let kind = match_ast! {
+ match parent {
+ ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
+ ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
+ ast::MacroType(ty) => make_path_kind_type(ty.into()),
+ ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
+ ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
+ Some(it) => match_ast! {
+ match it {
+ ast::Trait(_) => ItemListKind::Trait,
+ ast::Impl(it) => if it.trait_().is_some() {
+ ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
+ } else {
+ ItemListKind::Impl
+ },
+ _ => return None
+ }
+ },
+ None => return None,
+ } },
+ ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
+ ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
+ _ => return None,
+ }
+ };
+ Some(kind)
+ };
+ let make_path_kind_attr = |meta: ast::Meta| {
+ let attr = meta.parent_attr()?;
+ let kind = attr.kind();
+ let attached = attr.syntax().parent()?;
+ let is_trailing_outer_attr = kind != AttrKind::Inner
+ && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next)
+ .is_none();
+ let annotated_item_kind =
+ if is_trailing_outer_attr { None } else { Some(attached.kind()) };
+ Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
+ };
+
// Infer the path kind
let parent = path.syntax().parent()?;
let kind = match_ast! {
- match parent {
- ast::PathType(it) => make_path_kind_type(it.into()),
- ast::PathExpr(it) => {
- if let Some(p) = it.syntax().parent() {
- if ast::ExprStmt::can_cast(p.kind()) {
- if let Some(kind) = inbetween_body_and_decl_check(p) {
- return Some(make_res(NameRefKind::Keyword(kind)));
- }
+ match parent {
+ ast::PathType(it) => make_path_kind_type(it.into()),
+ ast::PathExpr(it) => {
+ if let Some(p) = it.syntax().parent() {
+ if ast::ExprStmt::can_cast(p.kind()) {
+ if let Some(kind) = inbetween_body_and_decl_check(p) {
+ return Some(make_res(NameRefKind::Keyword(kind)));
}
}
+ }
- path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+ path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
- make_path_kind_expr(it.into())
- },
- ast::TupleStructPat(it) => {
- path_ctx.has_call_parens = true;
- PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
- },
- ast::RecordPat(it) => {
- path_ctx.has_call_parens = true;
- PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
- },
- ast::PathPat(it) => {
- PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
- },
- ast::MacroCall(it) => {
- // A macro call in this position is usually a result of parsing recovery, so check that
- if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
- return Some(make_res(NameRefKind::Keyword(kind)));
- }
+ make_path_kind_expr(it.into())
+ },
+ ast::TupleStructPat(it) => {
+ path_ctx.has_call_parens = true;
+ PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+ },
+ ast::RecordPat(it) => {
+ path_ctx.has_call_parens = true;
+ PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+ },
+ ast::PathPat(it) => {
+ PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+ },
+ ast::MacroCall(it) => {
+ // A macro call in this position is usually a result of parsing recovery, so check that
+ if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
+ return Some(make_res(NameRefKind::Keyword(kind)));
+ }
- path_ctx.has_macro_bang = it.excl_token().is_some();
- let parent = it.syntax().parent()?;
- // Any path in an item list will be treated as a macro call by the parser
- match_ast! {
- match parent {
- ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
- ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
- ast::MacroType(ty) => make_path_kind_type(ty.into()),
- ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
- ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
- Some(it) => match_ast! {
- match it {
- ast::Trait(_) => ItemListKind::Trait,
- ast::Impl(it) => if it.trait_().is_some() {
- ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
- } else {
- ItemListKind::Impl
- },
- _ => return None
- }
- },
- None => return None,
- } },
- ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
- ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
- _ => return None,
- }
- }
- },
- ast::Meta(meta) => {
- let attr = meta.parent_attr()?;
- let kind = attr.kind();
- let attached = attr.syntax().parent()?;
- let is_trailing_outer_attr = kind != AttrKind::Inner
- && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
- let annotated_item_kind = if is_trailing_outer_attr {
- None
- } else {
- Some(attached.kind())
- };
- PathKind::Attr {
- attr_ctx: AttrCtx {
- kind,
- annotated_item_kind,
- }
+ kind_macro_call(it)?
+ },
+ ast::Meta(meta) => make_path_kind_attr(meta)?,
+ ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+ ast::UseTree(_) => PathKind::Use,
+ // completing inside a qualifier
+ ast::Path(parent) => {
+ path_ctx.parent = Some(parent.clone());
+ let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
+ match_ast! {
+ match parent {
+ ast::PathType(it) => make_path_kind_type(it.into()),
+ ast::PathExpr(it) => {
+ path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+
+ make_path_kind_expr(it.into())
+ },
+ ast::TupleStructPat(it) => {
+ path_ctx.has_call_parens = true;
+ PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+ },
+ ast::RecordPat(it) => {
+ path_ctx.has_call_parens = true;
+ PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+ },
+ ast::PathPat(it) => {
+ PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+ },
+ ast::MacroCall(it) => {
+ kind_macro_call(it)?
+ },
+ ast::Meta(meta) => make_path_kind_attr(meta)?,
+ ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+ ast::UseTree(_) => PathKind::Use,
+ ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+ _ => return None,
}
- },
- ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
- ast::UseTree(_) => PathKind::Use,
- _ => return None,
-
+ }
+ },
+ ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+ _ => return None,
}
};
path_ctx.has_type_args = segment.generic_arg_list().is_some();
// calculate the qualifier context
- if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
+ if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
path_ctx.use_tree_parent = use_tree_parent;
if !use_tree_parent && segment.coloncolon_token().is_some() {
path_ctx.qualified = Qualified::Absolute;
} else {
- let path = path
+ let qualifier = qualifier
.segment()
.and_then(|it| find_node_in_file(original_file, &it))
.map(|it| it.parent_path());
- if let Some(path) = path {
- // `<_>::$0`
- let is_infer_qualifier = path.qualifier().is_none()
- && matches!(
- path.segment().and_then(|it| it.kind()),
- Some(ast::PathSegmentKind::Type {
- type_ref: Some(ast::Type::InferType(_)),
- trait_ref: None,
- })
- );
+ if let Some(qualifier) = qualifier {
+ let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
+ Some(ast::PathSegmentKind::Type {
+ type_ref: Some(type_ref),
+ trait_ref,
+ }) if qualifier.qualifier().is_none() => Some((type_ref, trait_ref)),
+ _ => None,
+ };
- path_ctx.qualified = if is_infer_qualifier {
- Qualified::Infer
+ path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
+ let ty = match ty {
+ ast::Type::InferType(_) => None,
+ ty => sema.resolve_type(&ty),
+ };
+ let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
+ Qualified::TypeAnchor { ty, trait_ }
} else {
- let res = sema.resolve_path(&path);
+ let res = sema.resolve_path(&qualifier);
// For understanding how and why super_chain_len is calculated the way it
// is check the documentation at it's definition
let mut segment_count = 0;
- let super_count = iter::successors(Some(path.clone()), |p| p.qualifier())
- .take_while(|p| {
- p.segment()
- .and_then(|s| {
- segment_count += 1;
- s.super_token()
- })
- .is_some()
- })
- .count();
+ let super_count =
+ iter::successors(Some(qualifier.clone()), |p| p.qualifier())
+ .take_while(|p| {
+ p.segment()
+ .and_then(|s| {
+ segment_count += 1;
+ s.super_token()
+ })
+ .is_some()
+ })
+ .count();
let super_chain_len =
if segment_count > super_count { None } else { Some(super_count) };
- Qualified::With { path, resolution: res, super_chain_len }
+ Qualified::With { path: qualifier, resolution: res, super_chain_len }
}
};
}
Some((use_tree.path()?, true))
}
-fn has_ref(token: &SyntaxToken) -> bool {
- let mut token = token.clone();
- for skip in [SyntaxKind::IDENT, SyntaxKind::WHITESPACE, T![mut]] {
- if token.kind() == skip {
- token = match token.prev_token() {
- Some(it) => it,
- None => return false,
- }
- }
- }
- token.kind() == T![&]
-}
-
pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool {
// oh my ...
(|| {
expect![[r#"ty: ?, name: ?"#]],
);
}
+
+#[test]
+fn expected_type_ref_prefix_on_field() {
+ check_expected_type_and_name(
+ r#"
+fn foo(_: &mut i32) {}
+struct S {
+ field: i32,
+}
+
+fn main() {
+ let s = S {
+ field: 100,
+ };
+ foo(&mut s.f$0);
+}
+"#,
+ expect!["ty: i32, name: ?"],
+ );
+}
st S []
st &mut S [type]
st S []
- fn main() []
fn foo(…) []
+ fn main() []
"#]],
);
check_relevance(
lc s [type+name+local]
st S [type]
st S []
- fn main() []
fn foo(…) []
+ fn main() []
"#]],
);
check_relevance(
lc ssss [type+local]
st S [type]
st S []
- fn main() []
fn foo(…) []
+ fn main() []
"#]],
);
}
lc &t [type+local]
st S []
st &S [type]
- st T []
st S []
- fn main() []
+ st T []
fn foo(…) []
+ fn main() []
md core []
- tt Sized []
"#]],
)
}
lc &mut t [type+local]
st S []
st &mut S [type]
- st T []
st S []
- fn main() []
+ st T []
fn foo(…) []
+ fn main() []
md core []
- tt Sized []
"#]],
)
}
expect![[r#"
st S []
st &S [type]
- st T []
st S []
- fn main() []
+ st T []
fn bar() []
fn &bar() [type]
fn foo(…) []
+ fn main() []
md core []
- tt Sized []
"#]],
)
}
ev Foo::B [type_could_unify]
fn foo() []
en Foo []
- fn baz() []
fn bar() []
+ fn baz() []
"#]],
);
}
}
"#,
expect![[r#"
- md std []
st Buffer []
fn f() []
+ md std []
tt BufRead (use std::io::BufRead) [requires_import]
st BufReader (use std::io::BufReader) [requires_import]
st BufWriter (use std::io::BufWriter) [requires_import]
item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
}
FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => {
- item.ref_match(ref_match, receiver.syntax().text_range().start());
+ if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) {
+ item.ref_match(ref_match, original_expr.syntax().text_range().start());
+ }
}
_ => (),
}
use syntax::SmolStr;
use crate::{
- context::{ParamContext, ParamKind, PatternContext},
+ context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext},
render::{
variant::{format_literal_label, visible_fields},
RenderContext,
pub(crate) fn render_variant_pat(
ctx: RenderContext<'_>,
pattern_ctx: &PatternContext,
+ path_ctx: Option<&PathCompletionCtx>,
variant: hir::Variant,
local_name: Option<Name>,
path: Option<&hir::ModPath>,
(name.to_smol_str(), name.escaped().to_smol_str())
}
};
- let kind = variant.kind(ctx.db());
- let label = format_literal_label(name.as_str(), kind);
- let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
+
+ let (label, pat) = match path_ctx {
+ Some(PathCompletionCtx { has_call_parens: true, .. }) => (name, escaped_name.to_string()),
+ _ => {
+ let kind = variant.kind(ctx.db());
+ let label = format_literal_label(name.as_str(), kind);
+ let pat = render_pat(
+ &ctx,
+ pattern_ctx,
+ &escaped_name,
+ kind,
+ &visible_fields,
+ fields_omitted,
+ )?;
+ (label, pat)
+ }
+ };
Some(build_completion(ctx, label, pat, variant))
}
mod use_tree;
mod visibility;
-use std::mem;
-
use hir::{db::DefDatabase, PrefixKind, Semantics};
use ide_db::{
base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
) -> String {
// filter out all but one builtintype completion for smaller test outputs
let items = get_all_items(config, ra_fixture, trigger_character);
- let mut bt_seen = false;
let items = items
.into_iter()
- .filter(|it| {
- it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true)
- })
+ .filter(|it| it.kind() != CompletionItemKind::BuiltinType || it.label() == "u32")
.filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
.filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
.sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned)))
st Record
st Tuple
st Unit
- tt Trait
un Union
ev TupleV(…) TupleV(u32)
bt u32
st Record
st Tuple
st Unit
- tt Trait
tp TypeParam
un Union
ev TupleV(…) TupleV(u32)
"]],
);
}
+
+#[test]
+fn complete_record_expr_path() {
+ check(
+ r#"
+struct Zulu;
+impl Zulu {
+ fn test() -> Self { }
+}
+fn boi(val: Zulu) { }
+fn main() {
+ boi(Zulu:: $0 {});
+}
+"#,
+ expect![[r#"
+ fn test() fn() -> Zulu
+ "#]],
+ );
+}
}
"#,
expect![[r#"
- bn TupleVariant(…) TupleVariant($1)$0
+ bn TupleVariant TupleVariant
"#]],
);
check_empty(
}
"#,
expect![[r#"
- bn RecordVariant {…} RecordVariant { field$1 }$0
+ bn RecordVariant RecordVariant
"#]],
);
}
st Foo
st Foo {…} Foo { foo1: u32, foo2: u32 }
tt Default
- tt Sized
bt u32
kw crate::
kw self::
expect![[r#"
fn foo() (as Foo) fn() -> Self
"#]],
- )
+ );
+}
+
+#[test]
+fn type_anchor_type() {
+ check(
+ r#"
+trait Foo {
+ fn foo() -> Self;
+}
+struct Bar;
+impl Bar {
+ fn bar() {}
+}
+impl Foo for Bar {
+ fn foo() -> {
+ Bar
+ }
+}
+fn bar() -> Bar {
+ <Bar>::$0
+}
+"#,
+ expect![[r#"
+ fn bar() fn()
+ fn foo() (as Foo) fn() -> Self
+ "#]],
+ );
+}
+
+#[test]
+fn type_anchor_type_trait() {
+ check(
+ r#"
+trait Foo {
+ fn foo() -> Self;
+}
+struct Bar;
+impl Bar {
+ fn bar() {}
+}
+impl Foo for Bar {
+ fn foo() -> {
+ Bar
+ }
+}
+fn bar() -> Bar {
+ <Bar as Foo>::$0
+}
+"#,
+ expect![[r#"
+ fn foo() (as Foo) fn() -> Self
+ "#]],
+ );
}
#[test]
// |===
// | Editor | Action Name
//
- // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)**
+ // | VS Code | **rust-analyzer: Memory Usage (Clears Database)**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[]
pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
}
}
+// FIXME: IdentClass as a name no longer fits
#[derive(Debug)]
pub enum IdentClass {
NameClass(NameClass),
NameRefClass(NameRefClass),
+ Operator(OperatorClass),
}
impl IdentClass {
.map(IdentClass::NameClass)
.or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
},
+ ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator),
+ ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator),
+ ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator),
+ ast::PrefixExpr(prefix_expr) => OperatorClass::classify_prefix(sema,&prefix_expr).map(IdentClass::Operator),
+ ast::TryExpr(try_expr) => OperatorClass::classify_try(sema,&try_expr).map(IdentClass::Operator),
_ => None,
}
}
res.push(Definition::Local(local_ref));
res.push(Definition::Field(field_ref));
}
+ IdentClass::Operator(
+ OperatorClass::Await(func)
+ | OperatorClass::Prefix(func)
+ | OperatorClass::Bin(func)
+ | OperatorClass::Index(func)
+ | OperatorClass::Try(func),
+ ) => res.push(Definition::Function(func)),
+ }
+ res
+ }
+
+ pub fn definitions_no_ops(self) -> ArrayVec<Definition, 2> {
+ let mut res = ArrayVec::new();
+ match self {
+ IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => {
+ res.push(it)
+ }
+ IdentClass::NameClass(NameClass::PatFieldShorthand { local_def, field_ref }) => {
+ res.push(Definition::Local(local_def));
+ res.push(Definition::Field(field_ref));
+ }
+ IdentClass::NameRefClass(NameRefClass::Definition(it)) => res.push(it),
+ IdentClass::NameRefClass(NameRefClass::FieldShorthand { local_ref, field_ref }) => {
+ res.push(Definition::Local(local_ref));
+ res.push(Definition::Field(field_ref));
+ }
+ IdentClass::Operator(_) => (),
}
res
}
}
}
+#[derive(Debug)]
+pub enum OperatorClass {
+ Await(Function),
+ Prefix(Function),
+ Index(Function),
+ Try(Function),
+ Bin(Function),
+}
+
+impl OperatorClass {
+ pub fn classify_await(
+ sema: &Semantics<'_, RootDatabase>,
+ await_expr: &ast::AwaitExpr,
+ ) -> Option<OperatorClass> {
+ sema.resolve_await_to_poll(await_expr).map(OperatorClass::Await)
+ }
+
+ pub fn classify_prefix(
+ sema: &Semantics<'_, RootDatabase>,
+ prefix_expr: &ast::PrefixExpr,
+ ) -> Option<OperatorClass> {
+ sema.resolve_prefix_expr(prefix_expr).map(OperatorClass::Prefix)
+ }
+
+ pub fn classify_try(
+ sema: &Semantics<'_, RootDatabase>,
+ try_expr: &ast::TryExpr,
+ ) -> Option<OperatorClass> {
+ sema.resolve_try_expr(try_expr).map(OperatorClass::Try)
+ }
+
+ pub fn classify_index(
+ sema: &Semantics<'_, RootDatabase>,
+ index_expr: &ast::IndexExpr,
+ ) -> Option<OperatorClass> {
+ sema.resolve_index_expr(index_expr).map(OperatorClass::Index)
+ }
+
+ pub fn classify_bin(
+ sema: &Semantics<'_, RootDatabase>,
+ bin_expr: &ast::BinExpr,
+ ) -> Option<OperatorClass> {
+ sema.resolve_bin_expr(bin_expr).map(OperatorClass::Bin)
+ }
+}
+
/// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than
/// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a
/// reference most of the time, but there are a couple of annoying exceptions.
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Structural Search Replace**
+// | VS Code | **rust-analyzer: Structural Search Replace**
// |===
//
// Also available as an assist, by writing a comment containing the structural
search::FileReference,
FxIndexMap, RootDatabase,
};
-use syntax::{ast, AstNode, SyntaxKind::NAME, TextRange};
+use syntax::{ast, AstNode, SyntaxKind::IDENT, TextRange};
use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav};
let file = sema.parse(file_id);
let file = file.syntax();
let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
- NAME => 1,
+ IDENT => 1,
_ => 0,
})?;
let mut calls = CallLocations::default();
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Expand macro recursively**
+// | VS Code | **rust-analyzer: Expand macro recursively**
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[]
_ => 0,
})?;
- // due to how Rust Analyzer works internally, we need to special case derive attributes,
+ // due to how rust-analyzer works internally, we need to special case derive attributes,
// otherwise they might not get found, e.g. here with the cursor at $0 `#[attr]` would expand:
// ```
// #[attr]
| T![super]
| T![crate]
| T![Self]
- | COMMENT => 2,
+ | COMMENT => 4,
+ // index and prefix ops
+ T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
+ kind if kind.is_keyword() => 2,
+ T!['('] | T![')'] => 2,
kind if kind.is_trivia() => 0,
_ => 1,
})?;
}
foo!(bar$0);
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_await_poll() {
+ check(
+ r#"
+//- minicore: future
+
+struct MyFut;
+
+impl core::future::Future for MyFut {
+ type Output = ();
+
+ fn poll(
+ //^^^^
+ self: std::pin::Pin<&mut Self>,
+ cx: &mut std::task::Context<'_>
+ ) -> std::task::Poll<Self::Output>
+ {
+ ()
+ }
+}
+
+fn f() {
+ MyFut.await$0;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_try_op() {
+ check(
+ r#"
+//- minicore: try
+
+struct Struct;
+
+impl core::ops::Try for Struct {
+ fn branch(
+ //^^^^^^
+ self
+ ) {}
+}
+
+fn f() {
+ Struct?$0;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_index_op() {
+ check(
+ r#"
+//- minicore: index
+
+struct Struct;
+
+impl core::ops::Index<usize> for Struct {
+ fn index(
+ //^^^^^
+ self
+ ) {}
+}
+
+fn f() {
+ Struct[0]$0;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_prefix_op() {
+ check(
+ r#"
+//- minicore: deref
+
+struct Struct;
+
+impl core::ops::Deref for Struct {
+ fn deref(
+ //^^^^^
+ self
+ ) {}
+}
+
+fn f() {
+ $0*Struct;
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn goto_bin_op() {
+ check(
+ r#"
+//- minicore: add
+
+struct Struct;
+
+impl core::ops::Add for Struct {
+ fn add(
+ //^^^
+ self
+ ) {}
+}
+
+fn f() {
+ Struct +$0 Struct;
+}
"#,
);
}
let original_token =
pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind {
- IDENT | T![self] => 1,
+ IDENT | T![self] | INT_NUMBER => 1,
_ => 0,
})?;
let range = original_token.text_range();
fn find_defs(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> FxHashSet<Definition> {
sema.descend_into_macros(token)
.into_iter()
- .filter_map(|token| IdentClass::classify_token(sema, &token).map(IdentClass::definitions))
+ .filter_map(|token| IdentClass::classify_token(sema, &token))
+ .map(IdentClass::definitions_no_ops)
.flatten()
.collect()
}
use hir::{HasSource, Semantics};
use ide_db::{
base_db::FileRange,
- defs::{Definition, IdentClass},
+ defs::{Definition, IdentClass, OperatorClass},
famous_defs::FamousDefs,
helpers::pick_best_token,
FxIndexSet, RootDatabase,
let offset = range.start();
let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
- IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 3,
+ IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 4,
+ // index and prefix ops
+ T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3,
+ kind if kind.is_keyword() => 2,
T!['('] | T![')'] => 2,
kind if kind.is_trivia() => 0,
_ => 1,
.filter_map(|token| {
let node = token.parent()?;
let class = IdentClass::classify_token(sema, token)?;
+ if let IdentClass::Operator(OperatorClass::Await(_)) = class {
+ // It's better for us to fall back to the keyword hover here,
+ // rendering poll is very confusing
+ return None;
+ }
Some(class.definitions().into_iter().zip(iter::once(node).cycle()))
})
.flatten()
token: &SyntaxToken,
original_token: &SyntaxToken,
) -> Option<RangeInfo<HoverResult>> {
- let node = token
- .parent_ancestors()
- .take_while(|it| !ast::Item::can_cast(it.kind()))
- .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
+ let node =
+ token.parent_ancestors().take_while(|it| !ast::Item::can_cast(it.kind())).find(|n| {
+ ast::Expr::can_cast(n.kind())
+ || ast::Pat::can_cast(n.kind())
+ || ast::Type::can_cast(n.kind())
+ })?;
let expr_or_pat = match_ast! {
match node {
```"#]],
);
}
+
+#[test]
+fn hover_deref() {
+ check(
+ r#"
+//- minicore: deref
+
+struct Struct(usize);
+
+impl core::ops::Deref for Struct {
+ type Target = usize;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+fn f() {
+ $0*Struct(0);
+}
+"#,
+ expect![[r#"
+ ***
+
+ ```rust
+ test::Struct
+ ```
+
+ ```rust
+ fn deref(&self) -> &Self::Target
+ ```
+ "#]],
+ );
+}
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Toggle inlay hints*
+// | VS Code | **rust-analyzer: Toggle inlay hints*
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Join lines**
+// | VS Code | **rust-analyzer: Join lines**
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[]
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Find matching brace**
+// | VS Code | **rust-analyzer: Find matching brace**
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[]
.descend_into_macros(original_token.clone())
.into_iter()
.filter_map(|token| {
- IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| {
+ IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops).map(|it| {
it.into_iter().flat_map(|def| def_to_moniker(sema.db, def, current_crate))
})
})
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Move item up**
-// | VS Code | **Rust Analyzer: Move item down**
+// | VS Code | **rust-analyzer: Move item up**
+// | VS Code | **rust-analyzer: Move item down**
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[]
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Locate parent module**
+// | VS Code | **rust-analyzer: Locate parent module**
// |===
//
// image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[]
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Run**
+// | VS Code | **rust-analyzer: Run**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[]
pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Peek related tests**
+// | VS Code | **rust-analyzer: Peek related tests**
// |===
pub(crate) fn related_tests(
db: &RootDatabase,
let adt_name = ty.as_adt()?.name(sema.db);
let mut ty_args = ty.type_arguments().peekable();
let params = if ty_args.peek().is_some() {
- format!("<{}>", ty_args.format_with(", ", |ty, cb| cb(&ty.display(sema.db))))
+ format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty.display(sema.db))))
} else {
String::new()
};
- let test_id = TestId::Path(format!("{}{}", adt_name, params));
+ let mut test_id = format!("{}{}", adt_name, params);
+ test_id.retain(|c| c != ' ');
+ let test_id = TestId::Path(test_id);
Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg })
}
format_to!(
path,
"<{}>",
- ty_args.format_with(", ", |ty, cb| cb(&ty.display(db)))
+ ty_args.format_with(",", |ty, cb| cb(&ty.display(db)))
);
}
format_to!(path, "::{}", def_name);
+ path.retain(|c| c != ' ');
return Some(path);
}
}
$0
struct Foo<T, U>;
+/// ```
+/// ```
impl<T, U> Foo<T, U> {
/// ```rust
/// ````
fn t() {}
}
+
+/// ```
+/// ```
+impl Foo<Foo<(), ()>, ()> {
+ /// ```
+ /// ```
+ fn t() {}
+}
"#,
- &[DocTest],
+ &[DocTest, DocTest, DocTest, DocTest],
expect![[r#"
[
Runnable {
file_id: FileId(
0,
),
- full_range: 47..85,
+ full_range: 20..103,
+ focus_range: 47..56,
+ name: "impl",
+ kind: Impl,
+ },
+ kind: DocTest {
+ test_id: Path(
+ "Foo<T,U>",
+ ),
+ },
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 63..101,
+ name: "t",
+ },
+ kind: DocTest {
+ test_id: Path(
+ "Foo<T,U>::t",
+ ),
+ },
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 105..188,
+ focus_range: 126..146,
+ name: "impl",
+ kind: Impl,
+ },
+ kind: DocTest {
+ test_id: Path(
+ "Foo<Foo<(),()>,()>",
+ ),
+ },
+ cfg: None,
+ },
+ Runnable {
+ use_name_in_title: false,
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 153..186,
name: "t",
},
kind: DocTest {
test_id: Path(
- "Foo<T, U>::t",
+ "Foo<Foo<(),()>,()>::t",
),
},
cfg: None,
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Shuffle Crate Graph**
+// | VS Code | **rust-analyzer: Shuffle Crate Graph**
// |===
pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
let crate_graph = db.crate_graph();
fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Definition> {
for token in sema.descend_into_macros(token) {
- let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions);
+ let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
if let Some(&[x]) = def.as_deref() {
return Some(x);
} else {
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Status**
+// | VS Code | **rust-analyzer: Status**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
#[cfg(test)]
mod tests;
-use hir::{InFile, Name, Semantics};
+use hir::{Name, Semantics};
use ide_db::{FxHashMap, RootDatabase};
use syntax::{
ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T,
Leave(NodeOrToken::Node(node)) => {
// Doc comment highlighting injection, we do this when leaving the node
// so that we overwrite the highlighting of the doc comment itself.
- inject::doc_comment(hl, sema, InFile::new(file_id.into(), &node));
+ inject::doc_comment(hl, sema, file_id, &node);
continue;
}
};
use either::Either;
use hir::{InFile, Semantics};
use ide_db::{
- active_parameter::ActiveParameter, defs::Definition, rust_doc::is_rust_fence, SymbolKind,
+ active_parameter::ActiveParameter, base_db::FileId, defs::Definition, rust_doc::is_rust_fence,
+ SymbolKind,
};
use syntax::{
ast::{self, AstNode, IsString, QuoteOffsets},
const RUSTDOC_FENCE_LENGTH: usize = 3;
const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
-/// Injection of syntax highlighting of doctests.
+/// Injection of syntax highlighting of doctests and intra doc links.
pub(super) fn doc_comment(
hl: &mut Highlights,
sema: &Semantics<'_, RootDatabase>,
- InFile { file_id: src_file_id, value: node }: InFile<&SyntaxNode>,
+ src_file_id: FileId,
+ node: &SyntaxNode,
) {
let (attributes, def) = match doc_attributes(sema, node) {
Some(it) => it,
None => return,
};
+ let src_file_id = src_file_id.into();
// Extract intra-doc links and emit highlights for them.
if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
--- /dev/null
+
+<style>
+body { margin: 0; }
+pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime { color: #DFAF8F; font-style: italic; }
+.label { color: #DFAF8F; font-style: italic; }
+.comment { color: #7F9F7F; }
+.documentation { color: #629755; }
+.intra_doc_link { font-style: italic; }
+.injected { opacity: 0.65 ; }
+.struct, .enum { color: #7CB8BB; }
+.enum_variant { color: #BDE0F3; }
+.string_literal { color: #CC9393; }
+.field { color: #94BFF3; }
+.function { color: #93E0E3; }
+.function.unsafe { color: #BC8383; }
+.trait.unsafe { color: #BC8383; }
+.operator.unsafe { color: #BC8383; }
+.mutable.unsafe { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe { color: #BC8383; font-weight: bold; }
+.macro.unsafe { color: #BC8383; }
+.parameter { color: #94BFF3; }
+.text { color: #DCDCCC; }
+.type { color: #7CB8BB; }
+.builtin_type { color: #8CD0D3; }
+.type_param { color: #DFAF8F; }
+.attribute { color: #94BFF3; }
+.numeric_literal { color: #BFEBBF; }
+.bool_literal { color: #BFE6EB; }
+.macro { color: #94BFF3; }
+.derive { color: #94BFF3; font-style: italic; }
+.module { color: #AFD8AF; }
+.value_param { color: #DCDCCC; }
+.variable { color: #DCDCCC; }
+.format_specifier { color: #CC696B; }
+.mutable { text-decoration: underline; }
+.escape_sequence { color: #94BFF3; }
+.keyword { color: #F0DFAF; font-weight: bold; }
+.control { font-style: italic; }
+.reference { font-style: italic; font-weight: bold; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
+<span class="comment documentation">//! This is an intra doc injection test for modules</span>
+<span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
+<span class="comment documentation">//! This is an intra doc injection test for modules</span>
+
+<span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration public">Struct</span><span class="semicolon">;</span>
+</code></pre>
\ No newline at end of file
--- /dev/null
+
+<style>
+body { margin: 0; }
+pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime { color: #DFAF8F; font-style: italic; }
+.label { color: #DFAF8F; font-style: italic; }
+.comment { color: #7F9F7F; }
+.documentation { color: #629755; }
+.intra_doc_link { font-style: italic; }
+.injected { opacity: 0.65 ; }
+.struct, .enum { color: #7CB8BB; }
+.enum_variant { color: #BDE0F3; }
+.string_literal { color: #CC9393; }
+.field { color: #94BFF3; }
+.function { color: #93E0E3; }
+.function.unsafe { color: #BC8383; }
+.trait.unsafe { color: #BC8383; }
+.operator.unsafe { color: #BC8383; }
+.mutable.unsafe { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe { color: #BC8383; font-weight: bold; }
+.macro.unsafe { color: #BC8383; }
+.parameter { color: #94BFF3; }
+.text { color: #DCDCCC; }
+.type { color: #7CB8BB; }
+.builtin_type { color: #8CD0D3; }
+.type_param { color: #DFAF8F; }
+.attribute { color: #94BFF3; }
+.numeric_literal { color: #BFEBBF; }
+.bool_literal { color: #BFE6EB; }
+.macro { color: #94BFF3; }
+.derive { color: #94BFF3; font-style: italic; }
+.module { color: #AFD8AF; }
+.value_param { color: #DCDCCC; }
+.variable { color: #DCDCCC; }
+.format_specifier { color: #CC696B; }
+.mutable { text-decoration: underline; }
+.escape_sequence { color: #94BFF3; }
+.keyword { color: #F0DFAF; font-weight: bold; }
+.control { font-style: italic; }
+.reference { font-style: italic; font-weight: bold; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
+<span class="comment documentation">/// This is an intra doc injection test for modules</span>
+<span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
+<span class="comment documentation">/// This is an intra doc injection test for modules</span>
+<span class="keyword">mod</span> <span class="module declaration">foo</span><span class="semicolon">;</span>
+</code></pre>
\ No newline at end of file
}
#[test]
+fn test_mod_hl_injection() {
+ check_highlighting(
+ r##"
+//- /foo.rs
+//! [Struct]
+//! This is an intra doc injection test for modules
+//! [Struct]
+//! This is an intra doc injection test for modules
+
+pub struct Struct;
+//- /lib.rs crate:foo
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+mod foo;
+"##,
+ expect_file!["./test_data/highlight_module_docs_inline.html"],
+ false,
+ );
+ check_highlighting(
+ r##"
+//- /lib.rs crate:foo
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+mod foo;
+//- /foo.rs
+//! [Struct]
+//! This is an intra doc injection test for modules
+//! [Struct]
+//! This is an intra doc injection test for modules
+
+pub struct Struct;
+"##,
+ expect_file!["./test_data/highlight_module_docs_outline.html"],
+ false,
+ );
+}
+
+#[test]
+#[cfg_attr(
+ not(all(unix, target_pointer_width = "64")),
+ ignore = "depends on `DefaultHasher` outputs"
+)]
fn test_rainbow_highlighting() {
check_highlighting(
r#"
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Show Syntax Tree**
+// | VS Code | **rust-analyzer: Show Syntax Tree**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[]
pub(crate) fn syntax_tree(
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: View Crate Graph**
+// | VS Code | **rust-analyzer: View Crate Graph**
// |===
pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result<String, String> {
let crate_graph = db.crate_graph();
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: View Hir**
+// | VS Code | **rust-analyzer: View Hir**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[]
pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
// |===
// | Editor | Action Name
//
-// | VS Code | **Rust Analyzer: Debug ItemTree**
+// | VS Code | **rust-analyzer: Debug ItemTree**
// |===
pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String {
db.file_item_tree(file_id.into()).pretty_print()
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
+#[cfg(feature = "tracking")]
use std::sync::atomic::AtomicUsize;
/// Represents a struct used to enforce a numerical limit.
pub struct Limit {
upper_bound: usize,
- #[allow(unused)]
+ #[cfg(feature = "tracking")]
max: AtomicUsize,
}
/// Creates a new limit.
#[inline]
pub const fn new(upper_bound: usize) -> Self {
- Self { upper_bound, max: AtomicUsize::new(0) }
+ Self {
+ upper_bound,
+ #[cfg(feature = "tracking")]
+ max: AtomicUsize::new(0),
+ }
}
/// Creates a new limit.
#[inline]
#[cfg(feature = "tracking")]
pub const fn new_tracking(upper_bound: usize) -> Self {
- Self { upper_bound, max: AtomicUsize::new(1) }
+ Self {
+ upper_bound,
+ #[cfg(feature = "tracking")]
+ max: AtomicUsize::new(1),
+ }
}
/// Gets the underlying numeric limit.
mut qual: CompletedMarker,
) -> CompletedMarker {
loop {
- let use_tree = matches!(p.nth(2), T![*] | T!['{']);
+ let use_tree = mode == Mode::Use && matches!(p.nth(2), T![*] | T!['{']);
if p.at(T![::]) && !use_tree {
let path = qual.precede(p);
p.bump(T![::]);
}
}
+impl ToOwned for AbsPath {
+ type Owned = AbsPathBuf;
+
+ fn to_owned(&self) -> Self::Owned {
+ AbsPathBuf(self.0.to_owned())
+ }
+}
+
impl<'a> TryFrom<&'a Path> for &'a AbsPath {
type Error = &'a Path;
fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> {
let info = version::read_dylib_info(&path)?;
if info.version.0 < 1 || info.version.1 < 47 {
- let msg = format!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", path.display(), info);
+ let msg = format!("proc-macro {} built by {:#?} is not supported by rust-analyzer, please update your Rust version.", path.display(), info);
return Err(io::Error::new(io::ErrorKind::InvalidData, msg));
}
//! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47).
//!
//! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple
-//! interface the rest of rust analyzer can use to talk to the macro
+//! interface the rest of rust-analyzer can use to talk to the macro
//! provider.
//!
//! # Adding a new ABI
expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>,
}
+const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
+
impl ProcMacroSrv {
pub fn expand(&mut self, task: ExpandMacro) -> Result<FlatTree, PanicMessage> {
let expander = self.expander(task.lib.as_ref()).map_err(|err| {
// FIXME: replace this with std's scoped threads once they stabilize
// (then remove dependency on crossbeam)
let result = crossbeam::scope(|s| {
- let res = s
+ let res = match s
+ .builder()
+ .stack_size(EXPANDER_STACK_SIZE)
+ .name(task.macro_name.clone())
.spawn(|_| {
expander
.expand(&task.macro_name, ¯o_body, attributes.as_ref())
.map(|it| FlatTree::new(&it))
- })
- .join();
+ }) {
+ Ok(handle) => handle.join(),
+ Err(e) => std::panic::resume_unwind(Box::new(e)),
+ };
match res {
Ok(res) => res,
/// [`CargoWorkspace`] represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
-/// Note that internally, rust analyzer uses a different structure:
+/// Note that internally, rust-analyzer uses a different structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Packages` & `Targets`: purely cargo-related
/// concepts.
};
let crate_graph = ws.to_crate_graph(
- &mut |_, path: &AbsPath| load_proc_macro(proc_macro_client.as_ref(), path, &[]),
+ &mut |_, path: &AbsPath| {
+ load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[])
+ },
&mut |path: &AbsPath| {
let contents = loader.load_sync(path);
let path = vfs::VfsPath::from(path.to_path_buf());
use crate::lsp_ext;
-pub(crate) type CheckFixes = Arc<FxHashMap<FileId, Vec<Fix>>>;
+pub(crate) type CheckFixes = Arc<FxHashMap<usize, FxHashMap<FileId, Vec<Fix>>>>;
#[derive(Debug, Default, Clone)]
pub struct DiagnosticsMapConfig {
// FIXME: should be FxHashMap<FileId, Vec<ra_id::Diagnostic>>
pub(crate) native: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
// FIXME: should be Vec<flycheck::Diagnostic>
- pub(crate) check: FxHashMap<FileId, Vec<lsp_types::Diagnostic>>,
+ pub(crate) check: FxHashMap<usize, FxHashMap<FileId, Vec<lsp_types::Diagnostic>>>,
pub(crate) check_fixes: CheckFixes,
changes: FxHashSet<FileId>,
}
}
impl DiagnosticCollection {
- pub(crate) fn clear_check(&mut self) {
+ pub(crate) fn clear_check(&mut self, flycheck_id: usize) {
+ if let Some(it) = Arc::make_mut(&mut self.check_fixes).get_mut(&flycheck_id) {
+ it.clear();
+ }
+ if let Some(it) = self.check.get_mut(&flycheck_id) {
+ self.changes.extend(it.drain().map(|(key, _value)| key));
+ }
+ }
+
+ pub(crate) fn clear_check_all(&mut self) {
Arc::make_mut(&mut self.check_fixes).clear();
- self.changes.extend(self.check.drain().map(|(key, _value)| key))
+ self.changes
+ .extend(self.check.values_mut().flat_map(|it| it.drain().map(|(key, _value)| key)))
}
pub(crate) fn clear_native_for(&mut self, file_id: FileId) {
pub(crate) fn add_check_diagnostic(
&mut self,
+ flycheck_id: usize,
file_id: FileId,
diagnostic: lsp_types::Diagnostic,
fix: Option<Fix>,
) {
- let diagnostics = self.check.entry(file_id).or_default();
+ let diagnostics = self.check.entry(flycheck_id).or_default().entry(file_id).or_default();
for existing_diagnostic in diagnostics.iter() {
if are_diagnostics_equal(existing_diagnostic, &diagnostic) {
return;
}
let check_fixes = Arc::make_mut(&mut self.check_fixes);
- check_fixes.entry(file_id).or_default().extend(fix);
+ check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().extend(fix);
diagnostics.push(diagnostic);
self.changes.insert(file_id);
}
file_id: FileId,
) -> impl Iterator<Item = &lsp_types::Diagnostic> {
let native = self.native.get(&file_id).into_iter().flatten();
- let check = self.check.get(&file_id).into_iter().flatten();
+ let check =
+ self.check.values().filter_map(move |it| it.get(&file_id)).into_iter().flatten();
native.chain(check)
}
use crossbeam_channel::{unbounded, Receiver, Sender};
use flycheck::FlycheckHandle;
use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
-use ide_db::base_db::{CrateId, FileLoader, SourceDatabase};
+use ide_db::base_db::{CrateId, FileLoader, SourceDatabase, SourceDatabaseExt};
use lsp_types::{SemanticTokens, Url};
use parking_lot::{Mutex, RwLock};
use proc_macro_api::ProcMacroServer;
pub(crate) fn process_changes(&mut self) -> bool {
let _p = profile::span("GlobalState::process_changes");
- let mut fs_changes = Vec::new();
+ let mut fs_refresh_changes = Vec::new();
// A file was added or deleted
let mut has_structure_changes = false;
if let Some(path) = vfs.file_path(file.file_id).as_path() {
let path = path.to_path_buf();
if reload::should_refresh_for_change(&path, file.change_kind) {
- self.fetch_workspaces_queue
- .request_op(format!("vfs file change: {}", path.display()));
+ fs_refresh_changes.push((path, file.file_id));
}
- fs_changes.push((path, file.change_kind));
if file.is_created_or_deleted() {
has_structure_changes = true;
}
}
+ // Clear native diagnostics when their file gets deleted
if !file.exists() {
self.diagnostics.clear_native_for(file.file_id);
}
self.analysis_host.apply_change(change);
- let raw_database = &self.analysis_host.raw_database();
- self.proc_macro_changed =
- changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
- let crates = raw_database.relevant_crates(file.file_id);
- let crate_graph = raw_database.crate_graph();
+ {
+ let raw_database = self.analysis_host.raw_database();
+ let workspace_structure_change =
+ fs_refresh_changes.into_iter().find(|&(_, file_id)| {
+ !raw_database.source_root(raw_database.file_source_root(file_id)).is_library
+ });
+ if let Some((path, _)) = workspace_structure_change {
+ self.fetch_workspaces_queue
+ .request_op(format!("workspace vfs file change: {}", path.display()));
+ }
+ self.proc_macro_changed =
+ changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| {
+ let crates = raw_database.relevant_crates(file.file_id);
+ let crate_graph = raw_database.crate_graph();
+
+ crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
+ });
+ }
- crates.iter().any(|&krate| crate_graph[krate].is_proc_macro)
- });
true
}
}
// Fixes from `cargo check`.
- for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() {
+ for fix in
+ snap.check_fixes.values().filter_map(|it| it.get(&frange.file_id)).into_iter().flatten()
+ {
// FIXME: this mapping is awkward and shouldn't exist. Refactor
// `snap.check_fixes` to not convert to LSP prematurely.
let intersect_fix_range = fix
//! code here exercise this specific completion, and thus have a fast
//! edit/compile/test cycle.
//!
-//! Note that "Rust Analyzer: Run" action does not allow running a single test
-//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line"
+//! Note that "rust-analyzer: Run" action does not allow running a single test
+//! in release mode in VS Code. There's however "rust-analyzer: Copy Run Command Line"
//! which you can use to paste the command in terminal and add `--release` manually.
use std::sync::Arc;
//! requests/replies and notifications back to the client.
use std::{
fmt,
+ ops::Deref,
sync::Arc,
time::{Duration, Instant},
};
use always_assert::always;
use crossbeam_channel::{select, Receiver};
-use ide_db::base_db::{SourceDatabaseExt, VfsPath};
+use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath};
+use itertools::Itertools;
use lsp_server::{Connection, Notification, Request};
use lsp_types::notification::Notification as _;
use vfs::{ChangeKind, FileId};
let _p = profile::span("GlobalState::handle_event/flycheck");
loop {
match task {
- flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => {
+ flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => {
let snap = self.snapshot();
let diagnostics =
crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
for diag in diagnostics {
match url_to_file_id(&self.vfs.read().0, &diag.url) {
Ok(file_id) => self.diagnostics.add_check_diagnostic(
+ id,
file_id,
diag.diagnostic,
diag.fix,
flycheck::Message::Progress { id, progress } => {
let (state, message) = match progress {
flycheck::Progress::DidStart => {
- self.diagnostics.clear_check();
+ self.diagnostics.clear_check(id);
(Progress::Begin, None)
}
flycheck::Progress::DidCheckCrate(target) => {
let memdocs_added_or_removed = self.mem_docs.take_changes();
if self.is_quiescent() {
- if !was_quiescent {
+ if !was_quiescent
+ && !self.fetch_workspaces_queue.op_requested()
+ && !self.fetch_build_data_queue.op_requested()
+ {
for flycheck in &self.flycheck {
flycheck.update();
}
Ok(())
})?
.on::<lsp_types::notification::DidSaveTextDocument>(|this, params| {
- for flycheck in &this.flycheck {
- flycheck.update();
+ let mut updated = false;
+ if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) {
+ let (vfs, _) = &*this.vfs.read();
+ if let Some(file_id) = vfs.file_id(&vfs_path) {
+ let analysis = this.analysis_host.analysis();
+ // Crates containing or depending on the saved file
+ let crate_ids: Vec<_> = analysis
+ .crate_for(file_id)?
+ .into_iter()
+ .flat_map(|id| {
+ this.analysis_host
+ .raw_database()
+ .crate_graph()
+ .transitive_rev_deps(id)
+ })
+ .sorted()
+ .unique()
+ .collect();
+
+ let crate_root_paths: Vec<_> = crate_ids
+ .iter()
+ .filter_map(|&crate_id| {
+ analysis
+ .crate_root(crate_id)
+ .map(|file_id| {
+ vfs.file_path(file_id).as_path().map(ToOwned::to_owned)
+ })
+ .transpose()
+ })
+ .collect::<ide::Cancellable<_>>()?;
+ let crate_root_paths: Vec<_> =
+ crate_root_paths.iter().map(Deref::deref).collect();
+
+ // Find all workspaces that have at least one target containing the saved file
+ let workspace_ids =
+ this.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
+ project_model::ProjectWorkspace::Cargo { cargo, .. } => {
+ cargo.packages().any(|pkg| {
+ cargo[pkg].targets.iter().any(|&it| {
+ crate_root_paths.contains(&cargo[it].root.as_path())
+ })
+ })
+ }
+ project_model::ProjectWorkspace::Json { project, .. } => project
+ .crates()
+ .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)),
+ project_model::ProjectWorkspace::DetachedFiles { .. } => false,
+ });
+
+ // Find and trigger corresponding flychecks
+ for flycheck in &this.flycheck {
+ for (id, _) in workspace_ids.clone() {
+ if id == flycheck.id() {
+ updated = true;
+ flycheck.update();
+ continue;
+ }
+ }
+ }
+ }
+ if let Some(abs_path) = vfs_path.as_path() {
+ if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
+ this.fetch_workspaces_queue
+ .request_op(format!("DidSaveTextDocument {}", abs_path.display()));
+ }
+ }
}
- if let Ok(abs_path) = from_proto::abs_path(¶ms.text_document.uri) {
- if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) {
- this.fetch_workspaces_queue
- .request_op(format!("DidSaveTextDocument {}", abs_path.display()));
+ if !updated {
+ for flycheck in &this.flycheck {
+ flycheck.update();
}
}
Ok(())
}
if let Err(error) = self.fetch_build_data_error() {
- self.show_and_log_error(
- "rust-analyzer failed to run build scripts".to_string(),
- Some(error),
- );
+ self.show_and_log_error("failed to run build scripts".to_string(), Some(error));
}
let workspaces = self
let files_config = self.config.files();
let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
+ let standalone_server_name =
+ format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
+
if self.proc_macro_clients.is_empty() {
if let Some((path, args)) = self.config.proc_macro_srv() {
+ tracing::info!("Spawning proc-macro servers");
self.proc_macro_clients = self
.workspaces
.iter()
let mut path = path.clone();
if let ProjectWorkspace::Cargo { sysroot, .. } = ws {
- tracing::info!("Found a cargo workspace...");
+ tracing::debug!("Found a cargo workspace...");
if let Some(sysroot) = sysroot.as_ref() {
- tracing::info!("Found a cargo workspace with a sysroot...");
- let server_path = sysroot
- .root()
- .join("libexec")
- .join("rust-analyzer-proc-macro-srv");
+ tracing::debug!("Found a cargo workspace with a sysroot...");
+ let server_path =
+ sysroot.root().join("libexec").join(&standalone_server_name);
if std::fs::metadata(&server_path).is_ok() {
- tracing::info!(
+ tracing::debug!(
"And the server exists at {}",
server_path.display()
);
path = server_path;
args = vec![];
} else {
- tracing::info!(
+ tracing::debug!(
"And the server does not exist at {}",
server_path.display()
);
}
}
- tracing::info!(
- "Using proc-macro server at {} with args {:?}",
- path.display(),
- args
- );
+ tracing::info!(?args, "Using proc-macro server at {}", path.display(),);
ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| {
let error = format!(
- "Failed to run proc_macro_srv from path {}, error: {:?}",
+ "Failed to run proc-macro server from path {}, error: {:?}",
path.display(),
err
);
let mut crate_graph = CrateGraph::default();
for (idx, ws) in self.workspaces.iter().enumerate() {
- let proc_macro_client = self.proc_macro_clients[idx].as_ref();
+ let proc_macro_client = match self.proc_macro_clients.get(idx) {
+ Some(res) => res.as_ref().map_err(|e| &**e),
+ None => Err("Proc macros are disabled"),
+ };
let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
load_proc_macro(
proc_macro_client,
Some(it) => it,
None => {
self.flycheck = Vec::new();
- self.diagnostics.clear_check();
+ self.diagnostics.clear_check_all();
return;
}
};
/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
/// with an identity dummy expander.
pub(crate) fn load_proc_macro(
- server: Result<&ProcMacroServer, &String>,
+ server: Result<&ProcMacroServer, &str>,
path: &AbsPath,
dummy_replace: &[Box<str>],
) -> ProcMacroLoadResult {
};
let expander: Arc<dyn ProcMacroExpander> =
if dummy_replace.iter().any(|replace| &**replace == name) {
- Arc::new(DummyExpander)
+ match kind {
+ ProcMacroKind::Attr => Arc::new(IdentityExpander),
+ _ => Arc::new(EmptyExpander),
+ }
} else {
Arc::new(Expander(expander))
};
}
}
- /// Dummy identity expander, used for proc-macros that are deliberately ignored by the user.
+ /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user.
#[derive(Debug)]
- struct DummyExpander;
+ struct IdentityExpander;
- impl ProcMacroExpander for DummyExpander {
+ impl ProcMacroExpander for IdentityExpander {
fn expand(
&self,
subtree: &tt::Subtree,
Ok(subtree.clone())
}
}
+
+ /// Empty expander, used for proc-macros that are deliberately ignored by the user.
+ #[derive(Debug)]
+ struct EmptyExpander;
+
+ impl ProcMacroExpander for EmptyExpander {
+ fn expand(
+ &self,
+ _: &tt::Subtree,
+ _: Option<&tt::Subtree>,
+ _: &Env,
+ ) -> Result<tt::Subtree, ProcMacroExpansionError> {
+ Ok(tt::Subtree::default())
+ }
+ }
}
pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool {
const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"];
- let file_name = path.file_name().unwrap_or_default();
- if file_name == "Cargo.toml" || file_name == "Cargo.lock" {
+ let file_name = match path.file_name().unwrap_or_default().to_str() {
+ Some(it) => it,
+ None => return false,
+ };
+
+ if let "Cargo.toml" | "Cargo.lock" = file_name {
return true;
}
if change_kind == ChangeKind::Modify {
return false;
}
+
+ // .cargo/config{.toml}
if path.extension().unwrap_or_default() != "rs" {
- if (file_name == "config.toml" || file_name == "config")
- && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")) == Some(true)
- {
- return true;
- }
- return false;
+ let is_cargo_config = matches!(file_name, "config.toml" | "config")
+ && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false);
+ return is_cargo_config;
}
+
if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) {
return true;
}
fn check_code_formatting() {
let sh = &Shell::new().unwrap();
sh.change_dir(sourcegen::project_root());
- sh.set_var("RUSTUP_TOOLCHAIN", "stable");
- let out = cmd!(sh, "rustfmt --version").read().unwrap();
+ let out = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap();
if !out.contains("stable") {
panic!(
"Failed to run rustfmt from toolchain 'stable'. \
)
}
- let res = cmd!(sh, "cargo fmt -- --check").run();
+ let res = cmd!(sh, "rustup run stable cargo fmt -- --check").run();
if res.is_err() {
- let _ = cmd!(sh, "cargo fmt").run();
+ let _ = cmd!(sh, "rustup run stable cargo fmt").run();
}
res.unwrap()
}
}
fn ensure_rustfmt(sh: &Shell) {
- let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default();
+ let version = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap_or_default();
if !version.contains("stable") {
panic!(
"Failed to run rustfmt from toolchain 'stable'. \
pub fn reformat(text: String) -> String {
let sh = Shell::new().unwrap();
- sh.set_var("RUSTUP_TOOLCHAIN", "stable");
ensure_rustfmt(&sh);
let rustfmt_toml = project_root().join("rustfmt.toml");
- let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true")
- .stdin(text)
- .read()
- .unwrap();
+ let mut stdout = cmd!(
+ sh,
+ "rustup run stable rustfmt --config-path {rustfmt_toml} --config fn_single_line=true"
+ )
+ .stdin(text)
+ .read()
+ .unwrap();
if !stdout.ends_with('\n') {
stdout.push('\n');
}
ted::{self, Position},
AstNode, AstToken, Direction,
SyntaxKind::{ATTR, COMMENT, WHITESPACE},
- SyntaxNode,
+ SyntaxNode, SyntaxToken,
};
use super::HasName;
let position = match self.fields().last() {
Some(last_field) => {
- let comma = match last_field
- .syntax()
- .siblings_with_tokens(Direction::Next)
- .filter_map(|it| it.into_token())
- .find(|it| it.kind() == T![,])
- {
- Some(it) => it,
- None => {
- let comma = ast::make::token(T![,]);
- ted::insert(Position::after(last_field.syntax()), &comma);
- comma
- }
- };
+ let comma = get_or_insert_comma_after(last_field.syntax());
Position::after(comma)
}
None => match self.l_curly_token() {
let position = match self.fields().last() {
Some(last_field) => {
- let comma = match last_field
- .syntax()
- .siblings_with_tokens(Direction::Next)
- .filter_map(|it| it.into_token())
- .find(|it| it.kind() == T![,])
- {
- Some(it) => it,
- None => {
- let comma = ast::make::token(T![,]);
- ted::insert(Position::after(last_field.syntax()), &comma);
- comma
- }
- };
+ let syntax = last_field.syntax();
+ let comma = get_or_insert_comma_after(syntax);
Position::after(comma)
}
None => match self.l_curly_token() {
}
}
}
+
+fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken {
+ let comma = match syntax
+ .siblings_with_tokens(Direction::Next)
+ .filter_map(|it| it.into_token())
+ .find(|it| it.kind() == T![,])
+ {
+ Some(it) => it,
+ None => {
+ let comma = ast::make::token(T![,]);
+ ted::insert(Position::after(syntax), &comma);
+ comma
+ }
+ };
+ comma
+}
+
impl ast::StmtList {
pub fn push_front(&self, statement: ast::Stmt) {
ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax());
}
}
+impl ast::VariantList {
+ pub fn add_variant(&self, variant: ast::Variant) {
+ let (indent, position) = match self.variants().last() {
+ Some(last_item) => (
+ IndentLevel::from_node(last_item.syntax()),
+ Position::after(get_or_insert_comma_after(last_item.syntax())),
+ ),
+ None => match self.l_curly_token() {
+ Some(l_curly) => {
+ normalize_ws_between_braces(self.syntax());
+ (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly))
+ }
+ None => (IndentLevel::single(), Position::last_child_of(self.syntax())),
+ },
+ };
+ let elements: Vec<SyntaxElement<_>> = vec![
+ make::tokens::whitespace(&format!("{}{}", "\n", indent)).into(),
+ variant.syntax().clone().into(),
+ ast::make::token(T![,]).into(),
+ ];
+ ted::insert_all(position, elements);
+ }
+}
+
fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
let l = node
.children_with_tokens()
mod tests {
use std::fmt;
+ use stdx::trim_indent;
+ use test_utils::assert_eq_text;
+
use crate::SourceFile;
use super::*;
}",
);
}
+
+ #[test]
+ fn add_variant_to_empty_enum() {
+ let variant = make::variant(make::name("Bar"), None).clone_for_update();
+
+ check_add_variant(
+ r#"
+enum Foo {}
+"#,
+ r#"
+enum Foo {
+ Bar,
+}
+"#,
+ variant,
+ );
+ }
+
+ #[test]
+ fn add_variant_to_non_empty_enum() {
+ let variant = make::variant(make::name("Baz"), None).clone_for_update();
+
+ check_add_variant(
+ r#"
+enum Foo {
+ Bar,
+}
+"#,
+ r#"
+enum Foo {
+ Bar,
+ Baz,
+}
+"#,
+ variant,
+ );
+ }
+
+ #[test]
+ fn add_variant_with_tuple_field_list() {
+ let variant = make::variant(
+ make::name("Baz"),
+ Some(ast::FieldList::TupleFieldList(make::tuple_field_list(std::iter::once(
+ make::tuple_field(None, make::ty("bool")),
+ )))),
+ )
+ .clone_for_update();
+
+ check_add_variant(
+ r#"
+enum Foo {
+ Bar,
+}
+"#,
+ r#"
+enum Foo {
+ Bar,
+ Baz(bool),
+}
+"#,
+ variant,
+ );
+ }
+
+ #[test]
+ fn add_variant_with_record_field_list() {
+ let variant = make::variant(
+ make::name("Baz"),
+ Some(ast::FieldList::RecordFieldList(make::record_field_list(std::iter::once(
+ make::record_field(None, make::name("x"), make::ty("bool")),
+ )))),
+ )
+ .clone_for_update();
+
+ check_add_variant(
+ r#"
+enum Foo {
+ Bar,
+}
+"#,
+ r#"
+enum Foo {
+ Bar,
+ Baz { x: bool },
+}
+"#,
+ variant,
+ );
+ }
+
+ fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) {
+ let enum_ = ast_mut_from_text::<ast::Enum>(before);
+ enum_.variant_list().map(|it| it.add_variant(variant));
+ let after = enum_.to_string();
+ assert_eq_text!(&trim_indent(expected.trim()), &trim_indent(&after.trim()));
+ }
}
pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
- pub fn iterable(&self) -> Option<Expr> { support::child(&self.syntax) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
impl ast::HasAttrs for IfExpr {}
impl IfExpr {
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
- pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
}
impl ast::HasAttrs for WhileExpr {}
impl WhileExpr {
pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
- pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
}
impl MatchGuard {
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
- pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub fn variant(name: ast::Name, field_list: Option<ast::FieldList>) -> ast::Variant {
let field_list = match field_list {
None => String::new(),
- Some(it) => format!("{}", it),
+ Some(it) => match it {
+ ast::FieldList::RecordFieldList(record) => format!(" {}", record),
+ ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple),
+ },
};
ast_from_text(&format!("enum f {{ {}{} }}", name, field_list))
}
}
}
+impl ast::ForExpr {
+ pub fn iterable(&self) -> Option<ast::Expr> {
+ // If the iterable is a BlockExpr, check if the body is missing.
+ // If it is assume the iterable is the expression that is missing instead.
+ let mut exprs = support::children(self.syntax());
+ let first = exprs.next();
+ match first {
+ Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
+ first => first,
+ }
+ }
+}
+
impl ast::HasLoopBody for ast::ForExpr {
fn loop_body(&self) -> Option<ast::BlockExpr> {
let mut exprs = support::children(self.syntax());
}
}
+impl ast::WhileExpr {
+ pub fn condition(&self) -> Option<ast::Expr> {
+ // If the condition is a BlockExpr, check if the body is missing.
+ // If it is assume the condition is the expression that is missing instead.
+ let mut exprs = support::children(self.syntax());
+ let first = exprs.next();
+ match first {
+ Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
+ first => first,
+ }
+ }
+}
+
impl ast::HasLoopBody for ast::WhileExpr {
fn loop_body(&self) -> Option<ast::BlockExpr> {
let mut exprs = support::children(self.syntax());
}
}
}
+
+impl ast::IfExpr {
+ pub fn condition(&self) -> Option<ast::Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+impl ast::MatchGuard {
+ pub fn condition(&self) -> Option<ast::Expr> {
+ support::child(&self.syntax)
+ }
+}
-//! Syntax Tree library used throughout the rust analyzer.
+//! Syntax Tree library used throughout the rust-analyzer.
//!
//! Properties:
//! - easy and fast incremental re-parsing
| "value"
| "trait"
| "self_ty"
+ | "iterable"
+ | "condition"
);
if manually_implemented {
return;
.expect("failed to spawn thread");
NotifyHandle { sender, _thread: thread }
}
+
fn set_config(&mut self, config: loader::Config) {
self.sender.send(Message::Config(config)).unwrap();
}
+
fn invalidate(&mut self, path: AbsPathBuf) {
self.sender.send(Message::Invalidate(path)).unwrap();
}
+
fn load_sync(&mut self, path: &AbsPath) -> Option<Vec<u8>> {
read(path)
}
fn new(sender: loader::Sender) -> NotifyActor {
NotifyActor { sender, watched_entries: Vec::new(), watcher: None }
}
+
fn next_event(&self, receiver: &Receiver<Message>) -> Option<Event> {
let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver);
select! {
recv(watcher_receiver.unwrap_or(&never())) -> it => Some(Event::NotifyEvent(it.unwrap())),
}
}
+
fn run(mut self, inbox: Receiver<Message>) {
while let Some(event) = self.next_event(&inbox) {
- tracing::debug!("vfs-notify event: {:?}", event);
+ tracing::debug!(?event, "vfs-notify event");
match event {
Event::Message(msg) => match msg {
Message::Config(config) => {
In general, I use one of the following workflows for fixing bugs and implementing features:
If the problem concerns only internal parts of rust-analyzer (i.e. I don't need to touch the `rust-analyzer` crate or TypeScript code), there is a unit-test for it.
-So, I use **Rust Analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging.
+So, I use **rust-analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging.
As a sanity check after I'm done, I use `cargo xtask install --server` and **Reload Window** action in VS Code to verify that the thing works as I expect.
If the problem concerns only the VS Code extension, I use **Run Installed Extension** launch configuration from `launch.json`.
There are also several VS Code commands which might be of interest:
-* `Rust Analyzer: Status` shows some memory-usage statistics.
+* `rust-analyzer: Status` shows some memory-usage statistics.
-* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection.
+* `rust-analyzer: Syntax Tree` shows syntax tree of the current file/selection.
-* `Rust Analyzer: View Hir` shows the HIR expressions within the function containing the cursor.
+* `rust-analyzer: View Hir` shows the HIR expressions within the function containing the cursor.
You can hover over syntax nodes in the opened text file to see the appropriate
rust code that it refers to and the rust editor will also highlight the proper
./rust-rust-analyzer # Note the name!
```
-Additionally, it assumes that the remote for `rust-analyzer` is called `upstream` (I use `origin` to point to my fork).
+The remote for `rust-analyzer` must be called `upstream` (I use `origin` to point to my fork).
+In addition, for `xtask promote` (see below), `rust-rust-analyzer` must have a `rust-analyzer` remote pointing to this repository on GitHub.
`release` calls the GitHub API calls to scrape pull request comments and categorize them in the changelog.
This step uses the `curl` and `jq` applications, which need to be available in `PATH`.
* push it to `upstream`. This triggers GitHub Actions which:
* runs `cargo xtask dist` to package binaries and VS Code extension
* makes a GitHub release
- * pushes VS Code extension to the marketplace
+ * publishes the VS Code extension to the marketplace
* call the GitHub API for PR details
* create a new changelog in `rust-analyzer.github.io`
3. While the release is in progress, fill in the changelog
4. Commit & push the changelog
5. Tweet
-6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule.
+6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's subtree.
Self-approve the PR.
If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console.
### Testing
-Rust Analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on.
+rust-analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on.
The outermost boundary is the `rust-analyzer` crate, which defines an LSP interface in terms of stdio.
We do integration testing of this component, by feeding it with a stream of LSP requests and checking responses.
## Inputs
-Rust Analyzer never does any I/O itself, all inputs get passed explicitly via
+rust-analyzer never does any I/O itself, all inputs get passed explicitly via
the `AnalysisHost::apply_change` method, which accepts a single argument, a
`Change`. [`Change`] is a builder for a single change
"transaction", so it suffices to study its methods to understand all of the
== Troubleshooting
Start with looking at the rust-analyzer version.
-Try **Rust Analyzer: Show RA Version** in VS Code (using **Command Palette** feature typically activated by Ctrl+Shift+P) or `rust-analyzer --version` in the command line.
+Try **rust-analyzer: Show RA Version** in VS Code (using **Command Palette** feature typically activated by Ctrl+Shift+P) or `rust-analyzer --version` in the command line.
If the date is more than a week ago, it's better to update rust-analyzer version.
The next thing to check would be panic messages in rust-analyzer's log.
The root cause for many "`nothing works`" problems is that rust-analyzer fails to understand the project structure.
To debug that, first note the `rust-analyzer` section in the status bar.
If it has an error icon and red, that's the problem (hover will have somewhat helpful error message).
-**Rust Analyzer: Status** prints dependency information for the current file.
+**rust-analyzer: Status** prints dependency information for the current file.
Finally, `RA_LOG=project_model=debug` enables verbose logs during project loading.
If rust-analyzer outright crashes, try running `rust-analyzer analysis-stats /path/to/project/directory/` on the command line.
{
"command": "rust-analyzer.syntaxTree",
"title": "Show Syntax Tree",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.viewHir",
"title": "View Hir",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.viewFileText",
"title": "View File Text (as seen by the server)",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.viewItemTree",
"title": "Debug ItemTree",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.viewCrateGraph",
"title": "View Crate Graph",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.viewFullCrateGraph",
"title": "View Crate Graph (Full)",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.expandMacro",
"title": "Expand macro recursively",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.matchingBrace",
"title": "Find matching brace",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.parentModule",
"title": "Locate parent module",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.joinLines",
"title": "Join lines",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.run",
"title": "Run",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.copyRunCommandLine",
"title": "Copy Run Command Line",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.debug",
"title": "Debug",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.newDebugConfig",
"title": "Generate launch configuration",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.analyzerStatus",
"title": "Status",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.memoryUsage",
"title": "Memory Usage (Clears Database)",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.shuffleCrateGraph",
"title": "Shuffle Crate Graph",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.reloadWorkspace",
"title": "Reload workspace",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.reload",
"title": "Restart server",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.onEnter",
"title": "Enhanced enter key",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.ssr",
"title": "Structural Search Replace",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.serverVersion",
"title": "Show RA Version",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.toggleInlayHints",
"title": "Toggle inlay hints",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.openDocs",
"title": "Open docs under cursor",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.openCargoToml",
"title": "Open Cargo.toml",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.peekTests",
"title": "Peek related tests",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.moveItemUp",
"title": "Move item up",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
},
{
"command": "rust-analyzer.moveItemDown",
"title": "Move item down",
- "category": "Rust Analyzer"
+ "category": "rust-analyzer"
}
],
"keybindings": [
],
"configuration": {
"type": "object",
- "title": "Rust Analyzer",
+ "title": "rust-analyzer",
"properties": {
"rust-analyzer.cargoRunner": {
"type": [
"default": false,
"type": "boolean"
},
+ "rust-analyzer.typing.continueCommentsOnNewline": {
+ "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.",
+ "default": true,
+ "type": "boolean"
+ },
"$generated-start": {},
"rust-analyzer.assist.expressionFillDefault": {
"markdownDescription": "Placeholder expression to use for missing expressions in assists.",
readonly extensionId = "rust-lang.rust-analyzer";
readonly rootSection = "rust-analyzer";
- private readonly requiresWorkspaceReloadOpts = ["serverPath", "server"].map(
- (opt) => `${this.rootSection}.${opt}`
- );
+ private readonly requiresWorkspaceReloadOpts = [
+ "serverPath",
+ "server",
+ // FIXME: This shouldn't be here, changing this setting should reload
+ // `continueCommentsOnNewline` behavior without restart
+ "typing",
+ ].map((opt) => `${this.rootSection}.${opt}`);
private readonly requiresReloadOpts = [
"cargo",
"procMacro",
return this.get<boolean>("restartServerOnConfigChange");
}
+ get typingContinueCommentsOnNewline() {
+ return this.get<boolean>("typing.continueCommentsOnNewline");
+ }
+
get debug() {
let sourceFileMap = this.get<Record<string, string> | "auto">("debug.sourceFileMap");
if (sourceFileMap !== "auto") {
warnAboutExtensionConflicts();
- ctx.pushCleanup(configureLanguage());
+ if (config.typingContinueCommentsOnNewline) {
+ ctx.pushCleanup(configureLanguage());
+ }
vscode.workspace.onDidChangeConfiguration(
(_) =>
};
mod map;
-pub use map::ArenaMap;
+pub use map::{ArenaMap, Entry, OccupiedEntry, VacantEntry};
/// The raw index of a value in an arena.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
Arena { data: Vec::new() }
}
+ /// Create a new empty arena with specific capacity.
+ ///
+ /// ```
+ /// let arena: la_arena::Arena<i32> = la_arena::Arena::with_capacity(42);
+ /// assert!(arena.is_empty());
+ /// ```
+ pub fn with_capacity(capacity: usize) -> Arena<T> {
+ Arena { data: Vec::with_capacity(capacity) }
+ }
+
/// Empties the arena, removing all contained values.
///
/// ```
}
impl<T, V> ArenaMap<Idx<T>, V> {
+ /// Creates a new empty map.
+ pub const fn new() -> Self {
+ Self { v: Vec::new(), _ty: PhantomData }
+ }
+
+ /// Create a new empty map with specific capacity.
+ pub fn with_capacity(capacity: usize) -> Self {
+ Self { v: Vec::with_capacity(capacity), _ty: PhantomData }
+ }
+
+ /// Reserves capacity for at least additional more elements to be inserted in the map.
+ pub fn reserve(&mut self, additional: usize) {
+ self.v.reserve(additional);
+ }
+
+ /// Clears the map, removing all elements.
+ pub fn clear(&mut self) {
+ self.v.clear();
+ }
+
+ /// Shrinks the capacity of the map as much as possible.
+ pub fn shrink_to_fit(&mut self) {
+ let min_len = self.v.iter().rposition(|slot| slot.is_some()).map_or(0, |i| i + 1);
+ self.v.truncate(min_len);
+ self.v.shrink_to_fit();
+ }
+
+ /// Returns whether the map contains a value for the specified index.
+ pub fn contains_idx(&self, idx: Idx<T>) -> bool {
+ matches!(self.v.get(Self::to_idx(idx)), Some(Some(_)))
+ }
+
+ /// Removes an index from the map, returning the value at the index if the index was previously in the map.
+ pub fn remove(&mut self, idx: Idx<T>) -> Option<V> {
+ self.v.get_mut(Self::to_idx(idx))?.take()
+ }
+
/// Inserts a value associated with a given arena index into the map.
- pub fn insert(&mut self, idx: Idx<T>, t: V) {
+ ///
+ /// If the map did not have this index present, None is returned.
+ /// Otherwise, the value is updated, and the old value is returned.
+ pub fn insert(&mut self, idx: Idx<T>, t: V) -> Option<V> {
let idx = Self::to_idx(idx);
self.v.resize_with((idx + 1).max(self.v.len()), || None);
- self.v[idx] = Some(t);
+ self.v[idx].replace(t)
}
/// Returns a reference to the value associated with the provided index
self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
}
+ /// Gets the given key's corresponding entry in the map for in-place manipulation.
+ pub fn entry(&mut self, idx: Idx<T>) -> Entry<'_, Idx<T>, V> {
+ let idx = Self::to_idx(idx);
+ self.v.resize_with((idx + 1).max(self.v.len()), || None);
+ match &mut self.v[idx] {
+ slot @ Some(_) => Entry::Occupied(OccupiedEntry { slot, _ty: PhantomData }),
+ slot @ None => Entry::Vacant(VacantEntry { slot, _ty: PhantomData }),
+ }
+ }
+
fn to_idx(idx: Idx<T>) -> usize {
u32::from(idx.into_raw()) as usize
}
impl<T, V> Default for ArenaMap<Idx<V>, T> {
fn default() -> Self {
- ArenaMap { v: Vec::new(), _ty: PhantomData }
+ Self::new()
+ }
+}
+
+impl<T, V> Extend<(Idx<V>, T)> for ArenaMap<Idx<V>, T> {
+ fn extend<I: IntoIterator<Item = (Idx<V>, T)>>(&mut self, iter: I) {
+ iter.into_iter().for_each(move |(k, v)| {
+ self.insert(k, v);
+ });
+ }
+}
+
+impl<T, V> FromIterator<(Idx<V>, T)> for ArenaMap<Idx<V>, T> {
+ fn from_iter<I: IntoIterator<Item = (Idx<V>, T)>>(iter: I) -> Self {
+ let mut this = Self::new();
+ this.extend(iter);
+ this
+ }
+}
+
+/// A view into a single entry in a map, which may either be vacant or occupied.
+///
+/// This `enum` is constructed from the [`entry`] method on [`ArenaMap`].
+///
+/// [`entry`]: ArenaMap::entry
+pub enum Entry<'a, IDX, V> {
+ /// A vacant entry.
+ Vacant(VacantEntry<'a, IDX, V>),
+ /// An occupied entry.
+ Occupied(OccupiedEntry<'a, IDX, V>),
+}
+
+impl<'a, IDX, V> Entry<'a, IDX, V> {
+ /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable reference to
+ /// the value in the entry.
+ pub fn or_insert(self, default: V) -> &'a mut V {
+ match self {
+ Self::Vacant(ent) => ent.insert(default),
+ Self::Occupied(ent) => ent.into_mut(),
+ }
+ }
+
+ /// Ensures a value is in the entry by inserting the result of the default function if empty, and returns
+ /// a mutable reference to the value in the entry.
+ pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+ match self {
+ Self::Vacant(ent) => ent.insert(default()),
+ Self::Occupied(ent) => ent.into_mut(),
+ }
+ }
+
+ /// Provides in-place mutable access to an occupied entry before any potential inserts into the map.
+ pub fn and_modify<F: FnOnce(&mut V)>(mut self, f: F) -> Self {
+ if let Self::Occupied(ent) = &mut self {
+ f(ent.get_mut());
+ }
+ self
+ }
+}
+
+impl<'a, IDX, V> Entry<'a, IDX, V>
+where
+ V: Default,
+{
+ /// Ensures a value is in the entry by inserting the default value if empty, and returns a mutable reference
+ /// to the value in the entry.
+ pub fn or_default(self) -> &'a mut V {
+ self.or_insert_with(Default::default)
+ }
+}
+
+/// A view into an vacant entry in a [`ArenaMap`]. It is part of the [`Entry`] enum.
+pub struct VacantEntry<'a, IDX, V> {
+ slot: &'a mut Option<V>,
+ _ty: PhantomData<IDX>,
+}
+
+impl<'a, IDX, V> VacantEntry<'a, IDX, V> {
+ /// Sets the value of the entry with the `VacantEntry`’s key, and returns a mutable reference to it.
+ pub fn insert(self, value: V) -> &'a mut V {
+ self.slot.insert(value)
+ }
+}
+
+/// A view into an occupied entry in a [`ArenaMap`]. It is part of the [`Entry`] enum.
+pub struct OccupiedEntry<'a, IDX, V> {
+ slot: &'a mut Option<V>,
+ _ty: PhantomData<IDX>,
+}
+
+impl<'a, IDX, V> OccupiedEntry<'a, IDX, V> {
+ /// Gets a reference to the value in the entry.
+ pub fn get(&self) -> &V {
+ self.slot.as_ref().expect("Occupied")
+ }
+
+ /// Gets a mutable reference to the value in the entry.
+ pub fn get_mut(&mut self) -> &mut V {
+ self.slot.as_mut().expect("Occupied")
+ }
+
+ /// Converts the entry into a mutable reference to its value.
+ pub fn into_mut(self) -> &'a mut V {
+ self.slot.as_mut().expect("Occupied")
+ }
+
+ /// Sets the value of the entry with the `OccupiedEntry`’s key, and returns the entry’s old value.
+ pub fn insert(&mut self, value: V) -> V {
+ self.slot.replace(value).expect("Occupied")
+ }
+
+ /// Takes the value of the entry out of the map, and returns it.
+ pub fn remove(self) -> V {
+ self.slot.take().expect("Occupied")
}
}
cmd!(sh, "git switch master").run()?;
cmd!(sh, "git fetch upstream").run()?;
cmd!(sh, "git reset --hard upstream/master").run()?;
- cmd!(sh, "git submodule update --recursive").run()?;
let date = date_iso(sh)?;
let branch = format!("rust-analyzer-{date}");
cmd!(sh, "git switch -c {branch}").run()?;
- {
- let _dir = sh.push_dir("src/tools/rust-analyzer");
- cmd!(sh, "git fetch origin").run()?;
- cmd!(sh, "git reset --hard origin/release").run()?;
- }
- cmd!(sh, "git add src/tools/rust-analyzer").run()?;
- cmd!(sh, "git commit -m':arrow_up: rust-analyzer'").run()?;
+ cmd!(sh, "git subtree pull -m ':arrow_up: rust-analyzer' -P src/tools/rust-analyzer rust-analyzer release").run()?;
+
if !self.dry_run {
cmd!(sh, "git push -u origin {branch}").run()?;
cmd!(
libc = { version = "0.2.79", features = ["align"] }
# Ensure default features of libz-sys, which are disabled in some scenarios.
libz-sys = { version = "1.1.2" }
-
-# looks like the only user of deprecated `use_std` feature is `combine`, so this
-# can be removed if/when https://github.com/Marwes/combine/pull/348 be merged and released.
+# The only user of memchr's deprecated `use_std` feature is `combine`, so this can be
+# removed if/when https://github.com/Marwes/combine/pull/348 is merged and released.
memchr = { version = "2.5", features = ["std", "use_std"] }
-# same for regex
+# Ensure default features of regex, which are disabled in some scenarios.
regex = { version = "1.5.6" }
proc-macro2 = { version = "1", features = ["default"] }
quote = { version = "1", features = ["default"] }
process.setMaxListeners(opts["jobs"] + 1);
}
+ // We catch this "event" to display a nicer message in case of unexpected exit (because of a
+ // missing `--no-sandbox`).
+ const exitHandling = (code) => {
+ if (!opts["no_sandbox"]) {
+ console.log("");
+ console.log(
+ "`browser-ui-test` crashed unexpectedly. Please try again with adding `--test-args \
+--no-sandbox` at the end. For example: `x.py test src/test/rustdoc-gui --test-args --no-sandbox`");
+ console.log("");
+ }
+ };
+ process.on('exit', exitHandling);
+
const tests_queue = [];
let results = {
successful: [],
}
status_bar.finish();
+ // We don't need this listener anymore.
+ process.removeListener("exit", exitHandling);
+
if (debug) {
results.successful.sort(by_filename);
results.successful.forEach(r => {
fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) {
let (kind, span) = match expr.kind {
- ast::ExprKind::MethodCall(ref segment, ref expressions, _) => {
+ ast::ExprKind::MethodCall(ref segment, ref receiver, ref expressions, _) => {
let types = if let Some(ref generic_args) = segment.args {
if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
data.args
} else {
vec![]
};
- let span = mk_sp(expressions[0].span.hi(), expr.span.hi());
+ let span = mk_sp(receiver.span.hi(), expr.span.hi());
let kind = ChainItemKind::MethodCall(segment.clone(), types, expressions.clone());
(kind, span)
}
format!("::<{}>", type_list.join(", "))
};
let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str);
- rewrite_call(context, &callee_str, &args[1..], span, shape)
+ rewrite_call(context, &callee_str, &args, span, shape)
}
}
// is a try! macro, we'll convert it to shorthand when the option is set.
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> {
match expr.kind {
- ast::ExprKind::MethodCall(_, ref expressions, _) => {
- Some(Self::convert_try(&expressions[0], context))
+ ast::ExprKind::MethodCall(_, ref receiver, _, _) => {
+ Some(Self::convert_try(&receiver, context))
}
ast::ExprKind::Field(ref subexpr, _)
| ast::ExprKind::Try(ref subexpr)
#[cfg(unix)]
pub fn check(path: &Path, bad: &mut bool) {
+ use std::ffi::OsStr;
+
const ALLOWED: &[&str] = &["configure"];
crate::walk_no_read(
},
&mut |entry| {
let file = entry.path();
- let filename = file.file_name().unwrap().to_string_lossy();
- let extensions = [".py", ".sh"];
- if extensions.iter().any(|e| filename.ends_with(e)) {
+ let extension = file.extension();
+ let scripts = ["py", "sh", "ps1"];
+ if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) {
return;
}
} else if python2 {
PYTHON2
} else {
- // We would have returned early if we found that python is installed ...
- // maybe this should panic with an error instead?
- PYTHON
+ // Python was not found on path, so exit
+ eprintln!("Unable to find python in your PATH. Please check it is installed.");
+ process::exit(1);
}
}
--- /dev/null
+#!/usr/bin/env pwsh
+
+# See x.sh for why these scripts exist.
+
+$xpy = Join-Path $PSScriptRoot x.py
+# Start-Process for some reason splits arguments on spaces. (Isn't powershell supposed to be simpler than bash?)
+# Double-quote all the arguments so it doesn't do that.
+$xpy_args = @("""$xpy""")
+foreach ($arg in $args) {
+ $xpy_args += """$arg"""
+}
+
+foreach ($python in "py", "python3", "python", "python2") {
+ # NOTE: this only tests that the command exists in PATH, not that it's actually
+ # executable. The latter is not possible in a portable way, see
+ # https://github.com/PowerShell/PowerShell/issues/12625.
+ if (Get-Command $python -ErrorAction SilentlyContinue) {
+ if ($python -eq "py") {
+ # Use python3, not python2
+ $xpy_args = @("-3") + $xpy_args
+ }
+ $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args
+ Exit $process.ExitCode
+ }
+}
+
+Write-Error "${PSCommandPath}: error: did not find python installed"
+Exit 1
-#!/usr/bin/env bash
+#!/usr/bin/env python3
+# Some systems don't have `python3` in their PATH. This isn't supported by x.py directly;
+# they should use `x.sh` or `x.ps1` instead.
-# Modern Linux and macOS systems commonly only have a thing called `python3` and
-# not `python`, while Windows commonly does not have `python3`, so we cannot
-# directly use python in the shebang and have it consistently work. Instead we
-# embed some bash to look for a python to run the rest of the script.
-#
-# On Windows, `py -3` sometimes works. We need to try it first because `python3`
-# sometimes tries to launch the app store on Windows.
-'''':
-for PYTHON in "py -3" python3 python python2; do
- if command -v $PYTHON >/dev/null; then
- exec $PYTHON "$0" "$@"
- break
- fi
-done
-echo "$0: error: did not find python installed" >&2
-exit 1
-'''
-
-# The rest of this file is Python.
-#
# This file is only a "symlink" to bootstrap.py, all logic should go there.
import os
import sys
# If this is python2, check if python3 is available and re-execute with that
-# interpreter.
+# interpreter. Only python3 allows downloading CI LLVM.
#
-# `./x.py` would not normally benefit from this because the bash above tries
-# python3 before 2, but this matters if someone ran `python x.py` and their
-# system's `python` is python2.
+# This matters if someone's system `python` is python2.
if sys.version_info.major < 3:
try:
os.execvp("py", ["py", "-3"] + sys.argv)
--- /dev/null
+#!/bin/sh
+
+# Modern Linux and macOS systems commonly only have a thing called `python3` and
+# not `python`, while Windows commonly does not have `python3`, so we cannot
+# directly use python in the x.py shebang and have it consistently work. Instead we
+# have a shell script to look for a python to run x.py.
+
+set -eu
+
+realpath() {
+ if [ -d "$1" ]; then
+ CDPATH='' command cd "$1" && pwd -P
+ else
+ echo "$(realpath "$(dirname "$1")")/$(basename "$1")"
+ fi
+}
+
+xpy=$(dirname "$(realpath "$0")")/x.py
+
+# On Windows, `py -3` sometimes works. We need to try it first because `python3`
+# sometimes tries to launch the app store on Windows.
+for SEARCH_PYTHON in py python3 python python2; do
+ if python=$(command -v $SEARCH_PYTHON) && [ -x "$python" ]; then
+ if [ $SEARCH_PYTHON = py ]; then
+ extra_arg="-3"
+ else
+ extra_arg=""
+ fi
+ exec "$python" $extra_arg "$xpy" "$@"
+ fi
+done
+echo "$0: error: did not find python installed" >&2
+exit 1