diff options
212 files changed, 3193 insertions, 1739 deletions
diff --git a/.travis.yml b/.travis.yml index 3f2e43ab86d..9e46e6b8ef6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ matrix: fast_finish: true include: # Images used in testing PR and try-build should be run first. - - env: IMAGE=x86_64-gnu-llvm-5.0 RUST_BACKTRACE=1 + - env: IMAGE=x86_64-gnu-llvm-6.0 RUST_BACKTRACE=1 if: type = pull_request OR branch = auto - env: IMAGE=dist-x86_64-linux DEPLOY=1 diff --git a/Cargo.lock b/Cargo.lock index be4a1c2f1d3..7e03474565d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,7 +87,7 @@ dependencies = [ "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1813,7 +1813,7 @@ name = "rand_chacha" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1835,7 +1835,7 @@ name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1860,7 +1860,7 @@ name = "rand_xorshift" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2195,8 +2195,12 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "compiler_builtins 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-std-workspace-core 1.0.0", +] [[package]] name = "rustc-hash" @@ -2315,7 +2319,7 @@ dependencies = [ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_llvm 0.0.0", ] @@ -2331,7 +2335,7 @@ dependencies = [ "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", "rustc_codegen_utils 0.0.0", @@ -2892,6 +2896,7 @@ dependencies = [ "panic_unwind 0.0.0", "profiler_builtins 0.0.0", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_asan 0.0.0", "rustc_lsan 0.0.0", "rustc_msan 0.0.0", @@ -3578,7 +3583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-ap-serialize 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2c0e8161e956647592a737074736e6ce05ea36b70c770ea8cca3eb9cb33737" "checksum rustc-ap-syntax 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1adc189e5e4500a4167b9afa04e67067f40d0039e0e05870c977bebb561f065a" "checksum rustc-ap-syntax_pos 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4d42c430dbb0be4377bfe6aa5099074c63ac8796b24098562c2e2154aecc5652" -"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" +"checksum rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "82ae957aa1b3055d8e086486723c0ccd3d7b8fa190ae8fa2e35543b6171c810e" "checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c6d5a683c6ba4ed37959097e88d71c9e8e26659a3cb5be8b389078e7ad45306" "checksum rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40f06724db71e18d68b3b946fdf890ca8c921d9edccc1404fdfdb537b0d12649" diff --git a/README.md b/README.md index 37442661bcb..dc013a1ad2b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ standard library, and documentation. Read ["Installation"] from [The Book]. -["Installation"]: https://doc.rust-lang.org/book/second-edition/ch01-01-installation.html +["Installation"]: https://doc.rust-lang.org/book/ch01-01-installation.html [The Book]: https://doc.rust-lang.org/book/index.html ## Building from Source diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 3e91c2b3e86..0f7b6c22e1c 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "bootstrap" version = "0.0.0" +edition = "2018" [lib] name = "bootstrap" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index c1d56865da5..405fc871eef 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -21,20 +21,20 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::{Duration, Instant}; -use cache::{Cache, Interned, INTERNER}; -use check; -use compile; -use dist; -use doc; -use flags::Subcommand; -use install; -use native; -use test; -use tool; -use util::{add_lib_path, exe, libdir}; -use {Build, DocTests, Mode, GitRepo}; - -pub use Compiler; +use crate::cache::{Cache, Interned, INTERNER}; +use crate::check; +use crate::compile; +use crate::dist; +use crate::doc; +use crate::flags::Subcommand; +use crate::install; +use crate::native; +use crate::test; +use crate::tool; +use crate::util::{add_lib_path, exe, libdir}; +use crate::{Build, DocTests, Mode, GitRepo}; + +pub use crate::Compiler; use petgraph::graph::NodeIndex; use petgraph::Graph; @@ -1252,7 +1252,7 @@ impl<'a> Builder<'a> { #[cfg(test)] mod __test { use super::*; - use config::Config; + use crate::config::Config; use std::thread; fn configure(host: &[&str], target: &[&str]) -> Config { diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index 0b561a3523f..165cffa4587 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -23,7 +23,7 @@ use std::path::{Path, PathBuf}; use std::sync::Mutex; use std::cmp::{PartialOrd, Ord, Ordering}; -use builder::Step; +use crate::builder::Step; pub struct Interned<T>(usize, PhantomData<*const T>); diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index d5da0cabec8..3d2b3a2c9de 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -39,9 +39,9 @@ use std::process::Command; use build_helper::output; use cc; -use {Build, GitRepo}; -use config::Target; -use cache::Interned; +use crate::{Build, GitRepo}; +use crate::config::Target; +use crate::cache::Interned; // The `cc` crate doesn't provide a way to obtain a path to the detected archiver, // so use some simplified logic here. First we respect the environment variable `AR`, then diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 878b6ed73a3..8756ec944c2 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -20,8 +20,8 @@ use std::process::Command; use build_helper::output; -use Build; -use config::Config; +use crate::Build; +use crate::config::Config; // The version number pub const CFG_RELEASE_NUM: &str = "1.33.0"; diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 0c6dbb06bb8..84e7c40e455 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -10,11 +10,12 @@ //! Implementation of compiling the compiler and standard library, in "check" mode. -use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot}; -use builder::{RunConfig, Builder, ShouldRun, Step}; -use tool::{prepare_tool_cargo, SourceType}; -use {Compiler, Mode}; -use cache::{INTERNER, Interned}; +use crate::compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, + add_to_sysroot}; +use crate::builder::{RunConfig, Builder, ShouldRun, Step}; +use crate::tool::{prepare_tool_cargo, SourceType}; +use crate::{Compiler, Mode}; +use crate::cache::{INTERNER, Interned}; use std::path::PathBuf; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index 87f194fb7d2..dc42159d068 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -19,7 +19,7 @@ use std::fs; use std::io::{self, ErrorKind}; use std::path::Path; -use Build; +use crate::Build; pub fn clean(build: &Build, all: bool) { rm_rf("tmp".as_ref()); diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 689d0530f8b..61a04b97206 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -29,12 +29,12 @@ use build_helper::{output, mtime, up_to_date}; use filetime::FileTime; use serde_json; -use util::{exe, libdir, is_dylib}; -use {Compiler, Mode, GitRepo}; -use native; +use crate::util::{exe, libdir, is_dylib}; +use crate::{Compiler, Mode, GitRepo}; +use crate::native; -use cache::{INTERNER, Interned}; -use builder::{Step, RunConfig, ShouldRun, Builder}; +use crate::cache::{INTERNER, Interned}; +use crate::builder::{Step, RunConfig, ShouldRun, Builder}; #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] pub struct Std { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 1dafbe148af..2ae9da9c085 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -22,9 +22,9 @@ use std::cmp; use num_cpus; use toml; -use cache::{INTERNER, Interned}; -use flags::Flags; -pub use flags::Subcommand; +use crate::cache::{INTERNER, Interned}; +use crate::flags::Flags; +pub use crate::flags::Subcommand; /// Global configuration for the entire build and/or bootstrap. /// diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index f03eefb7a12..927f9bf8ddb 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -26,13 +26,13 @@ use std::process::{Command, Stdio}; use build_helper::output; -use {Compiler, Mode, LLVM_TOOLS}; -use channel; -use util::{libdir, is_dylib, exe}; -use builder::{Builder, RunConfig, ShouldRun, Step}; -use compile; -use tool::{self, Tool}; -use cache::{INTERNER, Interned}; +use crate::{Compiler, Mode, LLVM_TOOLS}; +use crate::channel; +use crate::util::{libdir, is_dylib, exe}; +use crate::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::compile; +use crate::tool::{self, Tool}; +use crate::cache::{INTERNER, Interned}; use time; pub fn pkgname(builder: &Builder, component: &str) -> String { diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 2d0625b26db..217328adfbf 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -22,15 +22,15 @@ use std::fs; use std::io; use std::path::{PathBuf, Path}; -use Mode; +use crate::Mode; use build_helper::up_to_date; -use util::symlink_dir; -use builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; -use tool::{self, prepare_tool_cargo, Tool, SourceType}; -use compile; -use cache::{INTERNER, Interned}; -use config::Config; +use crate::util::symlink_dir; +use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; +use crate::tool::{self, prepare_tool_cargo, Tool, SourceType}; +use crate::compile; +use crate::cache::{INTERNER, Interned}; +use crate::config::Config; macro_rules! book { ($($name:ident, $path:expr, $book_name:expr;)+) => { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index c49da8fc734..14e2f69432d 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -19,12 +19,12 @@ use std::process; use getopts::Options; -use builder::Builder; -use config::Config; -use metadata; -use {Build, DocTests}; +use crate::builder::Builder; +use crate::config::Config; +use crate::metadata; +use crate::{Build, DocTests}; -use cache::{Interned, INTERNER}; +use crate::cache::{Interned, INTERNER}; /// Deserialized version of all flags for this compile. pub struct Flags { diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index cb28698aa3d..aebcfb45195 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -18,11 +18,11 @@ use std::fs; use std::path::{Path, PathBuf, Component}; use std::process::Command; -use dist::{self, pkgname, sanitize_sh, tmpdir}; +use crate::dist::{self, pkgname, sanitize_sh, tmpdir}; -use builder::{Builder, RunConfig, ShouldRun, Step}; -use cache::Interned; -use config::Config; +use crate::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::cache::Interned; +use crate::config::Config; pub fn install_docs(builder: &Builder, stage: u32, host: Interned<String>) { install_sh(builder, "docs", "rust-docs", stage, Some(host)); diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs index f7b1c50f0fd..a9da2c491da 100644 --- a/src/bootstrap/job.rs +++ b/src/bootstrap/job.rs @@ -42,7 +42,7 @@ use std::env; use std::io; use std::mem; -use Build; +use crate::Build; type HANDLE = *mut u8; type BOOL = i32; diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index c8792918db2..c5b8f19eee6 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -159,7 +159,7 @@ use std::os::windows::fs::symlink_file; use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime}; use filetime::FileTime; -use util::{exe, libdir, OutputFolder, CiEnv}; +use crate::util::{exe, libdir, OutputFolder, CiEnv}; mod cc_detect; mod channel; @@ -188,7 +188,7 @@ mod job; mod job { use libc; - pub unsafe fn setup(build: &mut ::Build) { + pub unsafe fn setup(build: &mut crate::Build) { if build.config.low_priority { libc::setpriority(libc::PRIO_PGRP as _, 0, 10); } @@ -197,14 +197,14 @@ mod job { #[cfg(any(target_os = "haiku", not(any(unix, windows))))] mod job { - pub unsafe fn setup(_build: &mut ::Build) { + pub unsafe fn setup(_build: &mut crate::Build) { } } -pub use config::Config; -use flags::Subcommand; -use cache::{Interned, INTERNER}; -use toolstate::ToolState; +pub use crate::config::Config; +use crate::flags::Subcommand; +use crate::cache::{Interned, INTERNER}; +use crate::toolstate::ToolState; const LLVM_TOOLS: &[&str] = &[ "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index fa0b1983510..bb503e8b8d3 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -16,8 +16,8 @@ use std::collections::HashSet; use build_helper::output; use serde_json; -use {Build, Crate}; -use cache::INTERNER; +use crate::{Build, Crate}; +use crate::cache::INTERNER; #[derive(Deserialize)] struct Output { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 8ff175b0187..d9f51f6fd3d 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -28,11 +28,11 @@ use build_helper::output; use cmake; use cc; -use util::{self, exe}; +use crate::util::{self, exe}; use build_helper::up_to_date; -use builder::{Builder, RunConfig, ShouldRun, Step}; -use cache::Interned; -use GitRepo; +use crate::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::cache::Interned; +use crate::GitRepo; #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Llvm { @@ -278,11 +278,11 @@ fn check_llvm_version(builder: &Builder, llvm_config: &Path) { let mut parts = version.split('.').take(2) .filter_map(|s| s.parse::<u32>().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { - if major >= 5 { + if major >= 6 { return } } - panic!("\n\nbad LLVM version: {}, need >=5.0\n\n", version) + panic!("\n\nbad LLVM version: {}, need >=6.0\n\n", version) } fn configure_cmake(builder: &Builder, diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 7a9e6d4fd38..f585495b0aa 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -27,7 +27,7 @@ use std::process::Command; use build_helper::output; -use Build; +use crate::Build; struct Finder { cache: HashMap<OsString, Option<PathBuf>>, diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 87d5737e2a0..11932d58cea 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -23,17 +23,17 @@ use std::process::Command; use build_helper::{self, output}; -use builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; -use cache::{Interned, INTERNER}; -use compile; -use dist; -use flags::Subcommand; -use native; -use tool::{self, Tool, SourceType}; -use toolstate::ToolState; -use util::{self, dylib_path, dylib_path_var}; -use Crate as CargoCrate; -use {DocTests, Mode, GitRepo}; +use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; +use crate::cache::{Interned, INTERNER}; +use crate::compile; +use crate::dist; +use crate::flags::Subcommand; +use crate::native; +use crate::tool::{self, Tool, SourceType}; +use crate::toolstate::ToolState; +use crate::util::{self, dylib_path, dylib_path_var}; +use crate::Crate as CargoCrate; +use crate::{DocTests, Mode, GitRepo}; const ADB_TEST_DIR: &str = "/data/tmp/work"; @@ -616,7 +616,7 @@ impl Step for RustdocJS { if let Some(ref nodejs) = builder.config.nodejs { let mut command = Command::new(nodejs); command.args(&["src/tools/rustdoc-js/tester.js", &*self.host]); - builder.ensure(::doc::Std { + builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage, }); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 1bd4403a66f..4335359e115 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -15,16 +15,16 @@ use std::path::PathBuf; use std::process::{Command, exit}; use std::collections::HashSet; -use Mode; -use Compiler; -use builder::{Step, RunConfig, ShouldRun, Builder}; -use util::{exe, add_lib_path}; -use compile; -use native; -use channel::GitInfo; -use channel; -use cache::Interned; -use toolstate::ToolState; +use crate::Mode; +use crate::Compiler; +use crate::builder::{Step, RunConfig, ShouldRun, Builder}; +use crate::util::{exe, add_lib_path}; +use crate::compile; +use crate::native; +use crate::channel::GitInfo; +use crate::channel; +use crate::cache::Interned; +use crate::toolstate::ToolState; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum SourceType { diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index be24ae0ce66..b18e38e471e 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -21,8 +21,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::{SystemTime, Instant}; -use config::Config; -use builder::Builder; +use crate::config::Config; +use crate::builder::Builder; /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { diff --git a/src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-6.0/Dockerfile index 4f90c509726..160b23e0b00 100644 --- a/src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-6.0/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cmake \ sudo \ gdb \ - llvm-5.0-tools \ + llvm-6.0-tools \ libedit-dev \ zlib1g-dev \ xz-utils @@ -22,6 +22,6 @@ RUN sh /scripts/sccache.sh # using llvm-link-shared due to libffi issues -- see #34486 ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-5.0 \ + --llvm-root=/usr/lib/llvm-6.0 \ --enable-llvm-link-shared ENV RUST_CHECK_TARGET check diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index 215689dfc48..a2d2d3c74be 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -58,9 +58,34 @@ pub const CAPACITY: usize = 2 * B - 1; /// these should always be put behind pointers, and specifically behind `BoxedNode` in the owned /// case. /// -/// We put the metadata first so that its position is the same for every `K` and `V`, in order -/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to -/// prevent them from being reordered. +/// We have a separate type for the header and rely on it matching the prefix of `LeafNode`, in +/// order to statically allocate a single dummy node to avoid allocations. This struct is +/// `repr(C)` to prevent them from being reordered. `LeafNode` does not just contain a +/// `NodeHeader` because we do not want unnecessary padding between `len` and the keys. +/// Crucially, `NodeHeader` can be safely transmuted to different K and V. (This is exploited +/// by `as_header`.) +/// See `into_key_slice` for an explanation of K2. K2 cannot be safely transmuted around +/// because the size of `NodeHeader` depends on its alignment! +#[repr(C)] +struct NodeHeader<K, V, K2 = ()> { + /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. + /// This either points to an actual node or is null. + parent: *const InternalNode<K, V>, + + /// This node's index into the parent node's `edges` array. + /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`. + /// This is only guaranteed to be initialized when `parent` is non-null. + parent_idx: MaybeUninit<u16>, + + /// The number of keys and values this node stores. + /// + /// This next to `parent_idx` to encourage the compiler to join `len` and + /// `parent_idx` into the same 32-bit word, reducing space overhead. + len: u16, + + /// See `into_key_slice`. + keys_start: [K2; 0], +} #[repr(C)] struct LeafNode<K, V> { /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. @@ -98,24 +123,25 @@ impl<K, V> LeafNode<K, V> { len: 0 } } +} +impl<K, V> NodeHeader<K, V> { fn is_shared_root(&self) -> bool { ptr::eq(self, &EMPTY_ROOT_NODE as *const _ as *const _) } } // We need to implement Sync here in order to make a static instance. -unsafe impl Sync for LeafNode<(), ()> {} +unsafe impl Sync for NodeHeader<(), ()> {} // An empty node used as a placeholder for the root node, to avoid allocations. -// We use () in order to save space, since no operation on an empty tree will +// We use just a header in order to save space, since no operation on an empty tree will // ever take a pointer past the first key. -static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode { +static EMPTY_ROOT_NODE: NodeHeader<(), ()> = NodeHeader { parent: ptr::null(), parent_idx: MaybeUninit::uninitialized(), len: 0, - keys: MaybeUninit::uninitialized(), - vals: MaybeUninit::uninitialized(), + keys_start: [], }; /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden @@ -281,7 +307,7 @@ impl<K, V> Root<K, V> { .node) }; self.height -= 1; - self.as_mut().as_leaf_mut().parent = ptr::null(); + unsafe { (*self.as_mut().as_leaf_mut()).parent = ptr::null(); } unsafe { Global.dealloc(NonNull::from(top).cast(), Layout::new::<InternalNode<K, V>>()); @@ -306,6 +332,11 @@ impl<K, V> Root<K, V> { /// `Leaf`, the `NodeRef` points to a leaf node, when this is `Internal` the /// `NodeRef` points to an internal node, and when this is `LeafOrInternal` the /// `NodeRef` could be pointing to either type of node. +/// Note that in case of a leaf node, this might still be the shared root! Only turn +/// this into a `LeafNode` reference if you know it is not a root! Shared references +/// must be dereferencable *for the entire size of their pointee*, so `&InternalNode` +/// pointing to the shared root is UB. +/// Turning this into a `NodeHeader` is always safe. pub struct NodeRef<BorrowType, K, V, Type> { height: usize, node: NonNull<LeafNode<K, V>>, @@ -352,7 +383,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> { /// Finds the length of the node. This is the number of keys or values. In an /// internal node, the number of edges is `len() + 1`. pub fn len(&self) -> usize { - self.as_leaf().len as usize + self.as_header().len as usize } /// Returns the height of this node in the whole tree. Zero height denotes the @@ -382,14 +413,19 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> { } } - fn as_leaf(&self) -> &LeafNode<K, V> { + /// Assert that this is indeed a proper leaf node, and not the shared root. + unsafe fn as_leaf(&self) -> &LeafNode<K, V> { + self.node.as_ref() + } + + fn as_header(&self) -> &NodeHeader<K, V> { unsafe { - self.node.as_ref() + &*(self.node.as_ptr() as *const NodeHeader<K, V>) } } pub fn is_shared_root(&self) -> bool { - self.as_leaf().is_shared_root() + self.as_header().is_shared_root() } pub fn keys(&self) -> &[K] { @@ -418,7 +454,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> { >, Self > { - let parent_as_leaf = self.as_leaf().parent as *const LeafNode<K, V>; + let parent_as_leaf = self.as_header().parent as *const LeafNode<K, V>; if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { Ok(Handle { node: NodeRef { @@ -427,7 +463,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> { root: self.root, _marker: PhantomData }, - idx: unsafe { usize::from(*self.as_leaf().parent_idx.get_ref()) }, + idx: unsafe { usize::from(*self.as_header().parent_idx.get_ref()) }, _marker: PhantomData }) } else { @@ -534,10 +570,10 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> { } } - fn as_leaf_mut(&mut self) -> &mut LeafNode<K, V> { - unsafe { - self.node.as_mut() - } + /// Returns a raw ptr to avoid asserting exclusive access to the entire node. + fn as_leaf_mut(&mut self) -> *mut LeafNode<K, V> { + // We are mutable, so we cannot be the root, so accessing this as a leaf is okay. + self.node.as_ptr() } fn keys_mut(&mut self) -> &mut [K] { @@ -551,28 +587,50 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> { impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> { fn into_key_slice(self) -> &'a [K] { - // When taking a pointer to the keys, if our key has a stricter - // alignment requirement than the shared root does, then the pointer - // would be out of bounds, which LLVM assumes will not happen. If the - // alignment is more strict, we need to make an empty slice that doesn't - // use an out of bounds pointer. + // We have to be careful here because we might be pointing to the shared root. + // In that case, we must not create an `&LeafNode`. We could just return + // an empty slice whenever the length is 0 (this includes the shared root), + // but we want to avoid that run-time check. + // Instead, we create a slice pointing into the node whenever possible. + // We can sometimes do this even for the shared root, as the slice will be + // empty. We cannot *always* do this because if the type is too highly + // aligned, the offset of `keys` in a "full node" might be outside the bounds + // of the header! So we do an alignment check first, that will be + // evaluated at compile-time, and only do any run-time check in the rare case + // that the alignment is very big. if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() { &[] } else { - // Here either it's not the root, or the alignment is less strict, - // in which case the keys pointer will point "one-past-the-end" of - // the node, which is allowed by LLVM. + // Thanks to the alignment check above, we know that `keys` will be + // in-bounds of some allocation even if this is the shared root! + // (We might be one-past-the-end, but that is allowed by LLVM.) + // Getting the pointer is tricky though. `NodeHeader` does not have a `keys` + // field because we want its size to not depend on the alignment of `K` + // (needed becuase `as_header` should be safe). We cannot call `as_leaf` + // because we might be the shared root. + // For this reason, `NodeHeader` has this `K2` parameter (that's usually `()` + // and hence just adds a size-0-align-1 field, not affecting layout). + // We know that we can transmute `NodeHeader<K, V, ()>` to `NodeHeader<K, V, K>` + // because we did the alignment check above, and hence `NodeHeader<K, V, K>` + // is not bigger than `NodeHeader<K, V, ()>`! Then we can use `NodeHeader<K, V, K>` + // to compute the pointer where the keys start. + // This entire hack will become unnecessary once + // <https://github.com/rust-lang/rfcs/pull/2582> lands, then we can just take a raw + // pointer to the `keys` field of `*const InternalNode<K, V>`. + + // This is a non-debug-assert because it can be completely compile-time evaluated. + assert!(mem::size_of::<NodeHeader<K, V>>() == mem::size_of::<NodeHeader<K, V, K>>()); + let header = self.as_header() as *const _ as *const NodeHeader<K, V, K>; + let keys = unsafe { &(*header).keys_start as *const _ as *const K }; unsafe { - slice::from_raw_parts( - self.as_leaf().keys.as_ptr() as *const K, - self.len() - ) + slice::from_raw_parts(keys, self.len()) } } } fn into_val_slice(self) -> &'a [V] { debug_assert!(!self.is_shared_root()); + // We cannot be the root, so `as_leaf` is okay unsafe { slice::from_raw_parts( self.as_leaf().vals.as_ptr() as *const V, @@ -602,7 +660,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> { } else { unsafe { slice::from_raw_parts_mut( - self.as_leaf_mut().keys.as_mut_ptr() as *mut K, + (*self.as_leaf_mut()).keys.as_mut_ptr() as *mut K, self.len() ) } @@ -613,7 +671,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> { debug_assert!(!self.is_shared_root()); unsafe { slice::from_raw_parts_mut( - self.as_leaf_mut().vals.as_mut_ptr() as *mut V, + (*self.as_leaf_mut()).vals.as_mut_ptr() as *mut V, self.len() ) } @@ -637,9 +695,9 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> { unsafe { ptr::write(self.keys_mut().get_unchecked_mut(idx), key); ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - } - self.as_leaf_mut().len += 1; + (*self.as_leaf_mut()).len += 1; + } } /// Adds a key/value pair to the beginning of the node. @@ -651,9 +709,9 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> { unsafe { slice_insert(self.keys_mut(), 0, key); slice_insert(self.vals_mut(), 0, val); - } - self.as_leaf_mut().len += 1; + (*self.as_leaf_mut()).len += 1; + } } } @@ -672,7 +730,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> { ptr::write(self.vals_mut().get_unchecked_mut(idx), val); ptr::write(self.as_internal_mut().edges.get_unchecked_mut(idx + 1), edge.node); - self.as_leaf_mut().len += 1; + (*self.as_leaf_mut()).len += 1; Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } @@ -708,7 +766,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> { edge.node ); - self.as_leaf_mut().len += 1; + (*self.as_leaf_mut()).len += 1; self.correct_all_childrens_parent_links(); } @@ -732,12 +790,12 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> { ForceResult::Internal(internal) => { let edge = ptr::read(internal.as_internal().edges.get_unchecked(idx + 1)); let mut new_root = Root { node: edge, height: internal.height - 1 }; - new_root.as_mut().as_leaf_mut().parent = ptr::null(); + (*new_root.as_mut().as_leaf_mut()).parent = ptr::null(); Some(new_root) } }; - self.as_leaf_mut().len -= 1; + (*self.as_leaf_mut()).len -= 1; (key, val, edge) } } @@ -765,7 +823,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> { ); let mut new_root = Root { node: edge, height: internal.height - 1 }; - new_root.as_mut().as_leaf_mut().parent = ptr::null(); + (*new_root.as_mut().as_leaf_mut()).parent = ptr::null(); for i in 0..old_len { Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link(); @@ -775,7 +833,7 @@ impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> { } }; - self.as_leaf_mut().len -= 1; + (*self.as_leaf_mut()).len -= 1; (key, val, edge) } @@ -966,7 +1024,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge slice_insert(self.node.keys_mut(), self.idx, key); slice_insert(self.node.vals_mut(), self.idx, val); - self.node.as_leaf_mut().len += 1; + (*self.node.as_leaf_mut()).len += 1; self.node.vals_mut().get_unchecked_mut(self.idx) } @@ -1009,8 +1067,10 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: let idx = self.idx as u16; let ptr = self.node.as_internal_mut() as *mut _; let mut child = self.descend(); - child.as_leaf_mut().parent = ptr; - child.as_leaf_mut().parent_idx.set(idx); + unsafe { + (*child.as_leaf_mut()).parent = ptr; + (*child.as_leaf_mut()).parent_idx.set(idx); + } } /// Unsafely asserts to the compiler some static information about whether the underlying @@ -1158,7 +1218,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> new_len ); - self.node.as_leaf_mut().len = self.idx as u16; + (*self.node.as_leaf_mut()).len = self.idx as u16; new_node.len = new_len as u16; ( @@ -1180,7 +1240,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::KV> unsafe { let k = slice_remove(self.node.keys_mut(), self.idx); let v = slice_remove(self.node.vals_mut(), self.idx); - self.node.as_leaf_mut().len -= 1; + (*self.node.as_leaf_mut()).len -= 1; (self.left_edge(), k, v) } } @@ -1221,7 +1281,7 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: new_len + 1 ); - self.node.as_leaf_mut().len = self.idx as u16; + (*self.node.as_leaf_mut()).len = self.idx as u16; new_node.data.len = new_len as u16; let mut new_root = Root { @@ -1295,9 +1355,9 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: for i in self.idx+1..self.node.len() { Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); } - self.node.as_leaf_mut().len -= 1; + (*self.node.as_leaf_mut()).len -= 1; - left_node.as_leaf_mut().len += right_len as u16 + 1; + (*left_node.as_leaf_mut()).len += right_len as u16 + 1; if self.node.height > 1 { ptr::copy_nonoverlapping( @@ -1407,8 +1467,8 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: move_kv(left_kv, new_left_len, parent_kv, 0, 1); } - left_node.reborrow_mut().as_leaf_mut().len -= count as u16; - right_node.reborrow_mut().as_leaf_mut().len += count as u16; + (*left_node.reborrow_mut().as_leaf_mut()).len -= count as u16; + (*right_node.reborrow_mut().as_leaf_mut()).len += count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { @@ -1468,8 +1528,8 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: new_right_len); } - left_node.reborrow_mut().as_leaf_mut().len += count as u16; - right_node.reborrow_mut().as_leaf_mut().len -= count as u16; + (*left_node.reborrow_mut().as_leaf_mut()).len += count as u16; + (*right_node.reborrow_mut().as_leaf_mut()).len -= count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { @@ -1560,8 +1620,8 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, ma move_kv(left_kv, left_new_len, right_kv, 0, right_new_len); - left_node.reborrow_mut().as_leaf_mut().len = left_new_len as u16; - right_node.reborrow_mut().as_leaf_mut().len = right_new_len as u16; + (*left_node.reborrow_mut().as_leaf_mut()).len = left_new_len as u16; + (*right_node.reborrow_mut().as_leaf_mut()).len = right_new_len as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(right)) => { diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index 2ef84dbade0..ba46fafaf16 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -627,7 +627,9 @@ impl<T> LinkedList<T> { self.pop_front_node().map(Node::into_element) } - /// Appends an element to the back of a list + /// Appends an element to the back of a list. + /// + /// This operation should compute in O(1) time. /// /// # Examples /// @@ -647,6 +649,8 @@ impl<T> LinkedList<T> { /// Removes the last element from a list and returns it, or `None` if /// it is empty. /// + /// This operation should compute in O(1) time. + /// /// # Examples /// /// ``` diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index e329b45a617..509195cd047 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -80,6 +80,11 @@ fn test_reserve() { } #[test] +fn test_zst_capacity() { + assert_eq!(Vec::<()>::new().capacity(), usize::max_value()); +} + +#[test] fn test_extend() { let mut v = Vec::new(); let mut w = Vec::new(); diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0c5256b981e..8e0caa5ae33 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -609,10 +609,15 @@ pub trait Debug { /// println!("The origin is: {}", origin); /// ``` #[rustc_on_unimplemented( + on( + _Self="std::path::Path", + label="`{Self}` cannot be formatted with the default formatter; call `.display()` on it", + note="call `.display()` or `.to_string_lossy()` to safely print paths, \ + as they may contain non-Unicode data" + ), message="`{Self}` doesn't implement `{Display}`", label="`{Self}` cannot be formatted with the default formatter", - note="in format strings you may be able to use `{{:?}}` \ - (or {{:#?}} for pretty-print) instead", + note="in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead", )] #[doc(alias = "{}")] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 0c870f9e404..5dee1d6dd3a 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -33,6 +33,7 @@ use task::{Poll, LocalWaker}; /// /// When using a future, you generally won't call `poll` directly, but instead /// `await!` the value. +#[must_use] pub trait Future { /// The result of the `Future`. type Output; diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 92a4aed4e27..c0b83a6868b 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -98,6 +98,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item=()>) {} message="`{Self}` is not an iterator" )] #[doc(spotlight)] +#[must_use] pub trait Iterator { /// The type of the elements being iterated over. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 7b273f7862a..aa23d49672a 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -649,19 +649,6 @@ impl<I> Iterator for Cycle<I> where I: Clone + Iterator { _ => (usize::MAX, None) } } - - #[inline] - fn try_fold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R where - Self: Sized, F: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc> - { - let mut accum = init; - while let Some(x) = self.iter.next() { - accum = f(accum, x)?; - accum = self.iter.try_fold(accum, &mut f)?; - self.iter = self.orig.clone(); - } - Try::from_ok(accum) - } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index a51674fbfc7..c8ad38c52db 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -121,7 +121,6 @@ #![feature(const_slice_len)] #![feature(const_str_as_bytes)] #![feature(const_str_len)] -#![feature(const_let)] #![feature(const_int_rotate)] #![feature(const_int_wrapping)] #![feature(const_int_sign)] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 4acf3a15ebf..f1df1f2856e 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -70,7 +70,7 @@ assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", st #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { - $Ty(unsafe { NonZero(n) }) + $Ty(NonZero(n)) } /// Create a non-zero if the given value is not zero. @@ -2150,19 +2150,6 @@ impl isize { "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } } -// Emits the correct `cttz` call, depending on the size of the type. -macro_rules! uint_cttz_call { - // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic - // emits two conditional moves on x86_64. By promoting the value to - // u16 and setting bit 8, we get better code without any conditional - // operations. - // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) - // pending, remove this workaround once LLVM generates better code - // for cttz8. - ($value:expr, 8) => { intrinsics::cttz($value as u16 | 0x100) }; - ($value:expr, $_BITS:expr) => { intrinsics::cttz($value) } -} - // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr, @@ -2306,7 +2293,7 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " #[rustc_const_unstable(feature = "const_int_ops")] #[inline] pub const fn trailing_zeros(self) -> u32 { - unsafe { uint_cttz_call!(self, $BITS) as u32 } + unsafe { intrinsics::cttz(self) as u32 } } } diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index d1be724c326..3b356b9a1e7 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -72,6 +72,7 @@ label="expected an `Fn<{Args}>` closure, found `{Self}`", )] #[fundamental] // so that regex can rely that `&str: !FnMut` +#[must_use] pub trait Fn<Args> : FnMut<Args> { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -150,6 +151,7 @@ pub trait Fn<Args> : FnMut<Args> { label="expected an `FnMut<{Args}>` closure, found `{Self}`", )] #[fundamental] // so that regex can rely that `&str: !FnMut` +#[must_use] pub trait FnMut<Args> : FnOnce<Args> { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -228,6 +230,7 @@ pub trait FnMut<Args> : FnOnce<Args> { label="expected an `FnOnce<{Args}>` closure, found `{Self}`", )] #[fundamental] // so that regex can rely that `&str: !FnMut` +#[must_use] pub trait FnOnce<Args> { /// The returned type after the call operator is used. #[stable(feature = "fn_once_output", since = "1.12.0")] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 79ca600b4a5..b3c93ae1fa7 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2928,7 +2928,7 @@ impl<T: ?Sized> NonNull<T> { #[stable(feature = "nonnull", since = "1.25.0")] #[inline] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - NonNull { pointer: unsafe { NonZero(ptr as _) } } + NonNull { pointer: NonZero(ptr as _) } } /// Creates a new `NonNull` if `ptr` is non-null. diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 060983a702f..d2683e31eef 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -1072,6 +1072,15 @@ impl<T> AtomicPtr<T> { #[cfg(target_has_atomic = "8")] #[stable(feature = "atomic_bool_from", since = "1.24.0")] impl From<bool> for AtomicBool { + /// Converts a `bool` into an `AtomicBool`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::AtomicBool; + /// let atomic_bool = AtomicBool::from(true); + /// assert_eq!(format!("{:?}", atomic_bool), "true") + /// ``` #[inline] fn from(b: bool) -> Self { Self::new(b) } } @@ -1126,8 +1135,12 @@ macro_rules! atomic_int { #[$stable_from] impl From<$int_type> for $atomic_type { - #[inline] - fn from(v: $int_type) -> Self { Self::new(v) } + doc_comment! { + concat!( +"Converts an `", stringify!($int_type), "` into an `", stringify!($atomic_type), "`."), + #[inline] + fn from(v: $int_type) -> Self { Self::new(v) } + } } #[$stable_debug] diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 4efa0136314..00b4aa4fa2d 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1003,6 +1003,8 @@ fn test_cycle() { assert_eq!(it.next(), None); assert_eq!(empty::<i32>().cycle().fold(0, |acc, x| acc + x), 0); + + assert_eq!(once(1).cycle().skip(1).take(4).fold(0, |acc, x| acc + x), 4); } #[test] diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 8d2b1d74c55..43bc9d88895 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -36,6 +36,7 @@ use traits::{Obligation, ObligationCause, PredicateObligation}; use ty::fold::TypeFoldable; use ty::subst::{Kind, UnpackedKind}; use ty::{self, BoundVar, Lift, Ty, TyCtxt}; +use util::captures::Captures; impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> { /// The "main method" for a canonicalized trait query. Given the @@ -527,32 +528,30 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { param_env: ty::ParamEnv<'tcx>, unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>], result_subst: &'a CanonicalVarValues<'tcx>, - ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a { - Box::new( - unsubstituted_region_constraints - .iter() - .map(move |constraint| { - let constraint = substitute_value(self.tcx, result_subst, constraint); - let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below - - Obligation::new( - cause.clone(), - param_env, - match k1.unpack() { - UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives( - ty::Binder::bind( - ty::OutlivesPredicate(r1, r2) - ) - ), - UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives( - ty::Binder::bind( - ty::OutlivesPredicate(t1, r2) - ) - ), - } - ) - }) - ) as Box<dyn Iterator<Item = _>> + ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'gcx> { + unsubstituted_region_constraints + .iter() + .map(move |constraint| { + let constraint = substitute_value(self.tcx, result_subst, constraint); + let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below + + Obligation::new( + cause.clone(), + param_env, + match k1.unpack() { + UnpackedKind::Lifetime(r1) => ty::Predicate::RegionOutlives( + ty::Binder::bind( + ty::OutlivesPredicate(r1, r2) + ) + ), + UnpackedKind::Type(t1) => ty::Predicate::TypeOutlives( + ty::Binder::bind( + ty::OutlivesPredicate(t1, r2) + ) + ), + } + ) + }) } /// Given two sets of values for the same set of canonical variables, unify them. diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index f124623becd..833da67d3f1 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -347,6 +347,10 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' self.infcx.tcx } + fn trait_object_mode(&self) -> relate::TraitObjectMode { + self.infcx.trait_object_mode() + } + fn tag(&self) -> &'static str { "Generalizer" } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index 27faa4587f3..caa120fa267 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -39,6 +39,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } + fn trait_object_mode(&self) -> relate::TraitObjectMode { + self.fields.infcx.trait_object_mode() + } + fn a_is_expected(&self) -> bool { self.a_is_expected } fn relate_item_substs(&mut self, diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 8968c5949b6..ba21ebb49eb 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -15,7 +15,7 @@ use super::Subtype; use traits::ObligationCause; use ty::{self, Ty, TyCtxt}; -use ty::relate::{Relate, RelateResult, TypeRelation}; +use ty::relate::{self, Relate, RelateResult, TypeRelation}; /// "Greatest lower bound" (common subtype) pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { @@ -36,6 +36,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Glb" } + fn trait_object_mode(&self) -> relate::TraitObjectMode { + self.fields.infcx.trait_object_mode() + } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } fn a_is_expected(&self) -> bool { self.a_is_expected } diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 8875b4169dd..80fad447b46 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -15,7 +15,7 @@ use super::Subtype; use traits::ObligationCause; use ty::{self, Ty, TyCtxt}; -use ty::relate::{Relate, RelateResult, TypeRelation}; +use ty::relate::{self, Relate, RelateResult, TypeRelation}; /// "Least upper bound" (common supertype) pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { @@ -36,6 +36,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Lub" } + fn trait_object_mode(&self) -> relate::TraitObjectMode { + self.fields.infcx.trait_object_mode() + } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } fn a_is_expected(&self) -> bool { self.a_is_expected } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index b1a13354b7c..c961fd5fbd4 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -35,7 +35,7 @@ use syntax_pos::{self, Span}; use traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::TypeFoldable; -use ty::relate::RelateResult; +use ty::relate::{RelateResult, TraitObjectMode}; use ty::subst::{Kind, Substs}; use ty::{self, GenericParamDefKind, Ty, TyCtxt}; use ty::{FloatVid, IntVid, TyVid}; @@ -182,6 +182,9 @@ pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { // This flag is true while there is an active snapshot. in_snapshot: Cell<bool>, + // The TraitObjectMode used here, + trait_object_mode: TraitObjectMode, + // A set of constraints that regionck must validate. Each // constraint has the form `T:'a`, meaning "some type `T` must // outlive the lifetime 'a". These constraints derive from @@ -472,6 +475,7 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { global_tcx: TyCtxt<'a, 'gcx, 'gcx>, arena: SyncDroplessArena, fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>, + trait_object_mode: TraitObjectMode, } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { @@ -480,6 +484,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { global_tcx: self, arena: SyncDroplessArena::default(), fresh_tables: None, + trait_object_mode: TraitObjectMode::NoSquash, } } } @@ -492,6 +497,12 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { self } + pub fn with_trait_object_mode(mut self, mode: TraitObjectMode) -> Self { + debug!("with_trait_object_mode: setting mode to {:?}", mode); + self.trait_object_mode = mode; + self + } + /// Given a canonical value `C` as a starting point, create an /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is @@ -518,6 +529,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { pub fn enter<R>(&'tcx mut self, f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R) -> R { let InferCtxtBuilder { global_tcx, + trait_object_mode, ref arena, ref fresh_tables, } = *self; @@ -526,6 +538,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { f(InferCtxt { tcx, in_progress_tables, + trait_object_mode, projection_cache: Default::default(), type_variables: RefCell::new(type_variable::TypeVariableTable::new()), int_unification_table: RefCell::new(ut::UnificationTable::new()), @@ -607,6 +620,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.in_snapshot.get() } + pub fn trait_object_mode(&self) -> TraitObjectMode { + self.trait_object_mode + } + pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index 773c7129722..0ce0eb9a1ab 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -382,6 +382,13 @@ where self.infcx.tcx } + fn trait_object_mode(&self) -> relate::TraitObjectMode { + // squashing should only be done in coherence, not NLL + assert_eq!(self.infcx.trait_object_mode(), + relate::TraitObjectMode::NoSquash); + relate::TraitObjectMode::NoSquash + } + fn tag(&self) -> &'static str { "nll::subtype" } @@ -696,6 +703,13 @@ where self.infcx.tcx } + fn trait_object_mode(&self) -> relate::TraitObjectMode { + // squashing should only be done in coherence, not NLL + assert_eq!(self.infcx.trait_object_mode(), + relate::TraitObjectMode::NoSquash); + relate::TraitObjectMode::NoSquash + } + fn tag(&self) -> &'static str { "nll::generalizer" } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 3b0f9a5e545..ef2ef3f8a86 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -15,7 +15,7 @@ use traits::Obligation; use ty::{self, Ty, TyCtxt}; use ty::TyVar; use ty::fold::TypeFoldable; -use ty::relate::{Cause, Relate, RelateResult, TypeRelation}; +use ty::relate::{self, Cause, Relate, RelateResult, TypeRelation}; use std::mem; /// Ensures `a` is made a subtype of `b`. Returns `a` on success. @@ -43,6 +43,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> for Sub<'combine, 'infcx, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Sub" } + fn trait_object_mode(&self) -> relate::TraitObjectMode { + self.fields.infcx.trait_object_mode() + } + fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx } fn a_is_expected(&self) -> bool { self.a_is_expected } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index b7759a8c92b..cf437109e67 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -209,6 +209,12 @@ declare_lint! { } declare_lint! { + pub ORDER_DEPENDENT_TRAIT_OBJECTS, + Deny, + "trait-object types were treated as different depending on marker-trait order" +} + +declare_lint! { pub BAD_REPR, Warn, "detects incorrect use of `repr` attribute" @@ -365,6 +371,13 @@ pub mod parser { } } +declare_lint! { + pub DEPRECATED_IN_FUTURE, + Allow, + "detects use of items that will be deprecated in a future version", + report_in_external_macro: true +} + /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -405,6 +418,7 @@ impl LintPass for HardwiredLints { PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, LATE_BOUND_LIFETIME_ARGUMENTS, INCOHERENT_FUNDAMENTAL_IMPLS, + ORDER_DEPENDENT_TRAIT_OBJECTS, DEPRECATED, UNUSED_UNSAFE, UNUSED_MUT, @@ -427,6 +441,7 @@ impl LintPass for HardwiredLints { MACRO_USE_EXTERN_CRATE, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, parser::QUESTION_MARK_MACRO_SEP, + DEPRECATED_IN_FUTURE, ) } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index e576951417f..31a75bd106e 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1657,11 +1657,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn report_dead_assign(&self, hir_id: HirId, sp: Span, var: Variable, is_argument: bool) { if let Some(name) = self.should_warn(var) { if is_argument { - self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, - &format!("value passed to `{}` is never read", name)); + self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, + &format!("value passed to `{}` is never read", name)) + .help("maybe it is overwritten before being read?") + .emit(); } else { - self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, - &format!("value assigned to `{}` is never read", name)); + self.ir.tcx.struct_span_lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, + &format!("value assigned to `{}` is never read", name)) + .help("maybe it is overwritten before being read?") + .emit(); } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index ab379c910f7..61341cbc30c 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -13,7 +13,7 @@ pub use self::StabilityLevel::*; -use lint; +use lint::{self, Lint}; use hir::{self, Item, Generics, StructField, Variant, HirId}; use hir::def::Def; use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; @@ -562,18 +562,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return EvalResult::Allow; } - let lint_deprecated = |def_id: DefId, id: NodeId, note: Option<Symbol>| { - let path = self.item_path_str(def_id); - + let lint_deprecated = |def_id: DefId, + id: NodeId, + note: Option<Symbol>, + message: &str, + lint: &'static Lint| { let msg = if let Some(note) = note { - format!("use of deprecated item '{}': {}", path, note) + format!("{}: {}", message, note) } else { - format!("use of deprecated item '{}'", path) + format!("{}", message) }; - self.lint_node(lint::builtin::DEPRECATED, id, span, &msg); + self.lint_node(lint, id, span, &msg); if id == ast::DUMMY_NODE_ID { - span_bug!(span, "emitted a deprecated lint with dummy node id: {:?}", def_id); + span_bug!(span, "emitted a {} lint with dummy node id: {:?}", lint.name, def_id); } }; @@ -584,17 +586,39 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // version, then we should display no warning message. let deprecated_in_future_version = if let Some(sym) = depr_entry.attr.since { let since = sym.as_str(); - !deprecation_in_effect(&since) + if !deprecation_in_effect(&since) { + Some(since) + } else { + None + } } else { - false + None }; let parent_def_id = self.hir().local_def_id(self.hir().get_parent(id)); - let skip = deprecated_in_future_version || - self.lookup_deprecation_entry(parent_def_id) + let skip = self.lookup_deprecation_entry(parent_def_id) .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry)); - if !skip { - lint_deprecated(def_id, id, depr_entry.attr.note); + + if let Some(since) = deprecated_in_future_version { + let path = self.item_path_str(def_id); + let message = format!("use of item '{}' \ + that will be deprecated in future version {}", + path, + since); + + lint_deprecated(def_id, + id, + depr_entry.attr.note, + &message, + lint::builtin::DEPRECATED_IN_FUTURE); + } else if !skip { + let path = self.item_path_str(def_id); + let message = format!("use of deprecated item '{}'", path); + lint_deprecated(def_id, + id, + depr_entry.attr.note, + &message, + lint::builtin::DEPRECATED); } }; } @@ -614,8 +638,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if let Some(&Stability{rustc_depr: Some(attr::RustcDeprecation { reason, since }), ..}) = stability { if let Some(id) = id { + let path = self.item_path_str(def_id); if deprecation_in_effect(&since.as_str()) { - lint_deprecated(def_id, id, Some(reason)); + let message = format!("use of deprecated item '{}'", path); + lint_deprecated(def_id, + id, + Some(reason), + &message, + lint::builtin::DEPRECATED); + } else { + let message = format!("use of item '{}' \ + that will be deprecated in future version {}", + path, + since); + lint_deprecated(def_id, + id, + Some(reason), + &message, + lint::builtin::DEPRECATED_IN_FUTURE); } } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 68b5c3e2df3..9dff3277917 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -149,6 +149,14 @@ pub struct Mir<'tcx> { /// This is used for the "rust-call" ABI. pub spread_arg: Option<Local>, + /// Mark this MIR of a const context other than const functions as having converted a `&&` or + /// `||` expression into `&` or `|` respectively. This is problematic because if we ever stop + /// this conversion from happening and use short circuiting, we will cause the following code + /// to change the value of `x`: `let mut x = 42; false && { x = 55; true };` + /// + /// List of places where control flow was destroyed. Used for error reporting. + pub control_flow_destroyed: Vec<(Span, String)>, + /// A span representing this MIR, for error reporting pub span: Span, @@ -167,6 +175,7 @@ impl<'tcx> Mir<'tcx> { arg_count: usize, upvar_decls: Vec<UpvarDecl>, span: Span, + control_flow_destroyed: Vec<(Span, String)>, ) -> Self { // We need `arg_count` locals, and one for the return place assert!( @@ -191,6 +200,7 @@ impl<'tcx> Mir<'tcx> { spread_arg: None, span, cache: cache::Cache::new(), + control_flow_destroyed, } } @@ -421,6 +431,7 @@ impl_stable_hash_for!(struct Mir<'tcx> { arg_count, upvar_decls, spread_arg, + control_flow_destroyed, span, cache }); @@ -1748,6 +1759,9 @@ pub enum StatementKind<'tcx> { /// (e.g., inspecting constants and discriminant values), and the /// kind of pattern it comes from. This is in order to adapt potential /// error messages to these specific patterns. + /// + /// Note that this also is emitted for regular `let` bindings to ensure that locals that are + /// never accessed still get some sanity checks for e.g. `let x: ! = ..;` FakeRead(FakeReadCause, Place<'tcx>), /// Write the discriminant for a variant to the enum Place. @@ -2984,6 +2998,7 @@ BraceStructTypeFoldableImpl! { arg_count, upvar_decls, spread_arg, + control_flow_destroyed, span, cache, } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index f10f523e2b4..af338cd3868 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -20,6 +20,7 @@ use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause}; use traits::IntercrateMode; use traits::select::IntercrateAmbiguityCause; use ty::{self, Ty, TyCtxt}; +use ty::relate::TraitObjectMode; use ty::fold::TypeFoldable; use ty::subst::Subst; @@ -52,6 +53,7 @@ pub fn overlapping_impls<'gcx, F1, F2, R>( impl1_def_id: DefId, impl2_def_id: DefId, intercrate_mode: IntercrateMode, + trait_object_mode: TraitObjectMode, on_overlap: F1, no_overlap: F2, ) -> R @@ -62,12 +64,14 @@ where debug!("overlapping_impls(\ impl1_def_id={:?}, \ impl2_def_id={:?}, - intercrate_mode={:?})", + intercrate_mode={:?}, + trait_object_mode={:?})", impl1_def_id, impl2_def_id, - intercrate_mode); + intercrate_mode, + trait_object_mode); - let overlaps = tcx.infer_ctxt().enter(|infcx| { + let overlaps = tcx.infer_ctxt().with_trait_object_mode(trait_object_mode).enter(|infcx| { let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode); overlap(selcx, impl1_def_id, impl2_def_id).is_some() }); @@ -79,7 +83,7 @@ where // In the case where we detect an error, run the check again, but // this time tracking intercrate ambuiguity causes for better // diagnostics. (These take time and can lead to false errors.) - tcx.infer_ctxt().enter(|infcx| { + tcx.infer_ctxt().with_trait_object_mode(trait_object_mode).enter(|infcx| { let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode); selcx.enable_tracking_intercrate_ambiguity_causes(); on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap()) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 4ef4f457105..373d6652b9e 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -459,7 +459,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), - true); + true,); let all_impls = self.tcx.all_impls(trait_ref.def_id()); match simp { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 8d91132a6db..cf37c3fceba 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -64,6 +64,8 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; pub use self::specialize::{OverlapError, specialization_graph, translate_substs}; pub use self::specialize::find_associated_item; +pub use self::specialize::specialization_graph::FutureCompatOverlapError; +pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; pub use self::util::{supertraits, supertrait_def_ids, transitive_bounds, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index c438542106c..d46389b0ee2 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -44,7 +44,7 @@ use infer::{InferCtxt, InferOk, TypeFreshener}; use middle::lang_items; use mir::interpret::GlobalId; use ty::fast_reject; -use ty::relate::TypeRelation; +use ty::relate::{TypeRelation, TraitObjectMode}; use ty::subst::{Subst, Substs}; use ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable}; @@ -1501,6 +1501,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return false; } + // Same idea as the above, but for alt trait object modes. These + // should only be used in intercrate mode - better safe than sorry. + if self.infcx.trait_object_mode() != TraitObjectMode::NoSquash { + bug!("using squashing TraitObjectMode outside of intercrate mode? param_env={:?}", + param_env); + } + // Otherwise, we can use the global cache. true } @@ -3699,7 +3706,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { previous: &ty::PolyTraitRef<'tcx>, current: &ty::PolyTraitRef<'tcx>, ) -> bool { - let mut matcher = ty::_match::Match::new(self.tcx()); + let mut matcher = ty::_match::Match::new( + self.tcx(), self.infcx.trait_object_mode()); matcher.relate(previous, current).is_ok() } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 96bb545f25c..70d36e9afe1 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -24,10 +24,10 @@ pub mod specialization_graph; use hir::def_id::DefId; use infer::{InferCtxt, InferOk}; use lint; +use traits::{self, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use syntax_pos::DUMMY_SP; -use traits::{self, ObligationCause, TraitEngine}; use traits::select::IntercrateAmbiguityCause; use ty::{self, TyCtxt, TypeFoldable}; use ty::subst::{Subst, Substs}; @@ -36,6 +36,7 @@ use super::{SelectionContext, FulfillmentContext}; use super::util::impl_trait_ref_and_oblig; /// Information pertinent to an overlapping impl error. +#[derive(Debug)] pub struct OverlapError { pub with_impl: DefId, pub trait_desc: String, @@ -318,8 +319,9 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>( let insert_result = sg.insert(tcx, impl_def_id); // Report error if there was one. let (overlap, used_to_be_allowed) = match insert_result { - Err(overlap) => (Some(overlap), false), - Ok(opt_overlap) => (opt_overlap, true) + Err(overlap) => (Some(overlap), None), + Ok(Some(overlap)) => (Some(overlap.error), Some(overlap.kind)), + Ok(None) => (None, None) }; if let Some(overlap) = overlap { @@ -329,14 +331,20 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>( String::new(), |ty| { format!(" for type `{}`", ty) }), - if used_to_be_allowed { " (E0119)" } else { "" } + if used_to_be_allowed.is_some() { " (E0119)" } else { "" } ); let impl_span = tcx.sess.source_map().def_span( tcx.span_of_impl(impl_def_id).unwrap() ); - let mut err = if used_to_be_allowed { + let mut err = if let Some(kind) = used_to_be_allowed { + let lint = match kind { + FutureCompatOverlapErrorKind::Issue43355 => + lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS, + FutureCompatOverlapErrorKind::Issue33140 => + lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS, + }; tcx.struct_span_lint_node( - lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS, + lint, tcx.hir().as_local_node_id(impl_def_id).unwrap(), impl_span, &msg) diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index b0ca2f6cecc..1a228660306 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -17,6 +17,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, use traits; use ty::{self, TyCtxt, TypeFoldable}; use ty::fast_reject::{self, SimplifiedType}; +use ty::relate::TraitObjectMode; use rustc_data_structures::sync::Lrc; use syntax::ast::Ident; use util::captures::Captures; @@ -68,10 +69,22 @@ struct Children { blanket_impls: Vec<DefId>, } +#[derive(Copy, Clone, Debug)] +pub enum FutureCompatOverlapErrorKind { + Issue43355, + Issue33140, +} + +#[derive(Debug)] +pub struct FutureCompatOverlapError { + pub error: OverlapError, + pub kind: FutureCompatOverlapErrorKind +} + /// The result of attempting to insert an impl into a group of children. enum Inserted { /// The impl was inserted as a new child in this group of children. - BecameNewSibling(Option<OverlapError>), + BecameNewSibling(Option<FutureCompatOverlapError>), /// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc. ReplaceChildren(Vec<DefId>), @@ -170,6 +183,7 @@ impl<'a, 'gcx, 'tcx> Children { possible_sibling, impl_def_id, traits::IntercrateMode::Issue43355, + TraitObjectMode::NoSquash, |overlap| { if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { return Ok((false, false)); @@ -200,12 +214,36 @@ impl<'a, 'gcx, 'tcx> Children { replace_children.push(possible_sibling); } else { if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { + // do future-compat checks for overlap. Have issue #43355 + // errors overwrite issue #33140 errors when both are present. + + traits::overlapping_impls( + tcx, + possible_sibling, + impl_def_id, + traits::IntercrateMode::Fixed, + TraitObjectMode::SquashAutoTraitsIssue33140, + |overlap| { + last_lint = Some(FutureCompatOverlapError { + error: overlap_error(overlap), + kind: FutureCompatOverlapErrorKind::Issue33140 + }); + }, + || (), + ); + traits::overlapping_impls( tcx, possible_sibling, impl_def_id, traits::IntercrateMode::Fixed, - |overlap| last_lint = Some(overlap_error(overlap)), + TraitObjectMode::NoSquash, + |overlap| { + last_lint = Some(FutureCompatOverlapError { + error: overlap_error(overlap), + kind: FutureCompatOverlapErrorKind::Issue43355 + }); + }, || (), ); } @@ -272,7 +310,7 @@ impl<'a, 'gcx, 'tcx> Graph { pub fn insert(&mut self, tcx: TyCtxt<'a, 'gcx, 'tcx>, impl_def_id: DefId) - -> Result<Option<OverlapError>, OverlapError> { + -> Result<Option<FutureCompatOverlapError>, OverlapError> { assert!(impl_def_id.is_local()); let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs index d20b6d36199..29067bf518d 100644 --- a/src/librustc/ty/_match.rs +++ b/src/librustc/ty/_match.rs @@ -29,17 +29,24 @@ use ty::relate::{self, Relate, TypeRelation, RelateResult}; /// important thing about the result is Ok/Err. Also, matching never /// affects any type variables or unification state. pub struct Match<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx> + tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_object_mode: relate::TraitObjectMode } impl<'a, 'gcx, 'tcx> Match<'a, 'gcx, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Match<'a, 'gcx, 'tcx> { - Match { tcx } + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_object_mode: relate::TraitObjectMode) + -> Match<'a, 'gcx, 'tcx> { + Match { tcx, trait_object_mode } } } impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> { fn tag(&self) -> &'static str { "Match" } + fn trait_object_mode(&self) -> relate::TraitObjectMode { + self.trait_object_mode + } + fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.tcx } fn a_is_expected(&self) -> bool { true } // irrelevant diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 7005e14c26c..bd01dd8cb0c 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -43,6 +43,9 @@ pub enum SimplifiedTypeGen<D> PtrSimplifiedType, NeverSimplifiedType, TupleSimplifiedType(usize), + /// A trait object, all of whose components are markers + /// (e.g., `dyn Send + Sync`). + MarkerTraitObjectSimplifiedType, TraitSimplifiedType(D), ClosureSimplifiedType(D), GeneratorSimplifiedType(D), @@ -78,7 +81,12 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Array(..) | ty::Slice(_) => Some(ArraySimplifiedType), ty::RawPtr(_) => Some(PtrSimplifiedType), ty::Dynamic(ref trait_info, ..) => { - Some(TraitSimplifiedType(trait_info.principal().def_id())) + let principal_def_id = trait_info.principal().def_id(); + if tcx.trait_is_auto(principal_def_id) { + Some(MarkerTraitObjectSimplifiedType) + } else { + Some(TraitSimplifiedType(principal_def_id)) + } } ty::Ref(_, ty, _) => { // since we introduce auto-refs during method lookup, we @@ -144,6 +152,7 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> { NeverSimplifiedType => NeverSimplifiedType, TupleSimplifiedType(n) => TupleSimplifiedType(n), TraitSimplifiedType(d) => TraitSimplifiedType(map(d)), + MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType, ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)), GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)), GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n), @@ -170,7 +179,8 @@ impl<'a, 'gcx, D> HashStable<StableHashingContext<'a>> for SimplifiedTypeGen<D> ArraySimplifiedType | PtrSimplifiedType | NeverSimplifiedType | - ParameterSimplifiedType => { + ParameterSimplifiedType | + MarkerTraitObjectSimplifiedType => { // nothing to do } IntSimplifiedType(t) => t.hash_stable(hcx, hasher), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a1fc949137d..429b7f03af8 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1754,17 +1754,19 @@ bitflags! { pub struct AdtFlags: u32 { const NO_ADT_FLAGS = 0; const IS_ENUM = 1 << 0; - const IS_PHANTOM_DATA = 1 << 1; - const IS_FUNDAMENTAL = 1 << 2; - const IS_UNION = 1 << 3; - const IS_BOX = 1 << 4; + const IS_UNION = 1 << 1; + const IS_STRUCT = 1 << 2; + const HAS_CTOR = 1 << 3; + const IS_PHANTOM_DATA = 1 << 4; + const IS_FUNDAMENTAL = 1 << 5; + const IS_BOX = 1 << 6; /// Indicates whether the type is an `Arc`. - const IS_ARC = 1 << 5; + const IS_ARC = 1 << 7; /// Indicates whether the type is an `Rc`. - const IS_RC = 1 << 6; + const IS_RC = 1 << 8; /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. /// (i.e., this flag is never set unless this ADT is an enum). - const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 7; + const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 9; } } @@ -2079,31 +2081,43 @@ impl<'a, 'gcx, 'tcx> AdtDef { repr: ReprOptions) -> Self { debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr); let mut flags = AdtFlags::NO_ADT_FLAGS; + + if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") { + debug!("found non-exhaustive variant list for {:?}", did); + flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; + } + flags |= match kind { + AdtKind::Enum => AdtFlags::IS_ENUM, + AdtKind::Union => AdtFlags::IS_UNION, + AdtKind::Struct => AdtFlags::IS_STRUCT, + }; + + if let AdtKind::Struct = kind { + let variant_def = &variants[VariantIdx::new(0)]; + let def_key = tcx.def_key(variant_def.did); + match def_key.disambiguated_data.data { + DefPathData::StructCtor => flags |= AdtFlags::HAS_CTOR, + _ => (), + } + } + let attrs = tcx.get_attrs(did); if attr::contains_name(&attrs, "fundamental") { - flags = flags | AdtFlags::IS_FUNDAMENTAL; + flags |= AdtFlags::IS_FUNDAMENTAL; } if Some(did) == tcx.lang_items().phantom_data() { - flags = flags | AdtFlags::IS_PHANTOM_DATA; + flags |= AdtFlags::IS_PHANTOM_DATA; } if Some(did) == tcx.lang_items().owned_box() { - flags = flags | AdtFlags::IS_BOX; + flags |= AdtFlags::IS_BOX; } if Some(did) == tcx.lang_items().arc() { - flags = flags | AdtFlags::IS_ARC; + flags |= AdtFlags::IS_ARC; } if Some(did) == tcx.lang_items().rc() { - flags = flags | AdtFlags::IS_RC; - } - if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") { - debug!("found non-exhaustive variant list for {:?}", did); - flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; - } - match kind { - AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM, - AdtKind::Union => flags = flags | AdtFlags::IS_UNION, - AdtKind::Struct => {} + flags |= AdtFlags::IS_RC; } + AdtDef { did, variants, @@ -2114,25 +2128,25 @@ impl<'a, 'gcx, 'tcx> AdtDef { #[inline] pub fn is_struct(&self) -> bool { - !self.is_union() && !self.is_enum() + self.flags.contains(AdtFlags::IS_STRUCT) } #[inline] pub fn is_union(&self) -> bool { - self.flags.intersects(AdtFlags::IS_UNION) + self.flags.contains(AdtFlags::IS_UNION) } #[inline] pub fn is_enum(&self) -> bool { - self.flags.intersects(AdtFlags::IS_ENUM) + self.flags.contains(AdtFlags::IS_ENUM) } #[inline] pub fn is_variant_list_non_exhaustive(&self) -> bool { - self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) + self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) } - /// Returns the kind of the ADT - Struct or Enum. + /// Returns the kind of the ADT. #[inline] pub fn adt_kind(&self) -> AdtKind { if self.is_enum() { @@ -2161,33 +2175,39 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } - /// Returns whether this type is #[fundamental] for the purposes + /// If this function returns `true`, it implies that `is_struct` must return `true`. + #[inline] + pub fn has_ctor(&self) -> bool { + self.flags.contains(AdtFlags::HAS_CTOR) + } + + /// Returns whether this type is `#[fundamental]` for the purposes /// of coherence checking. #[inline] pub fn is_fundamental(&self) -> bool { - self.flags.intersects(AdtFlags::IS_FUNDAMENTAL) + self.flags.contains(AdtFlags::IS_FUNDAMENTAL) } /// Returns `true` if this is PhantomData<T>. #[inline] pub fn is_phantom_data(&self) -> bool { - self.flags.intersects(AdtFlags::IS_PHANTOM_DATA) + self.flags.contains(AdtFlags::IS_PHANTOM_DATA) } /// Returns `true` if this is `Arc<T>`. pub fn is_arc(&self) -> bool { - self.flags.intersects(AdtFlags::IS_ARC) + self.flags.contains(AdtFlags::IS_ARC) } /// Returns `true` if this is `Rc<T>`. pub fn is_rc(&self) -> bool { - self.flags.intersects(AdtFlags::IS_RC) + self.flags.contains(AdtFlags::IS_RC) } /// Returns `true` if this is Box<T>. #[inline] pub fn is_box(&self) -> bool { - self.flags.intersects(AdtFlags::IS_BOX) + self.flags.contains(AdtFlags::IS_BOX) } /// Returns whether this type has a destructor. diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 7ad4fd58273..88c3e5c8715 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -35,9 +35,20 @@ pub enum Cause { ExistentialRegionBound, // relating an existential region bound } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum TraitObjectMode { + NoSquash, + /// A temporary mode to treat `Send + Sync = Sync + Send`, should be + /// used only in coherence. + SquashAutoTraitsIssue33140 +} + pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized { fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx>; + /// Return the trait object mode to be used. + fn trait_object_mode(&self) -> TraitObjectMode; + /// Returns a static string we can use for printouts. fn tag(&self) -> &'static str; @@ -596,14 +607,44 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> { a: &Self, b: &Self) -> RelateResult<'tcx, Self> - where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { + use ty::ExistentialPredicate::*; - if a.len() != b.len() { + let tcx = relation.tcx(); + let (a_buf, b_buf); + let (a_norm, b_norm): (&[_], &[_]) = match relation.trait_object_mode() { + TraitObjectMode::NoSquash => { + (a, b) + } + TraitObjectMode::SquashAutoTraitsIssue33140 => { + // Treat auto-trait "principal" components as equal + // to the non-principal components, to make + // `dyn Send+Sync = dyn Sync+Send`. + let normalize = |d: &[ty::ExistentialPredicate<'tcx>]| { + let mut result: Vec<_> = d.iter().map(|pi| match pi { + Trait(ref a) if tcx.trait_is_auto(a.def_id) => { + AutoTrait(a.def_id) + }, + other => *other + }).collect(); + + result.sort_by(|a, b| a.stable_cmp(tcx, b)); + result.dedup(); + result + }; + + a_buf = normalize(a); + b_buf = normalize(b); + + (&a_buf, &b_buf) + } + }; + + if a_norm.len() != b_norm.len() { return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))); } - let tcx = relation.tcx(); - let v = a.iter().zip(b.iter()).map(|(ep_a, ep_b)| { + let v = a_norm.iter().zip(b_norm.iter()).map(|(ep_a, ep_b)| { use ty::ExistentialPredicate::*; match (*ep_a, *ep_b) { (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)), diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index d6aeb288b5c..1d28c4fa114 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -35,6 +35,7 @@ CloneTypeFoldableAndLiftImpls! { usize, ::ty::layout::VariantIdx, u64, + String, ::middle::region::Scope, ::syntax::ast::FloatTy, ::syntax::ast::NodeId, diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index a95ddefc869..01b1387d9cc 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -1024,17 +1024,11 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { self.count_insn("minnum"); - unsafe { - let instr = llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs); - instr.expect("LLVMRustBuildMinNum is not available in LLVM version < 6.0") - } + unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) } } fn maxnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { self.count_insn("maxnum"); - unsafe { - let instr = llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs); - instr.expect("LLVMRustBuildMaxNum is not available in LLVM version < 6.0") - } + unsafe { llvm::LLVMRustBuildMaxNum(self.llbuilder, lhs, rhs) } } fn select( diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 0bd6146f5aa..b75cd8f68b3 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -10,7 +10,6 @@ use attributes; use llvm; -use llvm_util; use rustc::dep_graph::DepGraphSafe; use rustc::hir; use debuginfo; @@ -446,10 +445,6 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { attributes::apply_target_cpu_attr(self, llfn) } - fn closure_env_needs_indirect_debuginfo(&self) -> bool { - llvm_util::get_major_version() < 6 - } - fn create_used_variable(&self) { let name = const_cstr!("llvm.used"); let section = const_cstr!("llvm.metadata"); diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 8b26ada1576..e229f8d95cd 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1192,7 +1192,7 @@ fn generic_simd_intrinsic( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } - // every intrinsic takes a SIMD vector as its first argument + // every intrinsic below takes a SIMD vector as its first argument require_simd!(arg_tys[0], "input"); let in_ty = arg_tys[0]; let in_elem = arg_tys[0].simd_type(tcx); @@ -1296,6 +1296,7 @@ fn generic_simd_intrinsic( if name == "simd_select" { let m_elem_ty = in_elem; let m_len = in_len; + require_simd!(arg_tys[1], "argument"); let v_len = arg_tys[1].simd_size(tcx); require!(m_len == v_len, "mismatched lengths: mask length `{}` != other vector length `{}`", diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 127759a4326..4732db88ec1 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1222,12 +1222,12 @@ extern "C" { B: &Builder<'a>, LHS: &'a Value, LHS: &'a Value, - ) -> Option<&'a Value>; + ) -> &'a Value; pub fn LLVMRustBuildMaxNum( B: &Builder<'a>, LHS: &'a Value, LHS: &'a Value, - ) -> Option<&'a Value>; + ) -> &'a Value; // Atomic Operations pub fn LLVMRustBuildAtomicLoad(B: &Builder<'a>, diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 12109ae1662..82b1d7e8b40 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -140,6 +140,7 @@ const X86_WHITELIST: &[(&str, Option<&str>)] = &[ ("avx512vpopcntdq", Some("avx512_target_feature")), ("bmi1", None), ("bmi2", None), + ("cmpxchg16b", Some("cmpxchg16b_target_feature")), ("fma", None), ("fxsr", None), ("lzcnt", None), @@ -212,6 +213,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { ("x86", "pclmulqdq") => "pclmul", ("x86", "rdrand") => "rdrnd", ("x86", "bmi1") => "bmi", + ("x86", "cmpxchg16b") => "cx16", ("aarch64", "fp") => "fp-armv8", ("aarch64", "fp16") => "fullfp16", (_, s) => s, diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 750de1c660c..d316b3ec350 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -610,35 +610,13 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( }; let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); - // Store the pointer to closure data in an alloca for debuginfo - // because that's what the llvm.dbg.declare intrinsic expects. - - // FIXME(eddyb) this shouldn't be necessary but SROA seems to - // mishandle DW_OP_plus not preceded by DW_OP_deref, i.e., it - // doesn't actually strip the offset when splitting the closure - // environment into its components so it ends up out of bounds. - // (cuviper) It seems to be fine without the alloca on LLVM 6 and later. - let env_alloca = !env_ref && bx.closure_env_needs_indirect_debuginfo(); - let env_ptr = if env_alloca { - let scratch = PlaceRef::alloca(bx, - bx.layout_of(tcx.mk_mut_ptr(arg.layout.ty)), - "__debuginfo_env_ptr"); - bx.store(place.llval, scratch.llval, scratch.align); - scratch.llval - } else { - place.llval - }; - for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() { let byte_offset_of_var_in_env = closure_layout.fields.offset(i).bytes(); let ops = bx.debuginfo_upvar_decls_ops_sequence(byte_offset_of_var_in_env); // The environment and the capture can each be indirect. - - // FIXME(eddyb) see above why we sometimes have to keep - // a pointer in an alloca for debuginfo atm. - let mut ops = if env_ref || env_alloca { &ops[..] } else { &ops[1..] }; + let mut ops = if env_ref { &ops[..] } else { &ops[1..] }; let ty = if let (true, &ty::Ref(_, ty, _)) = (decl.by_ref, &ty.sty) { ty @@ -648,7 +626,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( }; let variable_access = VariableAccess::IndirectVariable { - alloca: env_ptr, + alloca: place.llval, address_operations: &ops }; bx.declare_local( diff --git a/src/librustc_codegen_ssa/traits/misc.rs b/src/librustc_codegen_ssa/traits/misc.rs index d8871dd3a58..57afb800d01 100644 --- a/src/librustc_codegen_ssa/traits/misc.rs +++ b/src/librustc_codegen_ssa/traits/misc.rs @@ -32,7 +32,6 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn stats(&self) -> &RefCell<Stats>; fn consume_stats(self) -> RefCell<Stats>; fn codegen_unit(&self) -> &Arc<CodegenUnit<'tcx>>; - fn closure_env_needs_indirect_debuginfo(&self) -> bool; fn used_statics(&self) -> &RefCell<Vec<Self::Value>>; fn set_frame_pointer_elimination(&self, llfn: Self::Value); fn apply_target_cpu_attr(&self, llfn: Self::Value); diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 66364ff88b3..347121833d3 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -294,6 +294,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { edition: None, }, FutureIncompatibleInfo { + id: LintId::of(ORDER_DEPENDENT_TRAIT_OBJECTS), + reference: "issue #56484 <https://github.com/rust-lang/rust/issues/56484>", + edition: None, + }, + FutureIncompatibleInfo { id: LintId::of(TYVAR_BEHIND_RAW_POINTER), reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>", edition: Some(Edition::Edition2018), diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index e3029c6a19d..5eca62938f7 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -545,7 +545,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx self.mutate_place( ContextKind::SetDiscrim.new(location), (place, span), - Shallow(Some(ArtificialField::Discriminant)), + Shallow(None), JustWrite, flow_state, ); @@ -782,7 +782,6 @@ use self::AccessDepth::{Deep, Shallow}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum ArtificialField { - Discriminant, ArrayLength, ShallowBorrow, } @@ -1191,14 +1190,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => { let af = match *rvalue { - Rvalue::Len(..) => ArtificialField::ArrayLength, - Rvalue::Discriminant(..) => ArtificialField::Discriminant, + Rvalue::Len(..) => Some(ArtificialField::ArrayLength), + Rvalue::Discriminant(..) => None, _ => unreachable!(), }; self.access_place( context, (place, span), - (Shallow(Some(af)), Read(ReadKind::Copy)), + (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, flow_state, ); diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 8af23a8813a..07bda8af626 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -99,7 +99,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { self.mutate_place( ContextKind::SetDiscrim.new(location), place, - Shallow(Some(ArtificialField::Discriminant)), + Shallow(None), JustWrite, ); } @@ -360,14 +360,14 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { Rvalue::Len(ref place) | Rvalue::Discriminant(ref place) => { let af = match *rvalue { - Rvalue::Len(..) => ArtificialField::ArrayLength, - Rvalue::Discriminant(..) => ArtificialField::Discriminant, + Rvalue::Len(..) => Some(ArtificialField::ArrayLength), + Rvalue::Discriminant(..) => None, _ => unreachable!(), }; self.access_place( context, place, - (Shallow(Some(af)), Read(ReadKind::Copy)), + (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, ); } diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index eeac915cff3..e24586cca09 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -165,15 +165,12 @@ fn place_components_conflict<'gcx, 'tcx>( let base_ty = base.ty(mir, tcx).to_ty(tcx); match (elem, &base_ty.sty, access) { - (_, _, Shallow(Some(ArtificialField::Discriminant))) - | (_, _, Shallow(Some(ArtificialField::ArrayLength))) + (_, _, Shallow(Some(ArtificialField::ArrayLength))) | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { - // The discriminant and array length are like - // additional fields on the type; they do not - // overlap any existing data there. Furthermore, - // they cannot actually be a prefix of any - // borrowed place (at least in MIR as it is - // currently.) + // The array length is like additional fields on the + // type; it does not overlap any existing data there. + // Furthermore, if cannot actually be a prefix of any + // borrowed place (at least in MIR as it is currently.) // // e.g., a (mutable) borrow of `a[5]` while we read the // array length of `a`. diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 7e7c0b15555..4d61bf8dae6 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -19,7 +19,6 @@ use build::{BlockAnd, BlockAndExtension, Builder}; use build::{GuardFrame, GuardFrameLocal, LocalsForNode}; use hair::*; use hair::pattern::PatternTypeProjections; -use rustc::hir; use rustc::mir::*; use rustc::ty::{self, Ty}; use rustc::ty::layout::VariantIdx; @@ -100,7 +99,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .collect(); // create binding start block for link them by false edges - let candidate_count = arms.iter().fold(0, |ac, c| ac + c.patterns.len()); + let candidate_count = arms.iter().map(|c| c.patterns.len()).sum::<usize>(); let pre_binding_blocks: Vec<_> = (0..=candidate_count) .map(|_| self.cfg.start_new_block()) .collect(); @@ -337,7 +336,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn place_into_pattern( &mut self, - mut block: BasicBlock, + block: BasicBlock, irrefutable_pat: Pattern<'tcx>, initializer: &Place<'tcx>, set_match_place: bool, @@ -359,7 +358,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Simplify the candidate. Since the pattern is irrefutable, this should // always convert all match-pairs into bindings. - unpack!(block = self.simplify_candidate(block, &mut candidate)); + self.simplify_candidate(&mut candidate); if !candidate.match_pairs.is_empty() { span_bug!( @@ -681,12 +680,7 @@ enum TestKind<'tcx> { }, // test whether the value falls within an inclusive or exclusive range - Range { - lo: &'tcx ty::Const<'tcx>, - hi: &'tcx ty::Const<'tcx>, - ty: Ty<'tcx>, - end: hir::RangeEnd, - }, + Range(PatternRange<'tcx>), // test length of the slice is equal to len Len { @@ -745,7 +739,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // complete, all the match pairs which remain require some // form of test, whether it be a switch or pattern comparison. for candidate in &mut candidates { - unpack!(block = self.simplify_candidate(block, candidate)); + self.simplify_candidate(candidate); } // The candidates are sorted by priority. Check to see @@ -1035,7 +1029,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { test, match_pair ); let target_blocks = self.perform_test(block, &match_pair.place, &test); - let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect(); + let mut target_candidates = vec![vec![]; target_blocks.len()]; // Sort the candidates into the appropriate vector in // `target_candidates`. Note that at some point we may diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 328b330f762..0ce64283870 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -22,10 +22,9 @@ //! sort of test: for example, testing which variant an enum is, or //! testing a value against a constant. -use build::{BlockAnd, BlockAndExtension, Builder}; +use build::Builder; use build::matches::{Ascription, Binding, MatchPair, Candidate}; use hair::*; -use rustc::mir::*; use rustc::ty; use rustc::ty::layout::{Integer, IntegerExt, Size}; use syntax::attr::{SignedInt, UnsignedInt}; @@ -35,24 +34,23 @@ use std::mem; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn simplify_candidate<'pat>(&mut self, - block: BasicBlock, - candidate: &mut Candidate<'pat, 'tcx>) - -> BlockAnd<()> { + candidate: &mut Candidate<'pat, 'tcx>) { // repeatedly simplify match pairs until fixed point is reached loop { let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]); - let mut progress = match_pairs.len(); // count how many were simplified + let mut changed = false; for match_pair in match_pairs { match self.simplify_match_pair(match_pair, candidate) { - Ok(()) => {} + Ok(()) => { + changed = true; + } Err(match_pair) => { candidate.match_pairs.push(match_pair); - progress -= 1; // this one was not simplified } } } - if progress == 0 { - return block.unit(); // if we were not able to simplify any, done. + if !changed { + return; // if we were not able to simplify any, done. } } } @@ -109,7 +107,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { Err(match_pair) } - PatternKind::Range { lo, hi, ty, end } => { + PatternKind::Range(PatternRange { lo, hi, ty, end }) => { let range = match ty.sty { ty::Char => { Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 5d9cb014f58..c8dec6d0b97 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -18,6 +18,7 @@ use build::Builder; use build::matches::{Candidate, MatchPair, Test, TestKind}; use hair::*; +use hair::pattern::compare_const_vals; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::fx::FxHashMap; use rustc::ty::{self, Ty}; @@ -71,16 +72,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - PatternKind::Range { lo, hi, ty, end } => { - assert!(ty == match_pair.pattern.ty); + PatternKind::Range(range) => { + assert!(range.ty == match_pair.pattern.ty); Test { span: match_pair.pattern.span, - kind: TestKind::Range { - lo, - hi, - ty, - end, - }, + kind: TestKind::Range(range), } } @@ -136,7 +132,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { .. } => { panic!("you should have called add_variants_to_switch instead!"); } - PatternKind::Range { .. } | + PatternKind::Range(range) => { + // Check that none of the switch values are in the range. + self.values_not_contained_in_range(range, indices) + .unwrap_or(false) + } PatternKind::Slice { .. } | PatternKind::Array { .. } | PatternKind::Wild | @@ -200,20 +200,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { for (idx, discr) in adt_def.discriminants(tcx) { target_blocks.push(if variants.contains(idx) { values.push(discr.val); - targets.push(self.cfg.start_new_block()); - *targets.last().unwrap() + let block = self.cfg.start_new_block(); + targets.push(block); + block } else { - if otherwise_block.is_none() { - otherwise_block = Some(self.cfg.start_new_block()); - } - otherwise_block.unwrap() + *otherwise_block + .get_or_insert_with(|| self.cfg.start_new_block()) }); } - if let Some(otherwise_block) = otherwise_block { - targets.push(otherwise_block); - } else { - targets.push(self.unreachable_block()); - } + targets.push( + otherwise_block + .unwrap_or_else(|| self.unreachable_block()), + ); debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}", num_enum_variants, values, variants); let discr_ty = adt_def.repr.discr_type().to_ty(tcx); @@ -378,7 +376,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - TestKind::Range { ref lo, ref hi, ty, ref end } => { + TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => { // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. let lo = self.literal_operand(test.span, ty.clone(), lo.clone()); let hi = self.literal_operand(test.span, ty.clone(), hi.clone()); @@ -490,8 +488,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // away.) let tested_match_pair = candidate.match_pairs.iter() .enumerate() - .filter(|&(_, mp)| mp.place == *test_place) - .next(); + .find(|&(_, mp)| mp.place == *test_place); let (match_pair_index, match_pair) = match tested_match_pair { Some(pair) => pair, None => { @@ -532,6 +529,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { resulting_candidates[index].push(new_candidate); true } + + (&TestKind::SwitchInt { switch_ty: _, ref options, ref indices }, + &PatternKind::Range(range)) => { + let not_contained = self + .values_not_contained_in_range(range, indices) + .unwrap_or(false); + + if not_contained { + // No switch values are contained in the pattern range, + // so the pattern can be matched only if this test fails. + let otherwise = options.len(); + resulting_candidates[otherwise].push(candidate.clone()); + true + } else { + false + } + } + (&TestKind::SwitchInt { .. }, _) => false, @@ -610,8 +625,63 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } + (&TestKind::Range(test), + &PatternKind::Range(pat)) => { + if test == pat { + resulting_candidates[0] + .push(self.candidate_without_match_pair( + match_pair_index, + candidate, + )); + return true; + } + + let no_overlap = (|| { + use std::cmp::Ordering::*; + use rustc::hir::RangeEnd::*; + + let param_env = ty::ParamEnv::empty().and(test.ty); + let tcx = self.hir.tcx(); + + let lo = compare_const_vals(tcx, test.lo, pat.hi, param_env)?; + let hi = compare_const_vals(tcx, test.hi, pat.lo, param_env)?; + + match (test.end, pat.end, lo, hi) { + // pat < test + (_, _, Greater, _) | + (_, Excluded, Equal, _) | + // pat > test + (_, _, _, Less) | + (Excluded, _, _, Equal) => Some(true), + _ => Some(false), + } + })(); + + if no_overlap == Some(true) { + // Testing range does not overlap with pattern range, + // so the pattern can be matched only if this test fails. + resulting_candidates[1].push(candidate.clone()); + true + } else { + false + } + } + + (&TestKind::Range(range), &PatternKind::Constant { ref value }) => { + if self.const_range_contains(range, value) == Some(false) { + // `value` is not contained in the testing range, + // so `value` can be matched only if this test fails. + resulting_candidates[1].push(candidate.clone()); + true + } else { + false + } + } + + (&TestKind::Range { .. }, _) => false, + + (&TestKind::Eq { .. }, _) | - (&TestKind::Range { .. }, _) | (&TestKind::Len { .. }, _) => { // These are all binary tests. // @@ -722,6 +792,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { "simplifyable pattern found: {:?}", match_pair.pattern) } + + fn const_range_contains( + &self, + range: PatternRange<'tcx>, + value: &'tcx ty::Const<'tcx>, + ) -> Option<bool> { + use std::cmp::Ordering::*; + + let param_env = ty::ParamEnv::empty().and(range.ty); + let tcx = self.hir.tcx(); + + let a = compare_const_vals(tcx, range.lo, value, param_env)?; + let b = compare_const_vals(tcx, value, range.hi, param_env)?; + + match (b, range.end) { + (Less, _) | + (Equal, RangeEnd::Included) if a != Greater => Some(true), + _ => Some(false), + } + } + + fn values_not_contained_in_range( + &self, + range: PatternRange<'tcx>, + indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>, + ) -> Option<bool> { + for val in indices.keys() { + if self.const_range_contains(range, val)? { + return Some(false); + } + } + + Some(true) + } } fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index ab52d9be6b8..d6af125debf 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -111,13 +111,6 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t let safety = match fn_sig.unsafety { hir::Unsafety::Normal => Safety::Safe, - hir::Unsafety::Unsafe if tcx.is_min_const_fn(fn_def_id) => { - // As specified in #55607, a `const unsafe fn` differs - // from an `unsafe fn` in that its body is still considered - // safe code by default. - assert!(implicit_argument.is_none()); - Safety::Safe - }, hir::Unsafety::Unsafe => Safety::FnUnsafe, }; @@ -856,15 +849,17 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - Mir::new(self.cfg.basic_blocks, - self.source_scopes, - ClearCrossCrate::Set(self.source_scope_local_data), - IndexVec::new(), - yield_ty, - self.local_decls, - self.arg_count, - self.upvar_decls, - self.fn_span + Mir::new( + self.cfg.basic_blocks, + self.source_scopes, + ClearCrossCrate::Set(self.source_scope_local_data), + IndexVec::new(), + yield_ty, + self.local_decls, + self.arg_count, + self.upvar_decls, + self.fn_span, + self.hir.control_flow_destroyed(), ) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index a1471adac60..f93dbce97b5 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -372,6 +372,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // FIXME(eddyb) use logical ops in constants when // they can handle that kind of control-flow. (hir::BinOpKind::And, hir::Constness::Const) => { + cx.control_flow_destroyed.push(( + op.span, + "`&&` operator".into(), + )); ExprKind::Binary { op: BinOp::BitAnd, lhs: lhs.to_ref(), @@ -379,6 +383,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } (hir::BinOpKind::Or, hir::Constness::Const) => { + cx.control_flow_destroyed.push(( + op.span, + "`||` operator".into(), + )); ExprKind::Binary { op: BinOp::BitOr, lhs: lhs.to_ref(), diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index a0b2d99dfd3..5d8732bb8ae 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -56,6 +56,9 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { /// True if this constant/function needs overflow checks. check_overflow: bool, + + /// See field with the same name on `Mir` + control_flow_destroyed: Vec<(Span, String)>, } impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { @@ -96,9 +99,13 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { constness, body_owner_kind, check_overflow, + control_flow_destroyed: Vec::new(), } } + pub fn control_flow_destroyed(self) -> Vec<(Span, String)> { + self.control_flow_destroyed + } } impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index e604b118eac..b254fce4b76 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -29,7 +29,7 @@ pub mod cx; mod constant; pub mod pattern; -pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern}; +pub use self::pattern::{BindingMode, Pattern, PatternKind, PatternRange, FieldPattern}; pub(crate) use self::pattern::{PatternTypeProjection, PatternTypeProjections}; mod util; diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 5cfcc16162e..7ec6bbfe3c1 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -173,7 +173,7 @@ use self::WitnessPreference::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; -use super::{FieldPattern, Pattern, PatternKind}; +use super::{FieldPattern, Pattern, PatternKind, PatternRange}; use super::{PatternFoldable, PatternFolder, compare_const_vals}; use rustc::hir::def_id::DefId; @@ -604,12 +604,12 @@ impl<'tcx> Witness<'tcx> { _ => { match *ctor { ConstantValue(value) => PatternKind::Constant { value }, - ConstantRange(lo, hi, ty, end) => PatternKind::Range { + ConstantRange(lo, hi, ty, end) => PatternKind::Range(PatternRange { lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)), hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)), ty, end, - }, + }), _ => PatternKind::Wild, } } @@ -872,7 +872,7 @@ impl<'tcx> IntRange<'tcx> { -> Option<IntRange<'tcx>> { Self::from_ctor(tcx, &match pat.kind { box PatternKind::Constant { value } => ConstantValue(value), - box PatternKind::Range { lo, hi, ty, end } => ConstantRange( + box PatternKind::Range(PatternRange { lo, hi, ty, end }) => ConstantRange( lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(), hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(), ty, @@ -1311,7 +1311,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>, Some(vec![Variant(adt_def.variants[variant_index].did)]) } PatternKind::Constant { value } => Some(vec![ConstantValue(value)]), - PatternKind::Range { lo, hi, ty, end } => + PatternKind::Range(PatternRange { lo, hi, ty, end }) => Some(vec![ConstantRange( lo.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(), hi.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(), @@ -1642,7 +1642,7 @@ fn constructor_covered_by_range<'a, 'tcx>( ) -> Result<bool, ErrorReported> { let (from, to, end, ty) = match pat.kind { box PatternKind::Constant { value } => (value, value, RangeEnd::Included, value.ty), - box PatternKind::Range { lo, hi, ty, end } => (lo, hi, end, ty), + box PatternKind::Range(PatternRange { lo, hi, end, ty }) => (lo, hi, end, ty), _ => bug!("`constructor_covered_by_range` called with {:?}", pat), }; trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index ddd6a705b04..f78a70f6a25 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -24,7 +24,7 @@ use hair::constant::*; use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections}; use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; -use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty}; +use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift}; use rustc::ty::subst::{Substs, Kind}; use rustc::ty::layout::VariantIdx; use rustc::hir::{self, PatKind, RangeEnd}; @@ -219,12 +219,7 @@ pub enum PatternKind<'tcx> { value: &'tcx ty::Const<'tcx>, }, - Range { - lo: &'tcx ty::Const<'tcx>, - hi: &'tcx ty::Const<'tcx>, - ty: Ty<'tcx>, - end: RangeEnd, - }, + Range(PatternRange<'tcx>), /// matches against a slice, checking the length and extracting elements. /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. @@ -243,6 +238,14 @@ pub enum PatternKind<'tcx> { }, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct PatternRange<'tcx> { + pub lo: &'tcx ty::Const<'tcx>, + pub hi: &'tcx ty::Const<'tcx>, + pub ty: Ty<'tcx>, + pub end: RangeEnd, +} + impl<'tcx> fmt::Display for Pattern<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.kind { @@ -354,7 +357,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { PatternKind::Constant { value } => { fmt_const_val(f, value) } - PatternKind::Range { lo, hi, ty: _, end } => { + PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => { fmt_const_val(f, lo)?; match end { RangeEnd::Included => write!(f, "..=")?, @@ -483,7 +486,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); match (end, cmp) { (RangeEnd::Excluded, Some(Ordering::Less)) => - PatternKind::Range { lo, hi, ty, end }, + PatternKind::Range(PatternRange { lo, hi, ty, end }), (RangeEnd::Excluded, _) => { span_err!( self.tcx.sess, @@ -497,7 +500,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternKind::Constant { value: lo } } (RangeEnd::Included, Some(Ordering::Less)) => { - PatternKind::Range { lo, hi, ty, end } + PatternKind::Range(PatternRange { lo, hi, ty, end }) } (RangeEnd::Included, _) => { let mut err = struct_span_err!( @@ -1177,17 +1180,17 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { } => PatternKind::Constant { value: value.fold_with(folder) }, - PatternKind::Range { + PatternKind::Range(PatternRange { lo, hi, ty, end, - } => PatternKind::Range { + }) => PatternKind::Range(PatternRange { lo: lo.fold_with(folder), hi: hi.fold_with(folder), ty: ty.fold_with(folder), end, - }, + }), PatternKind::Slice { ref prefix, ref slice, @@ -1210,8 +1213,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { } } -pub fn compare_const_vals<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn compare_const_vals<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>, ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, @@ -1233,6 +1236,9 @@ pub fn compare_const_vals<'a, 'tcx>( return fallback(); } + let tcx = tcx.global_tcx(); + let (a, b, ty) = (a, b, ty).lift_to_tcx(tcx).unwrap(); + // FIXME: This should use assert_bits(ty) instead of use_bits // but triggers possibly bugs due to mismatching of arrays and slices if let (Some(a), Some(b)) = (a.to_bits(tcx, ty), b.to_bits(tcx, ty)) { diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 1a35f4da20b..983488da003 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -37,7 +37,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(if_while_or_patterns)] #![feature(try_from)] #![feature(reverse_bits)] -#![feature(underscore_imports)] +#![cfg_attr(stage0, feature(underscore_imports))] #![recursion_limit="256"] diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 11416294605..2728833251a 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -219,7 +219,8 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, local_decls_for_sig(&sig, span), sig.inputs().len(), vec![], - span + span, + vec![], ); if let Some(..) = ty { @@ -396,7 +397,8 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { self.local_decls, self.sig.inputs().len(), vec![], - self.span + self.span, + vec![], ) } @@ -844,7 +846,8 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, local_decls, sig.inputs().len(), vec![], - span + span, + vec![], ); if let Abi::RustCall = sig.abi { mir.spread_arg = Some(Local::new(sig.inputs().len())); @@ -921,6 +924,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, local_decls, sig.inputs().len(), vec![], - span + span, + vec![], ) } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 6af29b74c1c..36078693840 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -311,13 +311,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { violations: &[UnsafetyViolation], unsafe_blocks: &[(ast::NodeId, bool)]) { let safety = self.source_scope_local_data[self.source_info.scope].safety; - let within_unsafe = match (safety, self.min_const_fn) { - // Erring on the safe side, pun intended - (Safety::BuiltinUnsafe, true) | - // mir building encodes const fn bodies as safe, even for `const unsafe fn` - (Safety::FnUnsafe, true) => bug!("const unsafe fn body treated as inherently unsafe"), + let within_unsafe = match safety { // `unsafe` blocks are required in safe code - (Safety::Safe, _) => { + Safety::Safe => { for violation in violations { let mut violation = violation.clone(); match violation.kind { @@ -342,9 +338,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { } false } - // regular `unsafe` function bodies allow unsafe without additional unsafe blocks - (Safety::BuiltinUnsafe, false) | (Safety::FnUnsafe, false) => true, - (Safety::ExplicitUnsafe(node_id), _) => { + // `unsafe` function bodies allow unsafe without additional unsafe blocks + Safety::BuiltinUnsafe | Safety::FnUnsafe => true, + Safety::ExplicitUnsafe(node_id) => { // mark unsafe block as used if there are any unsafe operations inside if !violations.is_empty() { self.used_unsafe.insert(node_id); @@ -616,21 +612,6 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { } in violations.iter() { // Report an error. match kind { - UnsafetyViolationKind::General if tcx.is_min_const_fn(def_id) => { - let mut err = tcx.sess.struct_span_err( - source_info.span, - &format!("{} is unsafe and unsafe operations \ - are not allowed in const fn", description)); - err.span_label(source_info.span, &description.as_str()[..]) - .note(&details.as_str()[..]); - if tcx.fn_sig(def_id).unsafety() == hir::Unsafety::Unsafe { - err.note( - "unsafe action within a `const unsafe fn` still require an `unsafe` \ - block in contrast to regular `unsafe fn`." - ); - } - err.emit(); - } UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => { struct_span_err!( diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 7f8dfc111a4..f5bf73b4300 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -412,7 +412,8 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, initial_locals, 0, vec![], - mir.span + mir.span, + vec![], ), tcx, source: mir, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 5f08dee8728..58a3cb97e41 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -553,7 +553,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { this.super_place(place, context, location); match proj.elem { ProjectionElem::Deref => { - this.add(Qualif::NOT_CONST); + if context.is_mutating_use() { + // `not_const` errors out in const contexts + this.not_const() + } else { + // just make sure this doesn't get promoted + this.add(Qualif::NOT_CONST); + } let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx); match this.mode { Mode::Fn => {}, @@ -1178,7 +1184,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { if self.mir.local_kind(index) == LocalKind::Var && self.const_fn_arg_vars.insert(index) && !self.tcx.features().const_let { - // Direct use of an argument is permitted. match *rvalue { Rvalue::Use(Operand::Copy(Place::Local(local))) | @@ -1189,7 +1194,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } _ => {} } - // Avoid a generic error for other uses of arguments. if self.qualif.contains(Qualif::FN_ARGUMENT) { let decl = &self.mir.local_decls[index]; @@ -1348,6 +1352,37 @@ impl MirPass for QualifyAndPromoteConstants { // Do the actual promotion, now that we know what's viable. promote_consts::promote_candidates(mir, tcx, temps, candidates); } else { + if !mir.control_flow_destroyed.is_empty() { + let mut locals = mir.vars_iter(); + if let Some(local) = locals.next() { + let span = mir.local_decls[local].source_info.span; + let mut error = tcx.sess.struct_span_err( + span, + &format!( + "new features like let bindings are not permitted in {}s \ + which also use short circuiting operators", + mode, + ), + ); + for (span, kind) in mir.control_flow_destroyed.iter() { + error.span_note( + *span, + &format!("use of {} here does not actually short circuit due to \ + the const evaluator presently not being able to do control flow. \ + See https://github.com/rust-lang/rust/issues/49146 for more \ + information.", kind), + ); + } + for local in locals { + let span = mir.local_decls[local].source_info.span; + error.span_note( + span, + "more locals defined here", + ); + } + error.emit(); + } + } let promoted_temps = if mode == Mode::Const { // Already computed by `mir_const_qualif`. const_promoted_temps.unwrap() diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 3c1b9dbd91f..eee167c3579 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -230,7 +230,7 @@ fn check_statement( check_rvalue(tcx, mir, rval, span) } - StatementKind::FakeRead(..) => Err((span, "match in const fn is unstable".into())), + StatementKind::FakeRead(_, place) => check_place(tcx, mir, place, span, PlaceMode::Read), // just an assignment StatementKind::SetDiscriminant { .. } => Ok(()), diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs index f643870dec2..592f721b2f5 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/src/librustc_mir/transform/simplify.rs @@ -108,10 +108,14 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { pub fn simplify(mut self) { self.strip_nops(); + let mut start = START_BLOCK; + loop { let mut changed = false; - for bb in (0..self.basic_blocks.len()).map(BasicBlock::new) { + self.collapse_goto_chain(&mut start, &mut changed); + + for bb in self.basic_blocks.indices() { if self.pred_count[bb] == 0 { continue } @@ -142,6 +146,27 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> { if !changed { break } } + + if start != START_BLOCK { + debug_assert!(self.pred_count[START_BLOCK] == 0); + self.basic_blocks.swap(START_BLOCK, start); + self.pred_count.swap(START_BLOCK, start); + + // pred_count == 1 if the start block has no predecessor _blocks_. + if self.pred_count[START_BLOCK] > 1 { + for (bb, data) in self.basic_blocks.iter_enumerated_mut() { + if self.pred_count[bb] == 0 { + continue; + } + + for target in data.terminator_mut().successors_mut() { + if *target == start { + *target = START_BLOCK; + } + } + } + } + } } // Collapse a goto chain starting from `start` diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 42ead92783d..a5d2edbc5d4 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -41,7 +41,6 @@ pub mod ast_validation; pub mod rvalue_promotion; pub mod hir_stats; pub mod loops; -mod mir_stats; __build_diagnostic_array! { librustc_passes, DIAGNOSTICS } diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs deleted file mode 100644 index fb37f03a1cc..00000000000 --- a/src/librustc_passes/mir_stats.rs +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// The visitors in this module collect sizes and counts of the most important -// pieces of MIR. The resulting numbers are good approximations but not -// completely accurate (some things might be counted twice, others missed). - -use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData}; -use rustc::mir::{Constant, Location, Local, LocalDecl}; -use rustc::mir::{Place, PlaceElem, PlaceProjection}; -use rustc::mir::{Mir, Operand, ProjectionElem}; -use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind}; -use rustc::mir::{Terminator, TerminatorKind, SourceScope, SourceScopeData}; -use rustc::mir::interpret::EvalErrorKind; -use rustc::mir::visit as mir_visit; -use rustc::ty::{self, ClosureSubsts, TyCtxt}; -use rustc::util::nodemap::{FxHashMap}; - -struct NodeData { - count: usize, - size: usize, -} - -struct StatCollector<'a, 'tcx: 'a> { - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - data: FxHashMap<&'static str, NodeData>, -} - -impl<'a, 'tcx> StatCollector<'a, 'tcx> { - - fn record_with_size(&mut self, label: &'static str, node_size: usize) { - let entry = self.data.entry(label).or_insert(NodeData { - count: 0, - size: 0, - }); - - entry.count += 1; - entry.size = node_size; - } - - fn record<T>(&mut self, label: &'static str, node: &T) { - self.record_with_size(label, ::std::mem::size_of_val(node)); - } -} - -impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { - fn visit_mir(&mut self, mir: &Mir<'tcx>) { - self.record("Mir", mir); - - // since the `super_mir` method does not traverse the MIR of - // promoted rvalues, (but we still want to gather statistics - // on the structures represented there) we manually traverse - // the promoted rvalues here. - for promoted_mir in &mir.promoted { - self.visit_mir(promoted_mir); - } - - self.super_mir(mir); - } - - fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { - self.record("BasicBlockData", data); - self.super_basic_block_data(block, data); - } - - fn visit_source_scope_data(&mut self, scope_data: &SourceScopeData) { - self.record("SourceScopeData", scope_data); - self.super_source_scope_data(scope_data); - } - - fn visit_statement(&mut self, - block: BasicBlock, - statement: &Statement<'tcx>, - location: Location) { - self.record("Statement", statement); - self.record(match statement.kind { - StatementKind::Assign(..) => "StatementKind::Assign", - StatementKind::FakeRead(..) => "StatementKind::FakeRead", - StatementKind::Retag { .. } => "StatementKind::Retag", - StatementKind::EscapeToRaw { .. } => "StatementKind::EscapeToRaw", - StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant", - StatementKind::StorageLive(..) => "StatementKind::StorageLive", - StatementKind::StorageDead(..) => "StatementKind::StorageDead", - StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm", - StatementKind::AscribeUserType(..) => "StatementKind::AscribeUserType", - StatementKind::Nop => "StatementKind::Nop", - }, &statement.kind); - self.super_statement(block, statement, location); - } - - fn visit_terminator(&mut self, - block: BasicBlock, - terminator: &Terminator<'tcx>, - location: Location) { - self.record("Terminator", terminator); - self.super_terminator(block, terminator, location); - } - - fn visit_terminator_kind(&mut self, - block: BasicBlock, - kind: &TerminatorKind<'tcx>, - location: Location) { - self.record("TerminatorKind", kind); - self.record(match *kind { - TerminatorKind::Goto { .. } => "TerminatorKind::Goto", - TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt", - TerminatorKind::Resume => "TerminatorKind::Resume", - TerminatorKind::Abort => "TerminatorKind::Abort", - TerminatorKind::Return => "TerminatorKind::Return", - TerminatorKind::Unreachable => "TerminatorKind::Unreachable", - TerminatorKind::Drop { .. } => "TerminatorKind::Drop", - TerminatorKind::DropAndReplace { .. } => "TerminatorKind::DropAndReplace", - TerminatorKind::Call { .. } => "TerminatorKind::Call", - TerminatorKind::Assert { .. } => "TerminatorKind::Assert", - TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop", - TerminatorKind::Yield { .. } => "TerminatorKind::Yield", - TerminatorKind::FalseEdges { .. } => "TerminatorKind::FalseEdges", - TerminatorKind::FalseUnwind { .. } => "TerminatorKind::FalseUnwind", - }, kind); - self.super_terminator_kind(block, kind, location); - } - - fn visit_assert_message(&mut self, msg: &AssertMessage<'tcx>, location: Location) { - self.record("AssertMessage", msg); - self.record(match *msg { - EvalErrorKind::BoundsCheck { .. } => "AssertMessage::BoundsCheck", - EvalErrorKind::Overflow(..) => "AssertMessage::Overflow", - EvalErrorKind::OverflowNeg => "AssertMessage::OverflowNeg", - EvalErrorKind::DivisionByZero => "AssertMessage::DivisionByZero", - EvalErrorKind::RemainderByZero => "AssertMessage::RemainderByZero", - EvalErrorKind::GeneratorResumedAfterReturn => { - "AssertMessage::GeneratorResumedAfterReturn" - } - EvalErrorKind::GeneratorResumedAfterPanic => { - "AssertMessage::GeneratorResumedAfterPanic" - } - _ => bug!(), - }, msg); - self.super_assert_message(msg, location); - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - self.record("Rvalue", rvalue); - let rvalue_kind = match *rvalue { - Rvalue::Use(..) => "Rvalue::Use", - Rvalue::Repeat(..) => "Rvalue::Repeat", - Rvalue::Ref(..) => "Rvalue::Ref", - Rvalue::Len(..) => "Rvalue::Len", - Rvalue::Cast(..) => "Rvalue::Cast", - Rvalue::BinaryOp(..) => "Rvalue::BinaryOp", - Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp", - Rvalue::UnaryOp(..) => "Rvalue::UnaryOp", - Rvalue::Discriminant(..) => "Rvalue::Discriminant", - Rvalue::NullaryOp(..) => "Rvalue::NullaryOp", - Rvalue::Aggregate(ref kind, ref _operands) => { - // AggregateKind is not distinguished by visit API, so - // record it. (`super_rvalue` handles `_operands`.) - self.record(match **kind { - AggregateKind::Array(_) => "AggregateKind::Array", - AggregateKind::Tuple => "AggregateKind::Tuple", - AggregateKind::Adt(..) => "AggregateKind::Adt", - AggregateKind::Closure(..) => "AggregateKind::Closure", - AggregateKind::Generator(..) => "AggregateKind::Generator", - }, kind); - - "Rvalue::Aggregate" - } - }; - self.record(rvalue_kind, rvalue); - self.super_rvalue(rvalue, location); - } - - fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - self.record("Operand", operand); - self.record(match *operand { - Operand::Copy(..) => "Operand::Copy", - Operand::Move(..) => "Operand::Move", - Operand::Constant(..) => "Operand::Constant", - }, operand); - self.super_operand(operand, location); - } - - fn visit_place(&mut self, - place: &Place<'tcx>, - context: mir_visit::PlaceContext<'tcx>, - location: Location) { - self.record("Place", place); - self.record(match *place { - Place::Local(..) => "Place::Local", - Place::Static(..) => "Place::Static", - Place::Promoted(..) => "Place::Promoted", - Place::Projection(..) => "Place::Projection", - }, place); - self.super_place(place, context, location); - } - - fn visit_projection(&mut self, - place: &PlaceProjection<'tcx>, - context: mir_visit::PlaceContext<'tcx>, - location: Location) { - self.record("PlaceProjection", place); - self.super_projection(place, context, location); - } - - fn visit_projection_elem(&mut self, - place: &PlaceElem<'tcx>, - location: Location) { - self.record("PlaceElem", place); - self.record(match *place { - ProjectionElem::Deref => "PlaceElem::Deref", - ProjectionElem::Subslice { .. } => "PlaceElem::Subslice", - ProjectionElem::Field(..) => "PlaceElem::Field", - ProjectionElem::Index(..) => "PlaceElem::Index", - ProjectionElem::ConstantIndex { .. } => "PlaceElem::ConstantIndex", - ProjectionElem::Downcast(..) => "PlaceElem::Downcast", - }, place); - self.super_projection_elem(place, location); - } - - fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { - self.record("Constant", constant); - self.super_constant(constant, location); - } - - fn visit_source_info(&mut self, source_info: &SourceInfo) { - self.record("SourceInfo", source_info); - self.super_source_info(source_info); - } - - fn visit_closure_substs(&mut self, substs: &ClosureSubsts<'tcx>, _: Location) { - self.record("ClosureSubsts", substs); - self.super_closure_substs(substs); - } - - fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { - self.record("Const", constant); - self.super_const(constant); - } - - fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { - self.record("LocalDecl", local_decl); - self.super_local_decl(local, local_decl); - } - - fn visit_source_scope(&mut self, scope: &SourceScope) { - self.record("VisiblityScope", scope); - self.super_source_scope(scope); - } -} diff --git a/src/librustc_target/spec/apple_ios_base.rs b/src/librustc_target/spec/apple_ios_base.rs index e926e4913d6..ef41ea31e3e 100644 --- a/src/librustc_target/spec/apple_ios_base.rs +++ b/src/librustc_target/spec/apple_ios_base.rs @@ -74,6 +74,8 @@ fn build_pre_link_args(arch: Arch) -> Result<LinkArgs, String> { args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), arch_name.to_string(), + "-isysroot".to_string(), + sdk_root.clone(), "-Wl,-syslibroot".to_string(), sdk_root]); diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs index 07383b3d648..5b6d8abc5ef 100644 --- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs +++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs @@ -49,6 +49,7 @@ pub fn target() -> Result<Target, String> { max_atomic_width: Some(64), panic_strategy: PanicStrategy::Abort, cpu: "x86-64".into(), + features: "+rdrnd,+rdseed".into(), position_independent_executables: true, pre_link_args: iter::once( (LinkerFlavor::Gcc, PRE_LINK_ARGS.iter().cloned().map(String::from).collect()) diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs index df6458a766d..73aa8a10724 100644 --- a/src/librustc_traits/chalk_context/resolvent_ops.rs +++ b/src/librustc_traits/chalk_context/resolvent_ops.rs @@ -17,7 +17,7 @@ use rustc::traits::{ }; use rustc::ty::{self, Ty}; use rustc::ty::subst::Kind; -use rustc::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation}; use syntax_pos::DUMMY_SP; use super::{ChalkInferenceContext, ChalkArenas, ChalkExClause, ConstrainedSubst}; @@ -137,6 +137,10 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> { self.infcx.tcx } + fn trait_object_mode(&self) -> relate::TraitObjectMode { + self.infcx.trait_object_mode() + } + fn tag(&self) -> &'static str { "chalk_context::answer_substitutor" } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index e4ce04916ce..75ae8688834 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Def::Local(id) | Def::Upvar(id, ..) => { Some(self.tcx.hir().span(id)) } - _ => self.tcx.hir().span_if_local(def.def_id()) + _ => def.opt_def_id().and_then(|did| self.tcx.hir().span_if_local(did)), }; if let Some(span) = def_span { let label = match (unit_variant, inner_callee_path) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8901f4b6b29..957c8d9f19f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,7 +95,7 @@ mod op; use astconv::AstConv; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; -use rustc::hir::{self, GenericArg, Node, ItemKind, PatKind}; +use rustc::hir::{self, GenericArg, ItemKind, Node, PatKind}; use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -113,7 +113,8 @@ use rustc::mir::interpret::{ConstValue, GlobalId}; use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs, UserSelfTy, UserSubsts}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; -use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, + RegionKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; use rustc::ty::query::Providers; @@ -3217,8 +3218,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return_expr_ty); } - // A generic function for checking the then and else in an if - // or if-else. + // A generic function for checking the 'then' and 'else' clauses in an 'if' + // or 'if-else' expression. fn check_then_else(&self, cond_expr: &'gcx hir::Expr, then_expr: &'gcx hir::Expr, @@ -3544,7 +3545,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We don't look at stability attributes on // struct-like enums (yet...), but it's definitely not // a bug to have constructed one. - if adt_kind != ty::AdtKind::Enum { + if adt_kind != AdtKind::Enum { tcx.check_stability(v_field.did, Some(expr_id), field.span); } @@ -5156,26 +5157,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }).unwrap_or(false); let mut new_def = def; - let (def_id, ty) = if let Def::SelfCtor(impl_def_id) = def { - let ty = self.impl_self_ty(span, impl_def_id).ty; - - match ty.ty_adt_def() { - Some(adt_def) if adt_def.is_struct() => { - let variant = adt_def.non_enum_variant(); - new_def = Def::StructCtor(variant.did, variant.ctor_kind); - (variant.did, self.tcx.type_of(variant.did)) - } - _ => { - (impl_def_id, self.tcx.types.err) + let (def_id, ty) = match def { + Def::SelfCtor(impl_def_id) => { + let ty = self.impl_self_ty(span, impl_def_id).ty; + let adt_def = ty.ty_adt_def(); + + match adt_def { + Some(adt_def) if adt_def.has_ctor() => { + let variant = adt_def.non_enum_variant(); + new_def = Def::StructCtor(variant.did, variant.ctor_kind); + (variant.did, self.tcx.type_of(variant.did)) + } + _ => { + let mut err = self.tcx.sess.struct_span_err(span, + "the `Self` constructor can only be used with tuple or unit structs"); + if let Some(adt_def) = adt_def { + match adt_def.adt_kind() { + AdtKind::Enum => { + err.note("did you mean to use one of the enum's variants?"); + }, + AdtKind::Struct | + AdtKind::Union => { + err.span_label( + span, + format!("did you mean `Self {{ /* fields */ }}`?"), + ); + } + } + } + err.emit(); + + (impl_def_id, self.tcx.types.err) + } } } - } else { - let def_id = def.def_id(); + _ => { + let def_id = def.def_id(); - // The things we are substituting into the type should not contain - // escaping late-bound regions, and nor should the base type scheme. - let ty = self.tcx.type_of(def_id); - (def_id, ty) + // The things we are substituting into the type should not contain + // escaping late-bound regions, and nor should the base type scheme. + let ty = self.tcx.type_of(def_id); + (def_id, ty) + } }; let substs = AstConv::create_substs_for_generic_args( diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index ec1a43991f6..c273c8f6456 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -12,8 +12,9 @@ use namespace::Namespace; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc::traits::{self, IntercrateMode}; +use rustc::traits::{self, IntercrateMode, FutureCompatOverlapErrorKind}; use rustc::ty::TyCtxt; +use rustc::ty::relate::TraitObjectMode; use lint; @@ -29,9 +30,11 @@ struct InherentOverlapChecker<'a, 'tcx: 'a> { } impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { - fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId, - overlap: traits::OverlapResult, - used_to_be_allowed: bool) { + fn check_for_common_items_in_impls( + &self, impl1: DefId, impl2: DefId, + overlap: traits::OverlapResult, + used_to_be_allowed: Option<FutureCompatOverlapErrorKind>) + { let name_and_namespace = |def_id| { let item = self.tcx.associated_item(def_id); @@ -47,19 +50,28 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for &item2 in &impl_items2[..] { if (name, namespace) == name_and_namespace(item2) { let node_id = self.tcx.hir().as_local_node_id(impl1); - let mut err = if used_to_be_allowed && node_id.is_some() { - self.tcx.struct_span_lint_node( - lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS, - node_id.unwrap(), - self.tcx.span_of_impl(item1).unwrap(), - &format!("duplicate definitions with name `{}` (E0592)", name) - ) - } else { - struct_span_err!(self.tcx.sess, - self.tcx.span_of_impl(item1).unwrap(), - E0592, - "duplicate definitions with name `{}`", - name) + let mut err = match used_to_be_allowed { + Some(kind) if node_id.is_some() => { + let lint = match kind { + FutureCompatOverlapErrorKind::Issue43355 => + lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS, + FutureCompatOverlapErrorKind::Issue33140 => + lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS, + }; + self.tcx.struct_span_lint_node( + lint, + node_id.unwrap(), + self.tcx.span_of_impl(item1).unwrap(), + &format!("duplicate definitions with name `{}` (E0592)", name) + ) + } + _ => { + struct_span_err!(self.tcx.sess, + self.tcx.span_of_impl(item1).unwrap(), + E0592, + "duplicate definitions with name `{}`", + name) + } }; err.span_label(self.tcx.span_of_impl(item1).unwrap(), @@ -82,38 +94,73 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { + // First, check if the impl was forbidden under the + // old rules. In that case, just have an error. let used_to_be_allowed = traits::overlapping_impls( self.tcx, impl1_def_id, impl2_def_id, IntercrateMode::Issue43355, + TraitObjectMode::NoSquash, |overlap| { self.check_for_common_items_in_impls( impl1_def_id, impl2_def_id, overlap, - false, + None, ); false }, || true, ); - if used_to_be_allowed { - traits::overlapping_impls( - self.tcx, - impl1_def_id, - impl2_def_id, - IntercrateMode::Fixed, - |overlap| self.check_for_common_items_in_impls( + if !used_to_be_allowed { + continue; + } + + // Then, check if the impl was forbidden under only + // #43355. In that case, emit an #43355 error. + let used_to_be_allowed = traits::overlapping_impls( + self.tcx, + impl1_def_id, + impl2_def_id, + IntercrateMode::Fixed, + TraitObjectMode::NoSquash, + |overlap| { + self.check_for_common_items_in_impls( impl1_def_id, impl2_def_id, overlap, - true, - ), - || (), - ); + Some(FutureCompatOverlapErrorKind::Issue43355), + ); + false + }, + || true, + ); + + if !used_to_be_allowed { + continue; } + + // Then, check if the impl was forbidden under + // #33140. In that case, emit a #33140 error. + traits::overlapping_impls( + self.tcx, + impl1_def_id, + impl2_def_id, + IntercrateMode::Fixed, + TraitObjectMode::SquashAutoTraitsIssue33140, + |overlap| { + self.check_for_common_items_in_impls( + impl1_def_id, + impl2_def_id, + overlap, + Some(FutureCompatOverlapErrorKind::Issue33140), + ); + false + }, + || true, + ); } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c9f3aa011a1..46002c089cf 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -868,10 +868,10 @@ themePicker.onblur = handleThemeButtonsBlur; } { - let mut data = static_files::STORAGE_JS.to_owned(); - data.push_str(&format!("var resourcesSuffix = \"{}\";", cx.shared.resource_suffix)); write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)), - &data, + &format!("var resourcesSuffix = \"{}\";{}", + cx.shared.resource_suffix, + static_files::STORAGE_JS), options.enable_minification)?; } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 51714c35d6f..d5b8ecd4807 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -213,9 +213,9 @@ if (!DOMTokenList.prototype.remove) { function expandSection(id) { var elem = document.getElementById(id); if (elem && isHidden(elem)) { - var h3 = elem.parentNode.previousSibling; + var h3 = elem.parentNode.previousElementSibling; if (h3 && h3.tagName !== "H3") { - h3 = h3.previousSibling; // skip div.docblock + h3 = h3.previousElementSibling; // skip div.docblock } if (h3) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index d1336b1e8eb..01d2cbec192 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -305,7 +305,7 @@ nav.sub { overflow-x: auto; } -body:not(.source) .example-wrap > pre { +.rustdoc:not(.source) .example-wrap > pre { margin: 0; } diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index d1c377bf95a..22ac52f8728 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -111,7 +111,7 @@ function switchTheme(styleElem, mainStyleElem, newTheme) { var found = false; if (savedHref.length === 0) { - onEach(document.getElementsByTagName("link"), function(el) { + onEachLazy(document.getElementsByTagName("link"), function(el) { savedHref.push(el.href); }); } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 50acde64cf0..84ce9f6d257 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -395,6 +395,7 @@ pub fn make_test(s: &str, // Now push any outer attributes from the example, assuming they // are intended to be crate attributes. prog.push_str(&crate_attrs); + prog.push_str(&crates); // Uses libsyntax to parse the doctest and find if there's a main fn and the extern // crate already is included. @@ -488,37 +489,78 @@ pub fn make_test(s: &str, prog.push_str("\n}"); } + debug!("final doctest:\n{}", prog); + (prog, line_offset) } // FIXME(aburka): use a real parser to deal with multiline attributes fn partition_source(s: &str) -> (String, String, String) { - let mut after_header = false; + #[derive(Copy, Clone, PartialEq)] + enum PartitionState { + Attrs, + Crates, + Other, + } + let mut state = PartitionState::Attrs; let mut before = String::new(); let mut crates = String::new(); let mut after = String::new(); for line in s.lines() { let trimline = line.trim(); - let header = trimline.chars().all(|c| c.is_whitespace()) || - trimline.starts_with("#![") || - trimline.starts_with("#[macro_use] extern crate") || - trimline.starts_with("extern crate"); - if !header || after_header { - after_header = true; - after.push_str(line); - after.push_str("\n"); - } else { - if trimline.starts_with("#[macro_use] extern crate") - || trimline.starts_with("extern crate") { + + // FIXME(misdreavus): if a doc comment is placed on an extern crate statement, it will be + // shunted into "everything else" + match state { + PartitionState::Attrs => { + state = if trimline.starts_with("#![") || + trimline.chars().all(|c| c.is_whitespace()) || + (trimline.starts_with("//") && !trimline.starts_with("///")) + { + PartitionState::Attrs + } else if trimline.starts_with("extern crate") || + trimline.starts_with("#[macro_use] extern crate") + { + PartitionState::Crates + } else { + PartitionState::Other + }; + } + PartitionState::Crates => { + state = if trimline.starts_with("extern crate") || + trimline.starts_with("#[macro_use] extern crate") || + trimline.chars().all(|c| c.is_whitespace()) || + (trimline.starts_with("//") && !trimline.starts_with("///")) + { + PartitionState::Crates + } else { + PartitionState::Other + }; + } + PartitionState::Other => {} + } + + match state { + PartitionState::Attrs => { + before.push_str(line); + before.push_str("\n"); + } + PartitionState::Crates => { crates.push_str(line); crates.push_str("\n"); } - before.push_str(line); - before.push_str("\n"); + PartitionState::Other => { + after.push_str(line); + after.push_str("\n"); + } } } + debug!("before:\n{}", before); + debug!("crates:\n{}", crates); + debug!("after:\n{}", after); + (before, after, crates) } @@ -1035,8 +1077,8 @@ fn main() { assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] -fn main() { //Ceci n'est pas une `fn main` +fn main() { assert_eq!(2+2, 4); }".to_string(); let output = make_test(input, None, false, &opts); @@ -1083,8 +1125,8 @@ assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] -fn main() { // fn main +fn main() { assert_eq!(2+2, 4); }".to_string(); diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 41e778b6a4c..9cee00b9c76 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -21,6 +21,7 @@ libc = { version = "0.2.44", default-features = false, features = ['rustc-dep-of compiler_builtins = { version = "0.1.1" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } +rustc-demangle = { version = "0.1.10", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = "0.6.1" diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 7d17aaf2f26..d0dd4d4adcb 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -550,7 +550,8 @@ impl f32 { #[inline] #[rustc_deprecated(since = "1.10.0", reason = "you probably meant `(self - other).abs()`: \ - this operation is `(self - other).max(0.0)` (also \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ known as `fdimf` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdimf`, depending on how you wish to handle NaN (please consider \ diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index c800763167f..9e627ec2042 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -491,7 +491,8 @@ impl f64 { #[inline] #[rustc_deprecated(since = "1.10.0", reason = "you probably meant `(self - other).abs()`: \ - this operation is `(self - other).max(0.0)` (also \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ known as `fdim` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdim`, depending on how you wish to handle NaN (please consider \ diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index edcfdd9e534..35ae4939249 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1729,7 +1729,7 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// limited to just these cases: /// /// * `path` does not exist. -/// * A component in path is not a directory. +/// * A non-final component in path is not a directory. /// /// # Examples /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0febbe5694b..ead38f21126 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -339,6 +339,7 @@ pub use core::{unreachable, unimplemented, write, writeln, try}; extern crate alloc as alloc_crate; #[doc(masked)] extern crate libc; +extern crate rustc_demangle; // We always need an unwinder currently for backtraces #[doc(masked)] diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs index 95faf3a5dd6..05f30f2881a 100644 --- a/src/libstd/os/raw/mod.rs +++ b/src/libstd/os/raw/mod.rs @@ -27,6 +27,10 @@ all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "freebsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64")), all(target_os = "netbsd", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")), @@ -42,6 +46,10 @@ all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "freebsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64")), all(target_os = "netbsd", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")), diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 77371782977..e44113f76f4 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -14,11 +14,12 @@ use env; use io::prelude::*; use io; +use path::{self, Path}; +use ptr; +use rustc_demangle::demangle; use str; use sync::atomic::{self, Ordering}; -use path::{self, Path}; use sys::mutex::Mutex; -use ptr; pub use sys::backtrace::{ unwind_backtrace, @@ -191,7 +192,14 @@ fn output(w: &mut dyn Write, idx: usize, frame: Frame, PrintFormat::Short => write!(w, " {:2}: ", idx)?, } match s { - Some(string) => demangle(w, string, format)?, + Some(string) => { + let symbol = demangle(string); + match format { + PrintFormat::Full => write!(w, "{}", symbol)?, + // strip the trailing hash if short mode + PrintFormat::Short => write!(w, "{:#}", symbol)?, + } + } None => w.write_all(b"<unknown>")?, } w.write_all(b"\n") @@ -235,228 +243,3 @@ fn output_fileline(w: &mut dyn Write, w.write_all(b"\n") } - -// All rust symbols are in theory lists of "::"-separated identifiers. Some -// assemblers, however, can't handle these characters in symbol names. To get -// around this, we use C++-style mangling. The mangling method is: -// -// 1. Prefix the symbol with "_ZN" -// 2. For each element of the path, emit the length plus the element -// 3. End the path with "E" -// -// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar". -// -// We're the ones printing our backtraces, so we can't rely on anything else to -// demangle our symbols. It's *much* nicer to look at demangled symbols, so -// this function is implemented to give us nice pretty output. -// -// Note that this demangler isn't quite as fancy as it could be. We have lots -// of other information in our symbols like hashes, version, type information, -// etc. Additionally, this doesn't handle glue symbols at all. -pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> { - // During ThinLTO LLVM may import and rename internal symbols, so strip out - // those endings first as they're one of the last manglings applied to - // symbol names. - let llvm = ".llvm."; - if let Some(i) = s.find(llvm) { - let candidate = &s[i + llvm.len()..]; - let all_hex = candidate.chars().all(|c| { - match c { - 'A' ..= 'F' | '0' ..= '9' => true, - _ => false, - } - }); - - if all_hex { - s = &s[..i]; - } - } - - // Validate the symbol. If it doesn't look like anything we're - // expecting, we just print it literally. Note that we must handle non-rust - // symbols because we could have any function in the backtrace. - let mut valid = true; - let mut inner = s; - if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") { - inner = &s[3 .. s.len() - 1]; - // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too. - } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") { - inner = &s[2 .. s.len() - 1]; - } else { - valid = false; - } - - if valid { - let mut chars = inner.chars(); - while valid { - let mut i = 0; - for c in chars.by_ref() { - if c.is_numeric() { - i = i * 10 + c as usize - '0' as usize; - } else { - break - } - } - if i == 0 { - valid = chars.next().is_none(); - break - } else if chars.by_ref().take(i - 1).count() != i - 1 { - valid = false; - } - } - } - - // Alright, let's do this. - if !valid { - writer.write_all(s.as_bytes())?; - } else { - // remove the `::hfc2edb670e5eda97` part at the end of the symbol. - if format == PrintFormat::Short { - // The symbol in still mangled. - let mut split = inner.rsplitn(2, "17h"); - match (split.next(), split.next()) { - (Some(addr), rest) => { - if addr.len() == 16 && - addr.chars().all(|c| c.is_digit(16)) - { - inner = rest.unwrap_or(""); - } - } - _ => (), - } - } - - let mut first = true; - while !inner.is_empty() { - if !first { - writer.write_all(b"::")?; - } else { - first = false; - } - let mut rest = inner; - while rest.chars().next().unwrap().is_numeric() { - rest = &rest[1..]; - } - let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap(); - inner = &rest[i..]; - rest = &rest[..i]; - if rest.starts_with("_$") { - rest = &rest[1..]; - } - while !rest.is_empty() { - if rest.starts_with(".") { - if let Some('.') = rest[1..].chars().next() { - writer.write_all(b"::")?; - rest = &rest[2..]; - } else { - writer.write_all(b".")?; - rest = &rest[1..]; - } - } else if rest.starts_with("$") { - macro_rules! demangle { - ($($pat:expr => $demangled:expr),*) => ({ - $(if rest.starts_with($pat) { - writer.write_all($demangled)?; - rest = &rest[$pat.len()..]; - } else)* - { - writer.write_all(rest.as_bytes())?; - break; - } - - }) - } - - // see src/librustc/back/link.rs for these mappings - demangle! ( - "$SP$" => b"@", - "$BP$" => b"*", - "$RF$" => b"&", - "$LT$" => b"<", - "$GT$" => b">", - "$LP$" => b"(", - "$RP$" => b")", - "$C$" => b",", - - // in theory we can demangle any Unicode code point, but - // for simplicity we just catch the common ones. - "$u7e$" => b"~", - "$u20$" => b" ", - "$u27$" => b"'", - "$u5b$" => b"[", - "$u5d$" => b"]", - "$u7b$" => b"{", - "$u7d$" => b"}", - "$u3b$" => b";", - "$u2b$" => b"+", - "$u22$" => b"\"" - ) - } else { - let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') { - None => rest.len(), - Some((i, _)) => i, - }; - writer.write_all(rest[..idx].as_bytes())?; - rest = &rest[idx..]; - } - } - } - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use sys_common; - macro_rules! t { ($a:expr, $b:expr) => ({ - let mut m = Vec::new(); - sys_common::backtrace::demangle(&mut m, - $a, - super::PrintFormat::Full).unwrap(); - assert_eq!(String::from_utf8(m).unwrap(), $b); - }) } - - #[test] - fn demangle() { - t!("test", "test"); - t!("_ZN4testE", "test"); - t!("_ZN4test", "_ZN4test"); - t!("_ZN4test1a2bcE", "test::a::bc"); - } - - #[test] - fn demangle_dollars() { - t!("_ZN4$RP$E", ")"); - t!("_ZN8$RF$testE", "&test"); - t!("_ZN8$BP$test4foobE", "*test::foob"); - t!("_ZN9$u20$test4foobE", " test::foob"); - t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"); - } - - #[test] - fn demangle_many_dollars() { - t!("_ZN13test$u20$test4foobE", "test test::foob"); - t!("_ZN12test$BP$test4foobE", "test*test::foob"); - } - - #[test] - fn demangle_windows() { - t!("ZN4testE", "test"); - t!("ZN13test$u20$test4foobE", "test test::foob"); - t!("ZN12test$RF$test4foobE", "test&test::foob"); - } - - #[test] - fn demangle_elements_beginning_with_underscore() { - t!("_ZN13_$LT$test$GT$E", "<test>"); - t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"); - t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"); - } - - #[test] - fn demangle_trait_impls() { - t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE", - "<Test + 'static as foo::Bar<Test>>::bar"); - } -} diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 7723c15a266..73cbe49f43b 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -483,7 +483,7 @@ impl MetaItem { last_pos = segment.ident.span.hi(); } idents.push(self.node.tokens(self.span)); - TokenStream::concat(idents) + TokenStream::new(idents) } fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem> @@ -539,7 +539,7 @@ impl MetaItemKind { match *self { MetaItemKind::Word => TokenStream::empty(), MetaItemKind::NameValue(ref lit) => { - TokenStream::concat(vec![TokenTree::Token(span, Token::Eq).into(), lit.tokens()]) + TokenStream::new(vec![TokenTree::Token(span, Token::Eq).into(), lit.tokens()]) } MetaItemKind::List(ref list) => { let mut tokens = Vec::new(); @@ -552,7 +552,7 @@ impl MetaItemKind { TokenTree::Delimited( DelimSpan::from_single(span), token::Paren, - TokenStream::concat(tokens).into(), + TokenStream::new(tokens).into(), ).into() } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f4e9a7e4093..03c7aa96824 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{self, Block, Ident, NodeId, PatKind, Path}; +use ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path}; use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; use source_map::{ExpnInfo, MacroBang, MacroAttribute, dummy_spanned, respan}; @@ -1535,21 +1535,65 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let item = attr::mk_list_item(DUMMY_SP, include_ident, include_info); items.push(dummy_spanned(ast::NestedMetaItemKind::MetaItem(item))); } - Err(ref e) if e.kind() == ErrorKind::InvalidData => { - self.cx.span_err( - at.span, - &format!("{} wasn't a utf-8 file", filename.display()), - ); - } Err(e) => { - self.cx.span_err( - at.span, - &format!("couldn't read {}: {}", filename.display(), e), - ); + let lit = it + .meta_item() + .and_then(|item| item.name_value_literal()) + .unwrap(); + + if e.kind() == ErrorKind::InvalidData { + self.cx + .struct_span_err( + lit.span, + &format!("{} wasn't a utf-8 file", filename.display()), + ) + .span_label(lit.span, "contains invalid utf-8") + .emit(); + } else { + let mut err = self.cx.struct_span_err( + lit.span, + &format!("couldn't read {}: {}", filename.display(), e), + ); + err.span_label(lit.span, "couldn't read file"); + + if e.kind() == ErrorKind::NotFound { + err.help("external doc paths are relative to the crate root"); + } + + err.emit(); + } } } } else { - items.push(noop_fold_meta_list_item(it, self)); + let mut err = self.cx.struct_span_err( + it.span, + &format!("expected path to external documentation"), + ); + + // Check if the user erroneously used `doc(include(...))` syntax. + let literal = it.meta_item_list().and_then(|list| { + if list.len() == 1 { + list[0].literal().map(|literal| &literal.node) + } else { + None + } + }); + + let (path, applicability) = match &literal { + Some(LitKind::Str(path, ..)) => { + (path.to_string(), Applicability::MachineApplicable) + } + _ => (String::from("<path>"), Applicability::HasPlaceholders), + }; + + err.span_suggestion_with_applicability( + it.span, + "provide a file path with `=`", + format!("include = \"{}\"", path), + applicability, + ); + + err.emit(); } } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index c3497a17806..5820b49ab62 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -247,7 +247,7 @@ pub mod rt { let delim_span = DelimSpan::from_single(self.span); r.push(TokenTree::Delimited( - delim_span, token::Bracket, TokenStream::concat(inner).into() + delim_span, token::Bracket, TokenStream::new(inner).into() )); r } diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index a76779ffebd..a63abd40495 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -103,12 +103,12 @@ pub fn transcribe(cx: &ExtCtxt, } Frame::Delimited { forest, span, .. } => { if result_stack.is_empty() { - return TokenStream::concat(result); + return TokenStream::new(result); } let tree = TokenTree::Delimited( span, forest.delim, - TokenStream::concat(result).into(), + TokenStream::new(result).into(), ); result = result_stack.pop().unwrap(); result.push(tree.into()); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1a4de59cce6..4eca0c942f3 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -400,9 +400,6 @@ declare_features! ( // Allows `#[repr(packed)]` attribute on structs. (active, repr_packed, "1.26.0", Some(33158), None), - // Allows `use path as _;` and `extern crate c as _;`. - (active, underscore_imports, "1.26.0", Some(48216), None), - // Allows macro invocations in `extern {}` blocks. (active, macros_in_extern, "1.27.0", Some(49476), None), @@ -694,6 +691,8 @@ declare_features! ( (accepted, self_struct_ctor, "1.32.0", Some(51994), None), // `Self` in type definitions (RFC 2300) (accepted, self_in_typedefs, "1.32.0", Some(49303), None), + // `use path as _;` and `extern crate c as _;` + (accepted, underscore_imports, "1.33.0", Some(48216), None), ); // If you change this, please modify `src/doc/unstable-book` as well. You must @@ -1547,26 +1546,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: NodeId, _nested: bool) { - if let ast::UseTreeKind::Simple(Some(ident), ..) = use_tree.kind { - if ident.name == "_" { - gate_feature_post!(&self, underscore_imports, use_tree.span, - "renaming imports with `_` is unstable"); - } - } - - visit::walk_use_tree(self, use_tree, id); - } - fn visit_item(&mut self, i: &'a ast::Item) { match i.node { - ast::ItemKind::ExternCrate(_) => { - if i.ident.name == "_" { - gate_feature_post!(&self, underscore_imports, i.span, - "renaming extern crates with `_` is unstable"); - } - } - ast::ItemKind::Static(..) | ast::ItemKind::Const(_,_) => { if i.ident.name == "_" { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 0c24c20554a..1fa11a4d6c8 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -145,12 +145,6 @@ pub mod util { #[cfg(test)] pub mod parser_testing; pub mod move_map; - - mod rc_slice; - pub use self::rc_slice::RcSlice; - - mod rc_vec; - pub use self::rc_vec::RcVec; } pub mod json; diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 4ff6048e821..1bd0656846b 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -170,7 +170,7 @@ impl<'a> Parser<'a> { token::CloseDelim(_) | token::Eof => self.unexpected()?, _ => self.parse_token_tree(), }; - TokenStream::concat(vec![eq.into(), tree.into()]) + TokenStream::new(vec![eq.into(), tree.into()]) } else { TokenStream::empty() }; diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 86c87cf898d..0906c25cab3 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -22,7 +22,7 @@ impl<'a> StringReader<'a> { tts.push(self.parse_token_tree()?); } - Ok(TokenStream::concat(tts)) + Ok(TokenStream::new(tts)) } // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`. @@ -30,14 +30,14 @@ impl<'a> StringReader<'a> { let mut tts = vec![]; loop { if let token::CloseDelim(..) = self.token { - return TokenStream::concat(tts); + return TokenStream::new(tts); } match self.parse_token_tree() { Ok(tree) => tts.push(tree), Err(mut e) => { e.emit(); - return TokenStream::concat(tts); + return TokenStream::new(tts); } } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 10c451e1f81..e3cccacb3c3 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -863,13 +863,13 @@ mod tests { with_globals(|| { let tts = string_to_stream("fn a (b : i32) { b; }".to_string()); - let expected = TokenStream::concat(vec![ + let expected = TokenStream::new(vec![ TokenTree::Token(sp(0, 2), token::Ident(Ident::from_str("fn"), false)).into(), TokenTree::Token(sp(3, 4), token::Ident(Ident::from_str("a"), false)).into(), TokenTree::Delimited( DelimSpan::from_pair(sp(5, 6), sp(13, 14)), token::DelimToken::Paren, - TokenStream::concat(vec![ + TokenStream::new(vec![ TokenTree::Token(sp(6, 7), token::Ident(Ident::from_str("b"), false)).into(), TokenTree::Token(sp(8, 9), token::Colon).into(), @@ -880,7 +880,7 @@ mod tests { TokenTree::Delimited( DelimSpan::from_pair(sp(15, 16), sp(20, 21)), token::DelimToken::Brace, - TokenStream::concat(vec![ + TokenStream::new(vec![ TokenTree::Token(sp(17, 18), token::Ident(Ident::from_str("b"), false)).into(), TokenTree::Token(sp(18, 19), token::Semi).into(), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a4326d9ba47..a672a08a15a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2939,7 +2939,7 @@ impl<'a> Parser<'a> { _ => result.push(self.parse_token_tree().into()), } } - TokenStream::concat(result) + TokenStream::new(result) } /// Parse a prefix-unary-operator expr @@ -4635,7 +4635,7 @@ impl<'a> Parser<'a> { self.unexpected()?; unreachable!() }; - TokenStream::concat(vec![ + TokenStream::new(vec![ args.into(), TokenTree::Token(token_lo.to(self.prev_span), token::FatArrow).into(), body.into(), diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 90191c54126..c11ef33f931 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -28,8 +28,8 @@ use ext::tt::{macro_parser, quoted}; use parse::Directory; use parse::token::{self, DelimToken, Token}; use print::pprust; +use rustc_data_structures::sync::Lrc; use serialize::{Decoder, Decodable, Encoder, Encodable}; -use util::RcVec; use std::borrow::Cow; use std::{fmt, iter, mem}; @@ -123,7 +123,7 @@ impl TokenTree { } pub fn joint(self) -> TokenStream { - TokenStream { kind: TokenStreamKind::JointTree(self) } + TokenStream::JointTree(self) } /// Returns the opening delimiter as a token tree. @@ -154,65 +154,57 @@ impl TokenTree { /// instead of a representation of the abstract syntax tree. /// Today's `TokenTree`s can still contain AST via `Token::Interpolated` for back-compat. #[derive(Clone, Debug)] -pub struct TokenStream { - kind: TokenStreamKind, +pub enum TokenStream { + Empty, + Tree(TokenTree), + JointTree(TokenTree), + Stream(Lrc<Vec<TokenStream>>), } // `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::<TokenStream>() == 40); +static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::<TokenStream>() == 32); impl TokenStream { /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream` /// separating the two arguments with a comma for diagnostic suggestions. pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> { // Used to suggest if a user writes `foo!(a b);` - if let TokenStreamKind::Stream(ref slice) = self.kind { + if let TokenStream::Stream(ref stream) = self { let mut suggestion = None; - let mut iter = slice.iter().enumerate().peekable(); + let mut iter = stream.iter().enumerate().peekable(); while let Some((pos, ts)) = iter.next() { if let Some((_, next)) = iter.peek() { - let sp = match (&ts.kind, &next.kind) { - (TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma)), _) | - (_, TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma))) => { + let sp = match (&ts, &next) { + (TokenStream::Tree(TokenTree::Token(_, token::Token::Comma)), _) | + (_, TokenStream::Tree(TokenTree::Token(_, token::Token::Comma))) => { continue; } - (TokenStreamKind::Tree(TokenTree::Token(sp, _)), _) => *sp, - (TokenStreamKind::Tree(TokenTree::Delimited(sp, ..)), _) => sp.entire(), + (TokenStream::Tree(TokenTree::Token(sp, _)), _) => *sp, + (TokenStream::Tree(TokenTree::Delimited(sp, ..)), _) => sp.entire(), _ => continue, }; let sp = sp.shrink_to_hi(); - let comma = TokenStream { - kind: TokenStreamKind::Tree(TokenTree::Token(sp, token::Comma)), - }; + let comma = TokenStream::Tree(TokenTree::Token(sp, token::Comma)); suggestion = Some((pos, comma, sp)); } } if let Some((pos, comma, sp)) = suggestion { - let mut new_slice = vec![]; - let parts = slice.split_at(pos + 1); - new_slice.extend_from_slice(parts.0); - new_slice.push(comma); - new_slice.extend_from_slice(parts.1); - let slice = RcVec::new(new_slice); - return Some((TokenStream { kind: TokenStreamKind::Stream(slice) }, sp)); + let mut new_stream = vec![]; + let parts = stream.split_at(pos + 1); + new_stream.extend_from_slice(parts.0); + new_stream.push(comma); + new_stream.extend_from_slice(parts.1); + return Some((TokenStream::new(new_stream), sp)); } } None } } -#[derive(Clone, Debug)] -enum TokenStreamKind { - Empty, - Tree(TokenTree), - JointTree(TokenTree), - Stream(RcVec<TokenStream>), -} - impl From<TokenTree> for TokenStream { fn from(tt: TokenTree) -> TokenStream { - TokenStream { kind: TokenStreamKind::Tree(tt) } + TokenStream::Tree(tt) } } @@ -224,29 +216,29 @@ impl From<Token> for TokenStream { impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream { fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { - TokenStream::concat(iter.into_iter().map(Into::into).collect::<Vec<_>>()) + TokenStream::new(iter.into_iter().map(Into::into).collect::<Vec<_>>()) } } impl Extend<TokenStream> for TokenStream { fn extend<I: IntoIterator<Item = TokenStream>>(&mut self, iter: I) { let iter = iter.into_iter(); - let kind = mem::replace(&mut self.kind, TokenStreamKind::Empty); + let this = mem::replace(self, TokenStream::Empty); // Vector of token streams originally in self. - let tts: Vec<TokenStream> = match kind { - TokenStreamKind::Empty => { + let tts: Vec<TokenStream> = match this { + TokenStream::Empty => { let mut vec = Vec::new(); vec.reserve(iter.size_hint().0); vec } - TokenStreamKind::Tree(_) | TokenStreamKind::JointTree(_) => { + TokenStream::Tree(_) | TokenStream::JointTree(_) => { let mut vec = Vec::new(); vec.reserve(1 + iter.size_hint().0); - vec.push(TokenStream { kind }); + vec.push(this); vec } - TokenStreamKind::Stream(rc_vec) => match RcVec::try_unwrap(rc_vec) { + TokenStream::Stream(rc_vec) => match Lrc::try_unwrap(rc_vec) { Ok(mut vec) => { // Extend in place using the existing capacity if possible. // This is the fast path for libraries like `quote` that @@ -273,12 +265,7 @@ impl Extend<TokenStream> for TokenStream { // Build the resulting token stream. If it contains more than one token, // preserve capacity in the vector in anticipation of the caller // performing additional calls to extend. - let mut tts = builder.0; - *self = match tts.len() { - 0 => TokenStream::empty(), - 1 => tts.pop().unwrap(), - _ => TokenStream::concat_rc_vec(RcVec::new_preserving_capacity(tts)), - }; + *self = TokenStream::new(builder.0); } } @@ -292,7 +279,7 @@ impl PartialEq<TokenStream> for TokenStream { impl TokenStream { pub fn len(&self) -> usize { - if let TokenStreamKind::Stream(ref slice) = self.kind { + if let TokenStream::Stream(ref slice) = self { slice.len() } else { 0 @@ -300,28 +287,24 @@ impl TokenStream { } pub fn empty() -> TokenStream { - TokenStream { kind: TokenStreamKind::Empty } + TokenStream::Empty } pub fn is_empty(&self) -> bool { - match self.kind { - TokenStreamKind::Empty => true, + match self { + TokenStream::Empty => true, _ => false, } } - pub fn concat(mut streams: Vec<TokenStream>) -> TokenStream { + pub fn new(mut streams: Vec<TokenStream>) -> TokenStream { match streams.len() { 0 => TokenStream::empty(), 1 => streams.pop().unwrap(), - _ => TokenStream::concat_rc_vec(RcVec::new(streams)), + _ => TokenStream::Stream(Lrc::new(streams)), } } - fn concat_rc_vec(streams: RcVec<TokenStream>) -> TokenStream { - TokenStream { kind: TokenStreamKind::Stream(streams) } - } - pub fn trees(&self) -> Cursor { self.clone().into_trees() } @@ -383,9 +366,9 @@ impl TokenStream { /// Precondition: `self` consists of a single token tree. /// Returns true if the token tree is a joint operation w.r.t. `proc_macro::TokenNode`. pub fn as_tree(self) -> (TokenTree, bool /* joint? */) { - match self.kind { - TokenStreamKind::Tree(tree) => (tree, false), - TokenStreamKind::JointTree(tree) => (tree, true), + match self { + TokenStream::Tree(tree) => (tree, false), + TokenStream::JointTree(tree) => (tree, true), _ => unreachable!(), } } @@ -395,43 +378,43 @@ impl TokenStream { let mut result = Vec::new(); let mut i = 0; while let Some(stream) = trees.next_as_stream() { - result.push(match stream.kind { - TokenStreamKind::Tree(tree) => f(i, tree).into(), - TokenStreamKind::JointTree(tree) => f(i, tree).joint(), + result.push(match stream { + TokenStream::Tree(tree) => f(i, tree).into(), + TokenStream::JointTree(tree) => f(i, tree).joint(), _ => unreachable!() }); i += 1; } - TokenStream::concat(result) + TokenStream::new(result) } pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream { let mut trees = self.into_trees(); let mut result = Vec::new(); while let Some(stream) = trees.next_as_stream() { - result.push(match stream.kind { - TokenStreamKind::Tree(tree) => f(tree).into(), - TokenStreamKind::JointTree(tree) => f(tree).joint(), + result.push(match stream { + TokenStream::Tree(tree) => f(tree).into(), + TokenStream::JointTree(tree) => f(tree).joint(), _ => unreachable!() }); } - TokenStream::concat(result) + TokenStream::new(result) } fn first_tree_and_joint(&self) -> Option<(TokenTree, bool)> { - match self.kind { - TokenStreamKind::Empty => None, - TokenStreamKind::Tree(ref tree) => Some((tree.clone(), false)), - TokenStreamKind::JointTree(ref tree) => Some((tree.clone(), true)), - TokenStreamKind::Stream(ref stream) => stream.first().unwrap().first_tree_and_joint(), + match self { + TokenStream::Empty => None, + TokenStream::Tree(ref tree) => Some((tree.clone(), false)), + TokenStream::JointTree(ref tree) => Some((tree.clone(), true)), + TokenStream::Stream(ref stream) => stream.first().unwrap().first_tree_and_joint(), } } fn last_tree_if_joint(&self) -> Option<TokenTree> { - match self.kind { - TokenStreamKind::Empty | TokenStreamKind::Tree(..) => None, - TokenStreamKind::JointTree(ref tree) => Some(tree.clone()), - TokenStreamKind::Stream(ref stream) => stream.last().unwrap().last_tree_if_joint(), + match self { + TokenStream::Empty | TokenStream::Tree(..) => None, + TokenStream::JointTree(ref tree) => Some(tree.clone()), + TokenStream::Stream(ref stream) => stream.last().unwrap().last_tree_if_joint(), } } } @@ -474,28 +457,28 @@ impl TokenStreamBuilder { } pub fn build(self) -> TokenStream { - TokenStream::concat(self.0) + TokenStream::new(self.0) } fn push_all_but_last_tree(&mut self, stream: &TokenStream) { - if let TokenStreamKind::Stream(ref streams) = stream.kind { + if let TokenStream::Stream(ref streams) = stream { let len = streams.len(); match len { 1 => {} 2 => self.0.push(streams[0].clone().into()), - _ => self.0.push(TokenStream::concat_rc_vec(streams.sub_slice(0 .. len - 1))), + _ => self.0.push(TokenStream::new(streams[0 .. len - 1].to_vec())), } self.push_all_but_last_tree(&streams[len - 1]) } } fn push_all_but_first_tree(&mut self, stream: &TokenStream) { - if let TokenStreamKind::Stream(ref streams) = stream.kind { + if let TokenStream::Stream(ref streams) = stream { let len = streams.len(); match len { 1 => {} 2 => self.0.push(streams[1].clone().into()), - _ => self.0.push(TokenStream::concat_rc_vec(streams.sub_slice(1 .. len))), + _ => self.0.push(TokenStream::new(streams[1 .. len].to_vec())), } self.push_all_but_first_tree(&streams[0]) } @@ -515,13 +498,13 @@ enum CursorKind { #[derive(Clone)] struct StreamCursor { - stream: RcVec<TokenStream>, + stream: Lrc<Vec<TokenStream>>, index: usize, - stack: Vec<(RcVec<TokenStream>, usize)>, + stack: Vec<(Lrc<Vec<TokenStream>>, usize)>, } impl StreamCursor { - fn new(stream: RcVec<TokenStream>) -> Self { + fn new(stream: Lrc<Vec<TokenStream>>) -> Self { StreamCursor { stream: stream, index: 0, stack: Vec::new() } } @@ -530,10 +513,10 @@ impl StreamCursor { if self.index < self.stream.len() { self.index += 1; let next = self.stream[self.index - 1].clone(); - match next.kind { - TokenStreamKind::Tree(..) | TokenStreamKind::JointTree(..) => return Some(next), - TokenStreamKind::Stream(stream) => self.insert(stream), - TokenStreamKind::Empty => {} + match next { + TokenStream::Tree(..) | TokenStream::JointTree(..) => return Some(next), + TokenStream::Stream(stream) => self.insert(stream), + TokenStream::Empty => {} } } else if let Some((stream, index)) = self.stack.pop() { self.stream = stream; @@ -544,7 +527,7 @@ impl StreamCursor { } } - fn insert(&mut self, stream: RcVec<TokenStream>) { + fn insert(&mut self, stream: Lrc<Vec<TokenStream>>) { self.stack.push((mem::replace(&mut self.stream, stream), mem::replace(&mut self.index, 0))); } @@ -554,8 +537,8 @@ impl Iterator for Cursor { type Item = TokenTree; fn next(&mut self) -> Option<TokenTree> { - self.next_as_stream().map(|stream| match stream.kind { - TokenStreamKind::Tree(tree) | TokenStreamKind::JointTree(tree) => tree, + self.next_as_stream().map(|stream| match stream { + TokenStream::Tree(tree) | TokenStream::JointTree(tree) => tree, _ => unreachable!() }) } @@ -563,11 +546,11 @@ impl Iterator for Cursor { impl Cursor { fn new(stream: TokenStream) -> Self { - Cursor(match stream.kind { - TokenStreamKind::Empty => CursorKind::Empty, - TokenStreamKind::Tree(tree) => CursorKind::Tree(tree, false), - TokenStreamKind::JointTree(tree) => CursorKind::JointTree(tree, false), - TokenStreamKind::Stream(stream) => CursorKind::Stream(StreamCursor::new(stream)), + Cursor(match stream { + TokenStream::Empty => CursorKind::Empty, + TokenStream::Tree(tree) => CursorKind::Tree(tree, false), + TokenStream::JointTree(tree) => CursorKind::JointTree(tree, false), + TokenStream::Stream(stream) => CursorKind::Stream(StreamCursor::new(stream)), }) } @@ -590,7 +573,7 @@ impl Cursor { _ if stream.is_empty() => return, CursorKind::Empty => *self = stream.trees(), CursorKind::Tree(_, consumed) | CursorKind::JointTree(_, consumed) => { - *self = TokenStream::concat(vec![self.original_stream(), stream]).trees(); + *self = TokenStream::new(vec![self.original_stream(), stream]).trees(); if consumed { self.next(); } @@ -606,21 +589,21 @@ impl Cursor { CursorKind::Empty => TokenStream::empty(), CursorKind::Tree(ref tree, _) => tree.clone().into(), CursorKind::JointTree(ref tree, _) => tree.clone().joint(), - CursorKind::Stream(ref cursor) => TokenStream::concat_rc_vec({ + CursorKind::Stream(ref cursor) => TokenStream::Stream( cursor.stack.get(0).cloned().map(|(stream, _)| stream) .unwrap_or_else(|| cursor.stream.clone()) - }), + ), } } pub fn look_ahead(&self, n: usize) -> Option<TokenTree> { fn look_ahead(streams: &[TokenStream], mut n: usize) -> Result<TokenTree, usize> { for stream in streams { - n = match stream.kind { - TokenStreamKind::Tree(ref tree) | TokenStreamKind::JointTree(ref tree) + n = match stream { + TokenStream::Tree(ref tree) | TokenStream::JointTree(ref tree) if n == 0 => return Ok(tree.clone()), - TokenStreamKind::Tree(..) | TokenStreamKind::JointTree(..) => n - 1, - TokenStreamKind::Stream(ref stream) => match look_ahead(stream, n) { + TokenStream::Tree(..) | TokenStream::JointTree(..) => n - 1, + TokenStream::Stream(ref stream) => match look_ahead(stream, n) { Ok(tree) => return Ok(tree), Err(n) => n, }, @@ -656,7 +639,7 @@ impl Cursor { /// `ThinTokenStream` is smaller, but needs to allocate to represent a single `TokenTree`. /// We must use `ThinTokenStream` in `TokenTree::Delimited` to avoid infinite size due to recursion. #[derive(Debug, Clone)] -pub struct ThinTokenStream(Option<RcVec<TokenStream>>); +pub struct ThinTokenStream(Option<Lrc<Vec<TokenStream>>>); impl ThinTokenStream { pub fn stream(&self) -> TokenStream { @@ -666,18 +649,18 @@ impl ThinTokenStream { impl From<TokenStream> for ThinTokenStream { fn from(stream: TokenStream) -> ThinTokenStream { - ThinTokenStream(match stream.kind { - TokenStreamKind::Empty => None, - TokenStreamKind::Tree(tree) => Some(RcVec::new(vec![tree.into()])), - TokenStreamKind::JointTree(tree) => Some(RcVec::new(vec![tree.joint()])), - TokenStreamKind::Stream(stream) => Some(stream), + ThinTokenStream(match stream { + TokenStream::Empty => None, + TokenStream::Tree(tree) => Some(Lrc::new(vec![tree.into()])), + TokenStream::JointTree(tree) => Some(Lrc::new(vec![tree.joint()])), + TokenStream::Stream(stream) => Some(stream), }) } } impl From<ThinTokenStream> for TokenStream { fn from(stream: ThinTokenStream) -> TokenStream { - stream.0.map(TokenStream::concat_rc_vec).unwrap_or_else(TokenStream::empty) + stream.0.map(TokenStream::Stream).unwrap_or_else(TokenStream::empty) } } @@ -776,7 +759,7 @@ mod tests { let test_res = string_to_ts("foo::bar::baz"); let test_fst = string_to_ts("foo::bar"); let test_snd = string_to_ts("::baz"); - let eq_res = TokenStream::concat(vec![test_fst, test_snd]); + let eq_res = TokenStream::new(vec![test_fst, test_snd]); assert_eq!(test_res.trees().count(), 5); assert_eq!(eq_res.trees().count(), 5); assert_eq!(test_res.eq_unspanned(&eq_res), true); diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs deleted file mode 100644 index 520b7a48e30..00000000000 --- a/src/libsyntax/util/rc_slice.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::fmt; -use std::ops::{Deref, Range}; -use rustc_data_structures::sync::Lrc; - -use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, - HashStable}; - -#[derive(Clone)] -pub struct RcSlice<T> { - data: Lrc<Box<[T]>>, - offset: u32, - len: u32, -} - -impl<T> RcSlice<T> { - pub fn new(vec: Vec<T>) -> Self { - RcSlice { - offset: 0, - len: vec.len() as u32, - data: Lrc::new(vec.into_boxed_slice()), - } - } - - pub fn sub_slice(&self, range: Range<usize>) -> Self { - RcSlice { - data: self.data.clone(), - offset: self.offset + range.start as u32, - len: (range.end - range.start) as u32, - } - } -} - -impl<T> Deref for RcSlice<T> { - type Target = [T]; - fn deref(&self) -> &[T] { - &self.data[self.offset as usize .. (self.offset + self.len) as usize] - } -} - -impl<T: fmt::Debug> fmt::Debug for RcSlice<T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.deref(), f) - } -} - -impl<CTX, T> HashStable<CTX> for RcSlice<T> - where T: HashStable<CTX> -{ - fn hash_stable<W: StableHasherResult>(&self, - hcx: &mut CTX, - hasher: &mut StableHasher<W>) { - (**self).hash_stable(hcx, hasher); - } -} diff --git a/src/libsyntax/util/rc_vec.rs b/src/libsyntax/util/rc_vec.rs deleted file mode 100644 index 99fbce1ad91..00000000000 --- a/src/libsyntax/util/rc_vec.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::fmt; -use std::ops::{Deref, Range}; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; -use rustc_data_structures::sync::Lrc; - -#[derive(Clone)] -pub struct RcVec<T> { - data: Lrc<Vec<T>>, - offset: u32, - len: u32, -} - -impl<T> RcVec<T> { - pub fn new(mut vec: Vec<T>) -> Self { - // By default, constructing RcVec from Vec gives it just enough capacity - // to hold the initial elements. Callers that anticipate needing to - // extend the vector may prefer RcVec::new_preserving_capacity. - vec.shrink_to_fit(); - Self::new_preserving_capacity(vec) - } - - pub fn new_preserving_capacity(vec: Vec<T>) -> Self { - RcVec { - offset: 0, - len: vec.len() as u32, - data: Lrc::new(vec), - } - } - - pub fn sub_slice(&self, range: Range<usize>) -> Self { - RcVec { - data: self.data.clone(), - offset: self.offset + range.start as u32, - len: (range.end - range.start) as u32, - } - } - - /// If this RcVec has exactly one strong reference, returns ownership of the - /// underlying vector. Otherwise returns self unmodified. - pub fn try_unwrap(self) -> Result<Vec<T>, Self> { - match Lrc::try_unwrap(self.data) { - // If no other RcVec shares ownership of this data. - Ok(mut vec) => { - // Drop any elements after our view of the data. - vec.truncate(self.offset as usize + self.len as usize); - // Drop any elements before our view of the data. Do this after - // the `truncate` so that elements past the end of our view do - // not need to be copied around. - vec.drain(..self.offset as usize); - Ok(vec) - } - - // If the data is shared. - Err(data) => Err(RcVec { data, ..self }), - } - } -} - -impl<T> Deref for RcVec<T> { - type Target = [T]; - fn deref(&self) -> &[T] { - &self.data[self.offset as usize..(self.offset + self.len) as usize] - } -} - -impl<T: fmt::Debug> fmt::Debug for RcVec<T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.deref(), f) - } -} - -impl<CTX, T> HashStable<CTX> for RcVec<T> -where - T: HashStable<CTX>, -{ - fn hash_stable<W: StableHasherResult>(&self, hcx: &mut CTX, hasher: &mut StableHasher<W>) { - (**self).hash_stable(hcx, hasher); - } -} diff --git a/src/llvm b/src/llvm -Subproject a784eca10d2c1f09e65d67e16eca266485e1eac +Subproject 95185c8c801c765ac1072392d081d265af9fb31 diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 1355c0377ce..2f8dc0d466f 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -216,16 +216,11 @@ LLVMRustWriteArchive(char *Dst, size_t NumMembers, Members.push_back(std::move(*MOrErr)); } } + auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false); -#if LLVM_VERSION_GE(6, 0) if (!Result) return LLVMRustResult::Success; LLVMRustSetLastError(toString(std::move(Result)).c_str()); -#else - if (!Result.second) - return LLVMRustResult::Success; - LLVMRustSetLastError(Result.second.message().c_str()); -#endif return LLVMRustResult::Failure; } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index aa420bf6100..4d95368c00f 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -17,21 +17,15 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/AssemblyAnnotationWriter.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" - -#if LLVM_VERSION_GE(6, 0) -#include "llvm/CodeGen/TargetSubtargetInfo.h" -#include "llvm/IR/IntrinsicInst.h" -#else -#include "llvm/Target/TargetSubtargetInfo.h" -#endif - #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/IPO/FunctionImport.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" @@ -198,13 +192,9 @@ GEN_SUBTARGETS extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, const char *Feature) { -#if LLVM_VERSION_GE(6, 0) TargetMachine *Target = unwrap(TM); const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo(); return MCInfo->checkFeatures(std::string("+") + Feature); -#else - return false; -#endif } enum class LLVMRustCodeModel { @@ -392,13 +382,9 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.ThreadModel = ThreadModel::Single; } -#if LLVM_VERSION_GE(6, 0) Options.EmitStackSizeSection = EmitStackSizeSection; Optional<CodeModel::Model> CM; -#else - CodeModel::Model CM = CodeModel::Model::Default; -#endif if (RustCM != LLVMRustCodeModel::None) CM = fromRust(RustCM); TargetMachine *TM = TheTarget->createTargetMachine( diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index b9a0b435d3e..86c5dfcfb98 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -297,11 +297,7 @@ extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, // enable fpmath flag UnsafeAlgebra extern "C" void LLVMRustSetHasUnsafeAlgebra(LLVMValueRef V) { if (auto I = dyn_cast<Instruction>(unwrap<Value>(V))) { -#if LLVM_VERSION_GE(6, 0) I->setFast(true); -#else - I->setHasUnsafeAlgebra(true); -#endif } } @@ -1437,7 +1433,6 @@ LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) { return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN)); } -#if LLVM_VERSION_GE(6, 0) extern "C" LLVMValueRef LLVMRustBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { return wrap(unwrap(B)->CreateMinNum(unwrap(LHS),unwrap(RHS))); @@ -1446,13 +1441,3 @@ extern "C" LLVMValueRef LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS) { return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS),unwrap(RHS))); } -#else -extern "C" LLVMValueRef -LLVMRustBuildMinNum(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) { - return nullptr; -} -extern "C" LLVMValueRef -LLVMRustBuildMaxNum(LLVMBuilderRef, LLVMValueRef, LLVMValueRef) { - return nullptr; -} -#endif diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index 9cf17c45e87..a268838de45 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2018-11-28 +2018-12-13 diff --git a/src/stdsimd b/src/stdsimd -Subproject 5e628c5120c619a22799187371f057ec41e06f8 +Subproject 3c0503db8439928e42c1175f0009c506fc874ae diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index 5061d9a915e..52bdb1b103a 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -10,7 +10,6 @@ // compile-flags: -C no-prepopulate-passes // ignore-tidy-linelength -// min-llvm-version 6.0 #![crate_type = "lib"] #![feature(custom_attribute)] diff --git a/src/test/codegen/issue-44056-macos-tls-align.rs b/src/test/codegen/issue-44056-macos-tls-align.rs index b146e106aa1..ebd436cc647 100644 --- a/src/test/codegen/issue-44056-macos-tls-align.rs +++ b/src/test/codegen/issue-44056-macos-tls-align.rs @@ -11,7 +11,6 @@ // ignore-tidy-linelength // only-macos // no-system-llvm -// min-llvm-version 6.0 // compile-flags: -O #![crate_type = "rlib"] diff --git a/src/test/codegen/issue-45222.rs b/src/test/codegen/issue-45222.rs index 3544786e2e6..a6e633bf285 100644 --- a/src/test/codegen/issue-45222.rs +++ b/src/test/codegen/issue-45222.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags: -O -// min-llvm-version 6.0 #![crate_type = "lib"] diff --git a/src/test/codegen/issue-45466.rs b/src/test/codegen/issue-45466.rs index 14954763944..f916c1a0640 100644 --- a/src/test/codegen/issue-45466.rs +++ b/src/test/codegen/issue-45466.rs @@ -9,7 +9,6 @@ // except according to those terms. // compile-flags: -O -// min-llvm-version 6.0 #![crate_type="rlib"] diff --git a/src/test/codegen/simd-intrinsic-generic-gather.rs b/src/test/codegen/simd-intrinsic-generic-gather.rs index 6c47bf3e321..605a952e8ff 100644 --- a/src/test/codegen/simd-intrinsic-generic-gather.rs +++ b/src/test/codegen/simd-intrinsic-generic-gather.rs @@ -10,7 +10,6 @@ // ignore-emscripten // ignore-tidy-linelength -// min-llvm-version 6.0 // compile-flags: -C no-prepopulate-passes diff --git a/src/test/codegen/simd-intrinsic-generic-scatter.rs b/src/test/codegen/simd-intrinsic-generic-scatter.rs index 7b5b2e55e29..6645778468c 100644 --- a/src/test/codegen/simd-intrinsic-generic-scatter.rs +++ b/src/test/codegen/simd-intrinsic-generic-scatter.rs @@ -10,7 +10,6 @@ // ignore-emscripten // ignore-tidy-linelength -// min-llvm-version 6.0 // compile-flags: -C no-prepopulate-passes diff --git a/src/test/codegen/vtabletype.rs b/src/test/codegen/vtabletype.rs index abd1eb3e2cc..cb96a844341 100644 --- a/src/test/codegen/vtabletype.rs +++ b/src/test/codegen/vtabletype.rs @@ -14,7 +14,6 @@ // ignore-tidy-linelength // ignore-windows // ignore-macos -// min-llvm-version 6.0 // compile-flags: -g -C no-prepopulate-passes diff --git a/src/test/compile-fail/const-fn-error.rs b/src/test/compile-fail/const-fn-error.rs index 17dc9f94fe1..397bc7efd63 100644 --- a/src/test/compile-fail/const-fn-error.rs +++ b/src/test/compile-fail/const-fn-error.rs @@ -8,14 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] +#![feature(const_fn, const_let)] const X : usize = 2; const fn f(x: usize) -> usize { let mut sum = 0; - //~^ let bindings in constant functions are unstable - //~| statements in constant functions are unstable for i in 0..x { //~^ ERROR E0015 //~| ERROR E0019 diff --git a/src/test/compile-fail/must_use-in-stdlib-traits.rs b/src/test/compile-fail/must_use-in-stdlib-traits.rs new file mode 100644 index 00000000000..4bb5c59722a --- /dev/null +++ b/src/test/compile-fail/must_use-in-stdlib-traits.rs @@ -0,0 +1,47 @@ +#![deny(unused_must_use)] +#![feature(futures_api, pin, arbitrary_self_types)] + +use std::iter::Iterator; +use std::future::Future; + +use std::task::{Poll, LocalWaker}; +use std::pin::Pin; +use std::unimplemented; + +struct MyFuture; + +impl Future for MyFuture { + type Output = u32; + + fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<u32> { + Poll::Pending + } +} + +fn iterator() -> impl Iterator { + std::iter::empty::<u32>() +} + +fn future() -> impl Future { + MyFuture +} + +fn square_fn_once() -> impl FnOnce(u32) -> u32 { + |x| x * x +} + +fn square_fn_mut() -> impl FnMut(u32) -> u32 { + |x| x * x +} + +fn square_fn() -> impl Fn(u32) -> u32 { + |x| x * x +} + +fn main() { + iterator(); //~ ERROR unused implementer of `std::iter::Iterator` that must be used + future(); //~ ERROR unused implementer of `std::future::Future` that must be used + square_fn_once(); //~ ERROR unused implementer of `std::ops::FnOnce` that must be used + square_fn_mut(); //~ ERROR unused implementer of `std::ops::FnMut` that must be used + square_fn(); //~ ERROR unused implementer of `std::ops::Fn` that must be used +} diff --git a/src/test/mir-opt/match_test.rs b/src/test/mir-opt/match_test.rs new file mode 100644 index 00000000000..9bfb728e134 --- /dev/null +++ b/src/test/mir-opt/match_test.rs @@ -0,0 +1,85 @@ +// Make sure redundant testing paths in `match` expressions are sorted out. + +#![feature(exclusive_range_pattern)] + +fn main() { + let x = 3; + let b = true; + + // When `(0..=10).contains(x) && !b`, we should jump to the last arm + // without testing two other candidates. + match x { + 0..10 if b => 0, + 10..=20 => 1, + -1 => 2, + _ => 3, + }; +} + +// END RUST SOURCE +// START rustc.main.SimplifyCfg-initial.after.mir +// bb0: { +// ... +// _4 = Le(const 0i32, _1); +// switchInt(move _4) -> [false: bb10, otherwise: bb11]; +// } +// bb1: { +// _3 = const 0i32; +// goto -> bb16; +// } +// bb2: { +// _3 = const 1i32; +// goto -> bb16; +// } +// bb3: { +// _3 = const 2i32; +// goto -> bb16; +// } +// bb4: { +// _3 = const 3i32; +// goto -> bb16; +// } +// bb5: { +// falseEdges -> [real: bb12, imaginary: bb6]; +// } +// bb6: { +// falseEdges -> [real: bb2, imaginary: bb7]; +// } +// bb7: { +// falseEdges -> [real: bb3, imaginary: bb8]; +// } +// bb8: { +// falseEdges -> [real: bb4, imaginary: bb9]; +// } +// bb9: { +// unreachable; +// } +// bb10: { +// _7 = Le(const 10i32, _1); +// switchInt(move _7) -> [false: bb14, otherwise: bb15]; +// } +// bb11: { +// _5 = Lt(_1, const 10i32); +// switchInt(move _5) -> [false: bb10, otherwise: bb5]; +// } +// bb12: { +// StorageLive(_6); +// _6 = _2; +// switchInt(move _6) -> [false: bb13, otherwise: bb1]; +// } +// bb13: { +// falseEdges -> [real: bb8, imaginary: bb6]; +// } +// bb14: { +// switchInt(_1) -> [-1i32: bb7, otherwise: bb8]; +// } +// bb15: { +// _8 = Le(_1, const 20i32); +// switchInt(move _8) -> [false: bb14, otherwise: bb6]; +// } +// bb16: { +// StorageDead(_6); +// ... +// return; +// } +// END rustc.main.SimplifyCfg-initial.after.mir diff --git a/src/test/mir-opt/simplify_cfg.rs b/src/test/mir-opt/simplify_cfg.rs new file mode 100644 index 00000000000..ef843f71581 --- /dev/null +++ b/src/test/mir-opt/simplify_cfg.rs @@ -0,0 +1,54 @@ +// Test that the goto chain starting from bb0 is collapsed. + +fn main() { + loop { + if bar() { + break; + } + } +} + +#[inline(never)] +fn bar() -> bool { + true +} + +// END RUST SOURCE +// START rustc.main.SimplifyCfg-initial.before.mir +// bb0: { +// goto -> bb1; +// } +// bb1: { +// falseUnwind -> [real: bb3, cleanup: bb4]; +// } +// ... +// bb11: { +// ... +// goto -> bb1; +// } +// END rustc.main.SimplifyCfg-initial.before.mir +// START rustc.main.SimplifyCfg-initial.after.mir +// bb0: { +// falseUnwind -> [real: bb1, cleanup: bb2]; +// } +// ... +// bb5: { +// ... +// goto -> bb0; +// } +// END rustc.main.SimplifyCfg-initial.after.mir +// START rustc.main.SimplifyCfg-early-opt.before.mir +// bb0: { +// goto -> bb1; +// } +// bb1: { +// StorageLive(_2); +// _2 = const bar() -> bb3; +// } +// END rustc.main.SimplifyCfg-early-opt.before.mir +// START rustc.main.SimplifyCfg-early-opt.after.mir +// bb0: { +// StorageLive(_2); +// _2 = const bar() -> bb1; +// } +// END rustc.main.SimplifyCfg-early-opt.after.mir diff --git a/src/test/run-pass/ctfe/const-fn-destructuring-arg.rs b/src/test/run-pass/ctfe/const-fn-destructuring-arg.rs deleted file mode 100644 index 88f0d0714f9..00000000000 --- a/src/test/run-pass/ctfe/const-fn-destructuring-arg.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// run-pass -#![allow(dead_code)] - -// test that certain things are disallowed in constant functions - -#![feature(const_fn, const_let)] - -// no destructuring -const fn i(( - a, - b - ): (u32, u32)) -> u32 { - a + b -} - -fn main() {} diff --git a/src/test/run-pass/issues/issue-33140.rs b/src/test/run-pass/issues/issue-33140.rs new file mode 100644 index 00000000000..08c69452f69 --- /dev/null +++ b/src/test/run-pass/issues/issue-33140.rs @@ -0,0 +1,57 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(order_dependent_trait_objects)] + +trait Trait { + fn xyz() -> bool; +} + +impl Trait for dyn Send + Sync { + fn xyz() -> bool { false } +} + +impl Trait for dyn Sync + Send { + fn xyz() -> bool { true } +} + +trait Trait2 { + fn uvw() -> bool; +} + +impl Trait2 for dyn Send + Sync { + fn uvw() -> bool { false } +} + +impl Trait2 for dyn Sync + Send + Sync { + fn uvw() -> bool { true } +} + +struct Foo<T: ?Sized>(T); +impl Foo<dyn Send + Sync> { + fn abc() -> bool { + false + } +} + +impl Foo<dyn Sync + Send> { + fn abc() -> bool { + true + } +} + +fn main() { + assert_eq!(<dyn Send+Sync>::xyz(), false); + assert_eq!(<dyn Sync+Send>::xyz(), true); + assert_eq!(<dyn Send+Sync>::uvw(), false); + assert_eq!(<dyn Sync+Send+Sync>::uvw(), true); + assert_eq!(<Foo<dyn Send+Sync>>::abc(), false); + assert_eq!(<Foo<dyn Sync+Send>>::abc(), true); +} diff --git a/src/test/run-pass/mir/mir_match_test.rs b/src/test/run-pass/mir/mir_match_test.rs new file mode 100644 index 00000000000..1f96d6737e0 --- /dev/null +++ b/src/test/run-pass/mir/mir_match_test.rs @@ -0,0 +1,83 @@ +#![feature(exclusive_range_pattern)] + +// run-pass + +fn main() { + let incl_range = |x, b| { + match x { + 0..=5 if b => 0, + 5..=10 if b => 1, + 1..=4 if !b => 2, + _ => 3, + } + }; + assert_eq!(incl_range(3, false), 2); + assert_eq!(incl_range(3, true), 0); + assert_eq!(incl_range(5, false), 3); + assert_eq!(incl_range(5, true), 0); + + let excl_range = |x, b| { + match x { + 0..5 if b => 0, + 5..10 if b => 1, + 1..4 if !b => 2, + _ => 3, + } + }; + assert_eq!(excl_range(3, false), 2); + assert_eq!(excl_range(3, true), 0); + assert_eq!(excl_range(5, false), 3); + assert_eq!(excl_range(5, true), 1); + + let incl_range_vs_const = |x, b| { + match x { + 0..=5 if b => 0, + 7 => 1, + 3 => 2, + _ => 3, + } + }; + assert_eq!(incl_range_vs_const(5, false), 3); + assert_eq!(incl_range_vs_const(5, true), 0); + assert_eq!(incl_range_vs_const(3, false), 2); + assert_eq!(incl_range_vs_const(3, true), 0); + assert_eq!(incl_range_vs_const(7, false), 1); + assert_eq!(incl_range_vs_const(7, true), 1); + + let excl_range_vs_const = |x, b| { + match x { + 0..5 if b => 0, + 7 => 1, + 3 => 2, + _ => 3, + } + }; + assert_eq!(excl_range_vs_const(5, false), 3); + assert_eq!(excl_range_vs_const(5, true), 3); + assert_eq!(excl_range_vs_const(3, false), 2); + assert_eq!(excl_range_vs_const(3, true), 0); + assert_eq!(excl_range_vs_const(7, false), 1); + assert_eq!(excl_range_vs_const(7, true), 1); + + let const_vs_incl_range = |x, b| { + match x { + 3 if b => 0, + 5..=7 => 2, + 1..=4 => 1, + _ => 3, + } + }; + assert_eq!(const_vs_incl_range(3, false), 1); + assert_eq!(const_vs_incl_range(3, true), 0); + + let const_vs_excl_range = |x, b| { + match x { + 3 if b => 0, + 5..7 => 2, + 1..4 => 1, + _ => 3, + } + }; + assert_eq!(const_vs_excl_range(3, false), 1); + assert_eq!(const_vs_excl_range(3, true), 0); +} diff --git a/src/test/run-pass/simd/simd-intrinsic-generic-gather.rs b/src/test/run-pass/simd/simd-intrinsic-generic-gather.rs index 5f6a72a8e1e..e5ac5775b0c 100644 --- a/src/test/run-pass/simd/simd-intrinsic-generic-gather.rs +++ b/src/test/run-pass/simd/simd-intrinsic-generic-gather.rs @@ -10,7 +10,6 @@ // run-pass // ignore-emscripten -// min-llvm-version 6.0 // Test that the simd_{gather,scatter} intrinsics produce the correct results. diff --git a/src/test/run-pass/sse2.rs b/src/test/run-pass/sse2.rs index 041286fe656..779c72b8df1 100644 --- a/src/test/run-pass/sse2.rs +++ b/src/test/run-pass/sse2.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(stable_features)] -// min-llvm-version 6.0 -// ^ needs MCSubtargetInfo::checkFeatures() // ignore-cloudabi no std::env +#![allow(stable_features)] #![feature(cfg_target_feature)] use std::env; diff --git a/src/test/rustdoc/comment-in-doctest.rs b/src/test/rustdoc/comment-in-doctest.rs new file mode 100644 index 00000000000..3468bb7bda4 --- /dev/null +++ b/src/test/rustdoc/comment-in-doctest.rs @@ -0,0 +1,30 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--test + +// comments, both doc comments and regular ones, used to trick rustdoc's doctest parser into +// thinking that everything after it was part of the regular program. combined with the libsyntax +// parser loop failing to detect the manual main function, it would wrap everything in `fn main`, +// which would cause the doctest to fail as the "extern crate" declaration was no longer valid. +// oddly enough, it would pass in 2018 if a crate was in the extern prelude. see +// https://github.com/rust-lang/rust/issues/56727 + +//! ``` +//! // crate: proc-macro-test +//! //! this is a test +//! +//! // used to pull in proc-macro specific items +//! extern crate proc_macro; +//! +//! use proc_macro::TokenStream; +//! +//! # fn main() {} +//! ``` diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr index 17722bf226d..6f72de0edee 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr @@ -1,3 +1,31 @@ +warning[E0503]: cannot use `y` because it was mutably borrowed + --> $DIR/borrowck-anon-fields-variant.rs:27:7 + | +LL | Foo::Y(ref mut a, _) => a, + | --------- borrow of `y.0` occurs here +... +LL | Foo::Y(_, ref mut b) => b, + | ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0` +... +LL | *a += 1; + | ------- borrow later used here + | + = warning: This error has been downgraded to a warning for backwards compatibility with previous releases. + It represents potential unsoundness in your code. + This warning will become a hard error in the future. + +error[E0503]: cannot use `y` because it was mutably borrowed + --> $DIR/borrowck-anon-fields-variant.rs:44:7 + | +LL | Foo::Y(ref mut a, _) => a, + | --------- borrow of `y.0` occurs here +... +LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow + | ^^^^^^^^^^^^^^^^^^^^ use of borrowed `y.0` +... +LL | *a += 1; + | ------- borrow later used here + error[E0499]: cannot borrow `y.0` as mutable more than once at a time --> $DIR/borrowck-anon-fields-variant.rs:44:14 | @@ -10,6 +38,7 @@ LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow LL | *a += 1; | ------- first borrow later used here -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0499`. +Some errors occurred: E0499, E0503. +For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs index ef0de61d219..63e5bcccf5d 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs @@ -24,7 +24,7 @@ unsafe impl Sync for Foo {} static FOO: Foo = Foo(UnsafeCell::new(42)); static BAR: () = unsafe { - *FOO.0.get() = 5; //~ ERROR could not evaluate static initializer + *FOO.0.get() = 5; //~ ERROR contains unimplemented expression type }; fn main() {} diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr index 0892b05a69d..740954c6c66 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr @@ -1,9 +1,9 @@ -error[E0080]: could not evaluate static initializer +error[E0019]: static contains unimplemented expression type --> $DIR/assign-to-static-within-other-static-2.rs:27:5 | -LL | *FOO.0.get() = 5; //~ ERROR could not evaluate static initializer - | ^^^^^^^^^^^^^^^^ tried to modify a static's initial value from another static's initializer +LL | *FOO.0.get() = 5; //~ ERROR contains unimplemented expression type + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0080`. +For more information about this error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs index 01fcc8307c0..6c2fdcc8615 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs @@ -27,9 +27,7 @@ fn foo() {} static BAR: () = unsafe { *FOO.0.get() = 5; - // we do not error on the above access, because that is not detectable statically. Instead, - // const evaluation will error when trying to evaluate it. Due to the error below, we never even - // attempt to const evaluate `BAR`, so we don't see the error + //~^ contains unimplemented expression foo(); //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr index 01ad1fc9a21..49b39e2f5c6 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -1,9 +1,16 @@ +error[E0019]: static contains unimplemented expression type + --> $DIR/mod-static-with-const-fn.rs:29:5 + | +LL | *FOO.0.get() = 5; + | ^^^^^^^^^^^^^^^^ + error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/mod-static-with-const-fn.rs:34:5 + --> $DIR/mod-static-with-const-fn.rs:32:5 | LL | foo(); | ^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0015`. +Some errors occurred: E0015, E0019. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.rs b/src/test/ui/consts/const-fn-not-safe-for-const.rs index 30a738a83a3..2f7e2ecaa4e 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.rs +++ b/src/test/ui/consts/const-fn-not-safe-for-const.rs @@ -37,15 +37,13 @@ const fn get_Y_addr() -> &'static u32 { } const fn get() -> u32 { - let x = 22; - //~^ ERROR let bindings in constant functions are unstable - //~| ERROR statements in constant functions are unstable - let y = 44; - //~^ ERROR let bindings in constant functions are unstable - //~| ERROR statements in constant functions are unstable + let x = 22; //~ ERROR let bindings in constant functions are unstable +//~^ ERROR statements in constant functions + let y = 44; //~ ERROR let bindings in constant functions are unstable +//~^ ERROR statements in constant functions x + y - //~^ ERROR let bindings in constant functions are unstable - //~| ERROR let bindings in constant functions are unstable +//~^ ERROR let bindings in constant functions are unstable +//~| ERROR let bindings in constant functions are unstable } fn main() {} diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.stderr b/src/test/ui/consts/const-fn-not-safe-for-const.stderr index 613670acc93..1a8c5f558a2 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.stderr +++ b/src/test/ui/consts/const-fn-not-safe-for-const.stderr @@ -19,7 +19,7 @@ LL | &Y error[E0658]: let bindings in constant functions are unstable (see issue #48821) --> $DIR/const-fn-not-safe-for-const.rs:40:13 | -LL | let x = 22; +LL | let x = 22; //~ ERROR let bindings in constant functions are unstable | ^^ | = help: add #![feature(const_let)] to the crate attributes to enable @@ -27,29 +27,29 @@ LL | let x = 22; error[E0658]: statements in constant functions are unstable (see issue #48821) --> $DIR/const-fn-not-safe-for-const.rs:40:13 | -LL | let x = 22; +LL | let x = 22; //~ ERROR let bindings in constant functions are unstable | ^^ | = help: add #![feature(const_let)] to the crate attributes to enable error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/const-fn-not-safe-for-const.rs:43:13 + --> $DIR/const-fn-not-safe-for-const.rs:42:13 | -LL | let y = 44; +LL | let y = 44; //~ ERROR let bindings in constant functions are unstable | ^^ | = help: add #![feature(const_let)] to the crate attributes to enable error[E0658]: statements in constant functions are unstable (see issue #48821) - --> $DIR/const-fn-not-safe-for-const.rs:43:13 + --> $DIR/const-fn-not-safe-for-const.rs:42:13 | -LL | let y = 44; +LL | let y = 44; //~ ERROR let bindings in constant functions are unstable | ^^ | = help: add #![feature(const_let)] to the crate attributes to enable error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/const-fn-not-safe-for-const.rs:46:5 + --> $DIR/const-fn-not-safe-for-const.rs:44:5 | LL | x + y | ^ @@ -57,7 +57,7 @@ LL | x + y = help: add #![feature(const_let)] to the crate attributes to enable error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/const-fn-not-safe-for-const.rs:46:9 + --> $DIR/const-fn-not-safe-for-const.rs:44:9 | LL | x + y | ^ diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index 83825456b5c..c2ed6cd85ab 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -8,6 +8,7 @@ struct S { impl S { const fn foo(&mut self, x: u32) { self.state = x; + //~^ contains unimplemented expression } } diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 7f9a953c10f..0f294616d25 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -1,9 +1,16 @@ +error[E0019]: constant function contains unimplemented expression type + --> $DIR/const_let_assign3.rs:10:9 + | +LL | self.state = x; + | ^^^^^^^^^^^^^^ + error[E0017]: references in constants may only refer to immutable values - --> $DIR/const_let_assign3.rs:16:5 + --> $DIR/const_let_assign3.rs:17:5 | LL | s.foo(3); //~ ERROR references in constants may only refer to immutable values | ^ constants require immutable values -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0017`. +Some errors occurred: E0017, E0019. +For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/const_let_eq.rs b/src/test/ui/consts/const_let_eq.rs new file mode 100644 index 00000000000..8739cb80e94 --- /dev/null +++ b/src/test/ui/consts/const_let_eq.rs @@ -0,0 +1,470 @@ +#![feature(const_let, const_fn)] + +// run-pass + +struct Foo<T>(T); +struct Bar<T> { x: T } +struct W(u32); +struct A { a: u32 } + +const fn basics((a,): (u32,)) -> u32 { + // Deferred assignment: + let b: u32; + b = a + 1; + + // Immediate assignment: + let c: u32 = b + 1; + + // Mutables: + let mut d: u32 = c + 1; + d = d + 1; + // +4 so far. + + // No effect statements work: + ; ; + 1; + + // Array projection + let mut arr: [u32; 1] = [0]; + arr[0] = 1; + d = d + arr[0]; + // +5 + + // Field projection: + let mut foo: Foo<u32> = Foo(0); + let mut bar: Bar<u32> = Bar { x: 0 }; + foo.0 = 1; + bar.x = 1; + d = d + foo.0 + bar.x; + // +7 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(0)]; + arr[0].0 = 1; + d = d + arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 0 }]; + arr[0].x = 1; + d = d + arr[0].x; + // +9 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([0]); + (arr.0)[0] = 1; + d = d + (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [0] }; + arr.x[0] = 1; + d = d + arr.x[0]; + // +11 + + d +} + +const fn add_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a + 1; + d += 1; + // +2 so far. + + // Array projection + let mut arr: [u32; 1] = [0]; + arr[0] += 1; + d += arr[0]; + // +3 + + // Field projection: + let mut foo: Foo<u32> = Foo(0); + let mut bar: Bar<u32> = Bar { x: 0 }; + foo.0 += 1; + bar.x += 1; + d += foo.0 + bar.x; + // +5 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(0)]; + arr[0].0 += 1; + d += arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 0 }]; + arr[0].x += 1; + d += arr[0].x; + // +7 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([0]); + (arr.0)[0] += 1; + d += (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [0] }; + arr.x[0] += 1; + d += arr.x[0]; + // +9 + + d +} + +const fn mul_assign(A { a }: A) -> u32 { + // Mutables: + let mut d: u32 = a + 1; + d *= 2; + // 2^1 * (a + 1) + + // Array projection + let mut arr: [u32; 1] = [1]; + arr[0] *= 2; + d *= arr[0]; + // 2^2 * (a + 1) + + // Field projection: + let mut foo: Foo<u32> = Foo(1); + let mut bar: Bar<u32> = Bar { x: 1 }; + foo.0 *= 2; + bar.x *= 2; + d *= foo.0 + bar.x; + // 2^4 * (a + 1) + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(1)]; + arr[0].0 *= 2; + d *= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 1 }]; + arr[0].x *= 2; + d *= arr[0].x; + // 2^6 * (a + 1) + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([1]); + (arr.0)[0] *= 2; + d *= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [1] }; + arr.x[0] *= 2; + d *= arr.x[0]; + // 2^8 * (a + 1) + + d +} + +const fn div_assign(a: [u32; 1]) -> u32 { + let a = a[0]; + // Mutables: + let mut d: u32 = 1024 * a; + d /= 2; + // 512 + + // Array projection + let mut arr: [u32; 1] = [4]; + arr[0] /= 2; + d /= arr[0]; + // 256 + + // Field projection: + let mut foo: Foo<u32> = Foo(4); + let mut bar: Bar<u32> = Bar { x: 4 }; + foo.0 /= 2; + bar.x /= 2; + d /= foo.0; + d /= bar.x; + // 64 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(4)]; + arr[0].0 /= 2; + d /= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 4 }]; + arr[0].x /= 2; + d /= arr[0].x; + // 16 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([4]); + (arr.0)[0] /= 2; + d /= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [4] }; + arr.x[0] /= 2; + d /= arr.x[0]; + // 4 + + d +} + +const fn rem_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d %= 10; + d += 10; + + // Array projection + let mut arr: [u32; 1] = [3]; + arr[0] %= 2; + d %= 9 + arr[0]; + d += 10; + + // Field projection: + let mut foo: Foo<u32> = Foo(5); + let mut bar: Bar<u32> = Bar { x: 7 }; + foo.0 %= 2; + bar.x %= 2; + d %= 8 + foo.0 + bar.x; + d += 10; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(4)]; + arr[0].0 %= 3; + d %= 9 + arr[0].0; + d += 10; + let mut arr: [Bar<u32>; 1] = [Bar { x: 7 }]; + arr[0].x %= 3; + d %= 9 + arr[0].x; + d += 10; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([6]); + (arr.0)[0] %= 5; + d %= 9 + (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [11] }; + arr.x[0] %= 5; + d %= 9 + arr.x[0]; + + d +} + +const fn sub_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d -= 1; + + // Array projection + let mut arr: [u32; 1] = [2]; + arr[0] -= 1; + d -= arr[0]; + + // Field projection: + let mut foo: Foo<u32> = Foo(2); + let mut bar: Bar<u32> = Bar { x: 2 }; + foo.0 -= 1; + bar.x -= 1; + d -= foo.0 + bar.x; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(2)]; + arr[0].0 -= 1; + d -= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: 2 }]; + arr[0].x -= 1; + d -= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([2]); + (arr.0)[0] -= 1; + d -= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [2] }; + arr.x[0] -= 1; + d -= arr.x[0]; + + d +} + +const fn shl_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d <<= 1; // 10 + + // Array projection + let mut arr: [u32; 1] = [1]; + arr[0] <<= 1; + d <<= arr[0]; // 10 << 2 + + // Field projection: + let mut foo: Foo<u32> = Foo(1); + let mut bar: Bar<u32> = Bar { x: 1 }; + foo.0 <<= 1; + bar.x <<= 1; + d <<= foo.0 + bar.x; // 1000 << 4 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(1)]; + arr[0].0 <<= 1; + d <<= arr[0].0; // 1000_0000 << 2 + let mut arr: [Bar<u32>; 1] = [Bar { x: 1 }]; + arr[0].x <<= 1; + d <<= arr[0].x; // 1000_0000_00 << 2 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([1]); + (arr.0)[0] <<= 1; + d <<= (arr.0)[0]; // 1000_0000_0000 << 2 + let mut arr: Bar<[u32; 1]> = Bar { x: [1] }; + arr.x[0] <<= 1; + d <<= arr.x[0]; // 1000_0000_0000_00 << 2 + + d +} + +const fn shr_assign(W(a): W) -> u32 { + // Mutables: + let mut d: u32 = a; + d >>= 1; // /= 2 + + // Array projection + let mut arr: [u32; 1] = [2]; + arr[0] >>= 1; + d >>= arr[0]; // /= 4 + + // Field projection: + let mut foo: Foo<u32> = Foo(2); + let mut bar: Bar<u32> = Bar { x: 2 }; + foo.0 >>= 1; + bar.x >>= 1; + d >>= foo.0 + bar.x; // /= 16 + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(2)]; + arr[0].0 >>= 1; + d >>= arr[0].0; // /= 32 + let mut arr: [Bar<u32>; 1] = [Bar { x: 2 }]; + arr[0].x >>= 1; + d >>= arr[0].x; // /= 64 + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([2]); + (arr.0)[0] >>= 1; + d >>= (arr.0)[0]; // /= 128 + let mut arr: Bar<[u32; 1]> = Bar { x: [2] }; + arr.x[0] >>= 1; + d >>= arr.x[0]; // /= 256 + + d +} + +const fn bit_and_assign(W(a): W) -> u32 { + let f = 0b1111_1111_1111_1111; + + // Mutables: + let mut d: u32 = a; + d &= 0b1111_1111_1111_1110; + + // Array projection + let mut arr: [u32; 1] = [f]; + arr[0] &= 0b1111_1111_1111_1101; + d &= arr[0]; + + // Field projection: + let mut foo: Foo<u32> = Foo(f); + let mut bar: Bar<u32> = Bar { x: f }; + foo.0 &= 0b1111_1111_1111_0111; + bar.x &= 0b1111_1111_1101_1111; + d &= foo.0 & bar.x; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(f)]; + arr[0].0 &= 0b1111_1110_1111_1111; + d &= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: f }]; + arr[0].x &= 0b1111_1101_1111_1111; + d &= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([f]); + (arr.0)[0] &= 0b1011_1111_1111_1111; + d &= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [f] }; + arr.x[0] &= 0b0111_1111_1111_1111; + d &= arr.x[0]; + + d +} + +const fn bit_or_assign(W(a): W) -> u32 { + let f = 0b0000_0000_0000_0000; + + // Mutables: + let mut d: u32 = a; + d |= 0b0000_0000_0000_0001; + + // Array projection + let mut arr: [u32; 1] = [f]; + arr[0] |= 0b0000_0000_0000_1001; + d |= arr[0]; + + // Field projection: + let mut foo: Foo<u32> = Foo(f); + let mut bar: Bar<u32> = Bar { x: f }; + foo.0 |= 0b0000_0000_0001_0000; + bar.x |= 0b0000_0000_0100_0000; + d |= foo.0 | bar.x; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(f)]; + arr[0].0 |= 0b0000_0001_0000_0000; + d |= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: f }]; + arr[0].x |= 0b0000_0010_0000_0000; + d |= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([f]); + (arr.0)[0] |= 0b1000_0000_0000_0000; + d |= (arr.0)[0]; // /= 128 + let mut arr: Bar<[u32; 1]> = Bar { x: [f] }; + arr.x[0] |= 0b1100_0000_0000_0000; + d |= arr.x[0]; // /= 256 + + d +} + +const fn bit_xor_assign(W(a): W) -> u32 { + let f = 0b0000_0000_0000_0000; + + // Mutables: + let mut d: u32 = a; + d ^= 0b0000_0000_0000_0001; + + // Array projection + let mut arr: [u32; 1] = [f]; + arr[0] ^= 0b0000_0000_0000_0010; + d ^= arr[0]; + + // Field projection: + let mut foo: Foo<u32> = Foo(f); + let mut bar: Bar<u32> = Bar { x: f }; + foo.0 ^= 0b0000_0000_0001_0000; + bar.x ^= 0b0000_0000_1000_0000; + d ^= foo.0 ^ bar.x; + + // Array + Field projection: + let mut arr: [Foo<u32>; 1] = [Foo(f)]; + arr[0].0 ^= 0b0000_0001_0000_0000; + d ^= arr[0].0; + let mut arr: [Bar<u32>; 1] = [Bar { x: f }]; + arr[0].x ^= 0b0000_0010_0000_0000; + d ^= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[u32; 1]> = Foo([f]); + (arr.0)[0] ^= 0b0100_0000_0000_0000; + d ^= (arr.0)[0]; + let mut arr: Bar<[u32; 1]> = Bar { x: [f] }; + arr.x[0] ^= 0b1000_0000_0000_0000; + d ^= arr.x[0]; + + d +} + +macro_rules! test { + ($c:ident, $e:expr, $r:expr) => { + const $c: u32 = $e; + assert_eq!($c, $r); + assert_eq!($e, $r); + } +} + +fn main() { + test!(BASICS, basics((2,)), 13); + test!(ADD, add_assign(W(1)), 10); + test!(MUL, mul_assign(A { a: 0 }), 256); + test!(DIV, div_assign([1]), 4); + test!(REM, rem_assign(W(5)), 5); + test!(SUB, sub_assign(W(8)), 0); + test!(SHL, shl_assign(W(1)), 0b1000_0000_0000_0000); + test!(SHR, shr_assign(W(256)), 1); + test!(AND, bit_and_assign(W(0b1011_1111_1111_1111_1111)), 0b0011_1100_1101_0100); + test!(OR, bit_or_assign(W(0b1011_0000_0000_0000)), 0b1111_0011_0101_1001); + test!(XOR, bit_xor_assign(W(0b0000_0000_0000_0000)), 0b1100_0011_1001_0011); +} diff --git a/src/test/ui/consts/const_let_eq_float.rs b/src/test/ui/consts/const_let_eq_float.rs new file mode 100644 index 00000000000..2c7262df367 --- /dev/null +++ b/src/test/ui/consts/const_let_eq_float.rs @@ -0,0 +1,279 @@ +// compile-pass + +#![feature(const_let, const_fn)] + +struct Foo<T>(T); +struct Bar<T> { x: T } +struct W(f32); +struct A { a: f32 } + +const fn basics((a,): (f32,)) -> f32 { + // Deferred assignment: + let b: f32; + b = a + 1.0; + + // Immediate assignment: + let c: f32 = b + 1.0; + + // Mutables: + let mut d: f32 = c + 1.0; + d = d + 1.0; + // +4 so far. + + // No effect statements work: + ; ; + 1; + + // Array projection + let mut arr: [f32; 1] = [0.0]; + arr[0] = 1.0; + d = d + arr[0]; + // +5 + + // Field projection: + let mut foo: Foo<f32> = Foo(0.0); + let mut bar: Bar<f32> = Bar { x: 0.0 }; + foo.0 = 1.0; + bar.x = 1.0; + d = d + foo.0 + bar.x; + // +7 + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(0.0)]; + arr[0].0 = 1.0; + d = d + arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 0.0 }]; + arr[0].x = 1.0; + d = d + arr[0].x; + // +9 + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([0.0]); + (arr.0)[0] = 1.0; + d = d + (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [0.0] }; + arr.x[0] = 1.0; + d = d + arr.x[0]; + // +11 + + d +} + +const fn add_assign(W(a): W) -> f32 { + // Mutables: + let mut d: f32 = a + 1.0; + d += 1.0; + // +2 so far. + + // Array projection + let mut arr: [f32; 1] = [0.0]; + arr[0] += 1.0; + d += arr[0]; + // +3 + + // Field projection: + let mut foo: Foo<f32> = Foo(0.0); + let mut bar: Bar<f32> = Bar { x: 0.0 }; + foo.0 += 1.0; + bar.x += 1.0; + d += foo.0 + bar.x; + // +5 + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(0.0)]; + arr[0].0 += 1.0; + d += arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 0.0 }]; + arr[0].x += 1.0; + d += arr[0].x; + // +7 + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([0.0]); + (arr.0)[0] += 1.0; + d += (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [0.0] }; + arr.x[0] += 1.0; + d += arr.x[0]; + // +9 + + d +} + +const fn mul_assign(A { a }: A) -> f32 { + // Mutables: + let mut d: f32 = a + 1.0; + d *= 2.0; + // 2^1 * (a + 1) + + // Array projection + let mut arr: [f32; 1] = [1.0]; + arr[0] *= 2.0; + d *= arr[0]; + // 2^2 * (a + 1) + + // Field projection: + let mut foo: Foo<f32> = Foo(1.0); + let mut bar: Bar<f32> = Bar { x: 1.0 }; + foo.0 *= 2.0; + bar.x *= 2.0; + d *= foo.0 + bar.x; + // 2^4 * (a + 1) + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(1.0)]; + arr[0].0 *= 2.0; + d *= arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 1.0 }]; + arr[0].x *= 2.0; + d *= arr[0].x; + // 2^6 * (a + 1) + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([1.0]); + (arr.0)[0] *= 2.0; + d *= (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [1.0] }; + arr.x[0] *= 2.0; + d *= arr.x[0]; + // 2^8 * (a + 1) + + d +} + +const fn div_assign(a: [f32; 1]) -> f32 { + let a = a[0]; + // Mutables: + let mut d: f32 = 1024.0 * a; + d /= 2.0; + // 512 + + // Array projection + let mut arr: [f32; 1] = [4.0]; + arr[0] /= 2.0; + d /= arr[0]; + // 256 + + // Field projection: + let mut foo: Foo<f32> = Foo(4.0); + let mut bar: Bar<f32> = Bar { x: 4.0 }; + foo.0 /= 2.0; + bar.x /= 2.0; + d /= foo.0; + d /= bar.x; + // 64 + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(4.0)]; + arr[0].0 /= 2.0; + d /= arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 4.0 }]; + arr[0].x /= 2.0; + d /= arr[0].x; + // 16 + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([4.0]); + (arr.0)[0] /= 2.0; + d /= (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [4.0] }; + arr.x[0] /= 2.0; + d /= arr.x[0]; + // 4 + + d +} + +const fn rem_assign(W(a): W) -> f32 { + // Mutables: + let mut d: f32 = a; + d %= 10.0; + d += 10.0; + + // Array projection + let mut arr: [f32; 1] = [3.0]; + arr[0] %= 2.0; + d %= 9.0 + arr[0]; + d += 10.0; + + // Field projection: + let mut foo: Foo<f32> = Foo(5.0); + let mut bar: Bar<f32> = Bar { x: 7.0 }; + foo.0 %= 2.0; + bar.x %= 2.0; + d %= 8.0 + foo.0 + bar.x; + d += 10.0; + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(4.0)]; + arr[0].0 %= 3.0; + d %= 9.0 + arr[0].0; + d += 10.0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 7.0 }]; + arr[0].x %= 3.0; + d %= 9.0 + arr[0].x; + d += 10.0; + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([6.0]); + (arr.0)[0] %= 5.0; + d %= 9.0 + (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [11.0] }; + arr.x[0] %= 5.0; + d %= 9.0 + arr.x[0]; + + d +} + +const fn sub_assign(W(a): W) -> f32 { + // Mutables: + let mut d: f32 = a; + d -= 1.0; + + // Array projection + let mut arr: [f32; 1] = [2.0]; + arr[0] -= 1.0; + d -= arr[0]; + + // Field projection: + let mut foo: Foo<f32> = Foo(2.0); + let mut bar: Bar<f32> = Bar { x: 2.0 }; + foo.0 -= 1.0; + bar.x -= 1.0; + d -= foo.0 + bar.x; + + // Array + Field projection: + let mut arr: [Foo<f32>; 1] = [Foo(2.0)]; + arr[0].0 -= 1.0; + d -= arr[0].0; + let mut arr: [Bar<f32>; 1] = [Bar { x: 2.0 }]; + arr[0].x -= 1.0; + d -= arr[0].x; + + // Field + Array projection: + let mut arr: Foo<[f32; 1]> = Foo([2.0]); + (arr.0)[0] -= 1.0; + d -= (arr.0)[0]; + let mut arr: Bar<[f32; 1]> = Bar { x: [2.0] }; + arr.x[0] -= 1.0; + d -= arr.x[0]; + + d +} + +macro_rules! test { + ($c:ident, $e:expr, $r:expr) => { + const $c: f32 = $e; + assert_eq!($c, $r); + assert_eq!($e, $r); + } +} + +fn main() { + test!(BASICS, basics((2.0,)), 13.0); + test!(ADD, add_assign(W(1.0)), 10.0); + test!(MUL, mul_assign(A { a: 0.0 }), 256.0); + test!(DIV, div_assign([1.0]), 4.0); + test!(REM, rem_assign(W(5.0)), 5.0); + test!(SUB, sub_assign(W(8.0)), 0.0); +} diff --git a/src/test/ui/consts/const_short_circuit.rs b/src/test/ui/consts/const_short_circuit.rs new file mode 100644 index 00000000000..cc49e4696e5 --- /dev/null +++ b/src/test/ui/consts/const_short_circuit.rs @@ -0,0 +1,16 @@ +#![feature(underscore_const_names, const_let)] + +const _: bool = false && false; +const _: bool = true && false; +const _: bool = { + let mut x = true && false; + //~^ ERROR new features like let bindings are not permitted + x +}; +const _: bool = { + let x = true && false; + //~^ ERROR new features like let bindings are not permitted + x +}; + +fn main() {} diff --git a/src/test/ui/consts/const_short_circuit.stderr b/src/test/ui/consts/const_short_circuit.stderr new file mode 100644 index 00000000000..a67bb0b1b6d --- /dev/null +++ b/src/test/ui/consts/const_short_circuit.stderr @@ -0,0 +1,26 @@ +error: new features like let bindings are not permitted in constants which also use short circuiting operators + --> $DIR/const_short_circuit.rs:6:9 + | +LL | let mut x = true && false; + | ^^^^^ + | +note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See https://github.com/rust-lang/rust/issues/49146 for more information. + --> $DIR/const_short_circuit.rs:6:22 + | +LL | let mut x = true && false; + | ^^ + +error: new features like let bindings are not permitted in constants which also use short circuiting operators + --> $DIR/const_short_circuit.rs:11:9 + | +LL | let x = true && false; + | ^ + | +note: use of `&&` operator here does not actually short circuit due to the const evaluator presently not being able to do control flow. See https://github.com/rust-lang/rust/issues/49146 for more information. + --> $DIR/const_short_circuit.rs:11:18 + | +LL | let x = true && false; + | ^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr index f43befb37c1..6c4e9e0a067 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr @@ -115,7 +115,7 @@ LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn error: local variables in const fn are unstable --> $DIR/min_const_fn.rs:109:34 | -LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable +LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn | ^ error: `if`, `match`, `&&` and `||` are not stable in const fn diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 43ca9e75393..ad983da4df9 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -106,7 +106,7 @@ const fn foo30_2(x: *mut u32) -> usize { x as usize } const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } } //~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn -const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable +const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn const fn foo36(a: bool, b: bool) -> bool { a && b } //~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn const fn foo37(a: bool, b: bool) -> bool { a || b } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index bcb9be6e548..a93a4f817fc 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -115,7 +115,7 @@ LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn error: local variables in const fn are unstable --> $DIR/min_const_fn.rs:109:34 | -LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn are unstable +LL | const fn foo30_6() -> bool { let x = true; x } //~ ERROR local variables in const fn | ^ error: `if`, `match`, `&&` and `||` are not stable in const fn diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs index f11b43dcd86..92e99c6228a 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.rs @@ -28,13 +28,13 @@ const fn call_unsafe_generic_cell_const_fn() -> *const Vec<std::cell::Cell<u32>> unsafe { ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() } //~^ ERROR calls to `const unsafe fn` in const fns } -const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~^ dereferencing raw pointers in constant functions fn main() {} const unsafe fn no_union() { union Foo { x: (), y: () } - Foo { x: () }.y //~ ERROR not allowed in const fn + Foo { x: () }.y //~^ unions in const fn } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 922a7883b9f..fafc89d1493 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -1,7 +1,7 @@ error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) --> $DIR/min_const_fn_unsafe.rs:31:59 | -LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } | ^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable @@ -9,7 +9,7 @@ LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR no error[E0658]: unions in const fn are unstable (see issue #51909) --> $DIR/min_const_fn_unsafe.rs:38:5 | -LL | Foo { x: () }.y //~ ERROR not allowed in const fn +LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | = help: add #![feature(const_fn_union)] to the crate attributes to enable @@ -38,24 +38,6 @@ LL | unsafe { ret_null_mut_ptr_no_unsafe::<Vec<std::cell::Cell<u32>>>() } | = help: add #![feature(min_const_unsafe_fn)] to the crate attributes to enable -error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:31:59 - | -LL | const unsafe fn deref_forbidden(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn - | ^^ dereference of raw pointer - | - = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: access to union field is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe.rs:38:5 - | -LL | Foo { x: () }.y //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^ access to union field - | - = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs index 8a6884bc6b9..67a48206126 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.rs @@ -34,29 +34,28 @@ const unsafe fn foo9_3() -> *const String { const unsafe fn foo10_3() -> *const Vec<std::cell::Cell<u32>> { unsafe { foo6::<Vec<std::cell::Cell<u32>>>() } } -// not ok const unsafe fn foo8_2() -> i32 { - foo4() //~ ERROR not allowed in const fn + foo4() } const unsafe fn foo9_2() -> *const String { - foo5::<String>() //~ ERROR not allowed in const fn + foo5::<String>() } const unsafe fn foo10_2() -> *const Vec<std::cell::Cell<u32>> { - foo6::<Vec<std::cell::Cell<u32>>>() //~ ERROR not allowed in const fn + foo6::<Vec<std::cell::Cell<u32>>>() } -const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~^ dereferencing raw pointers in constant functions -const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn +const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~^ dereferencing raw pointers in constant functions -const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed +const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe //~^ dereferencing raw pointers in constant functions fn main() {} const unsafe fn no_union() { union Foo { x: (), y: () } - Foo { x: () }.y //~ ERROR not allowed in const fn + Foo { x: () }.y //~^ unions in const fn } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr index 20c75afbe63..63bf9a53e50 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_feature_gate.stderr @@ -1,97 +1,44 @@ error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:46:51 | -LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn +LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } | ^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:49:60 | -LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn +LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } | ^^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:52:62 | -LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed +LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe | ^^^ | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error[E0658]: unions in const fn are unstable (see issue #51909) - --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5 + --> $DIR/min_const_fn_unsafe_feature_gate.rs:59:5 | -LL | Foo { x: () }.y //~ ERROR not allowed in const fn +LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | = help: add #![feature(const_fn_union)] to the crate attributes to enable -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:39:5 +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/min_const_fn_unsafe_feature_gate.rs:52:62 | -LL | foo4() //~ ERROR not allowed in const fn - | ^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:42:5 - | -LL | foo5::<String>() //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: call to unsafe function is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:45:5 - | -LL | foo6::<Vec<std::cell::Cell<u32>>>() //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:47:51 - | -LL | const unsafe fn foo30_3(x: *mut usize) -> usize { *x } //~ ERROR not allowed in const fn - | ^^ dereference of raw pointer - | - = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:50:60 - | -LL | const unsafe fn foo30_4(x: *mut usize) -> &'static usize { &*x } //~ ERROR not allowed in const fn - | ^^^ dereference of raw pointer - | - = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: dereference of raw pointer is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:53:62 - | -LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ ERROR not allowed +LL | const fn foo30_5(x: *mut usize) -> &'static usize { unsafe { &*x } } //~ is unsafe | ^^^ dereference of raw pointer | = note: raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior -error: access to union field is unsafe and unsafe operations are not allowed in const fn - --> $DIR/min_const_fn_unsafe_feature_gate.rs:60:5 - | -LL | Foo { x: () }.y //~ ERROR not allowed in const fn - | ^^^^^^^^^^^^^^^ access to union field - | - = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior - = note: unsafe action within a `const unsafe fn` still require an `unsafe` block in contrast to regular `unsafe fn`. - -error: aborting due to 11 previous errors +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors occurred: E0133, E0658. +For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.rs b/src/test/ui/consts/min_const_fn/mutable_borrow.rs new file mode 100644 index 00000000000..3dd76b630a8 --- /dev/null +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.rs @@ -0,0 +1,17 @@ +const fn mutable_ref_in_const() -> u8 { + let mut a = 0; //~ ERROR local variables in const fn + let b = &mut a; + *b +} + +struct X; + +impl X { + const fn inherent_mutable_ref_in_const() -> u8 { + let mut a = 0; //~ ERROR local variables in const fn + let b = &mut a; + *b + } +} + +fn main() {} diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr new file mode 100644 index 00000000000..fa46f5c804f --- /dev/null +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr @@ -0,0 +1,14 @@ +error: local variables in const fn are unstable + --> $DIR/mutable_borrow.rs:2:9 + | +LL | let mut a = 0; //~ ERROR local variables in const fn + | ^^^^^ + +error: local variables in const fn are unstable + --> $DIR/mutable_borrow.rs:11:13 + | +LL | let mut a = 0; //~ ERROR local variables in const fn + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs index 34e8eaba9f2..5863429a2f2 100644 --- a/src/test/ui/consts/projection_qualif.rs +++ b/src/test/ui/consts/projection_qualif.rs @@ -7,6 +7,7 @@ const FOO: &u32 = { { let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants + //~^ contains unimplemented expression } &{a} }; diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr index d5252f199be..cc3635a979b 100644 --- a/src/test/ui/consts/projection_qualif.stderr +++ b/src/test/ui/consts/projection_qualif.stderr @@ -4,6 +4,12 @@ error[E0017]: references in constants may only refer to immutable values LL | let b: *mut u32 = &mut a; //~ ERROR may only refer to immutable values | ^^^^^^ constants require immutable values +error[E0019]: constant contains unimplemented expression type + --> $DIR/projection_qualif.rs:9:18 + | +LL | unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants + | ^^^^^^ + error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911) --> $DIR/projection_qualif.rs:9:18 | @@ -12,7 +18,7 @@ LL | unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constant | = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors occurred: E0017, E0658. +Some errors occurred: E0017, E0019, E0658. For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/consts/single_variant_match_ice.rs b/src/test/ui/consts/single_variant_match_ice.rs index 67a41bc5dc4..79dde3c18e8 100644 --- a/src/test/ui/consts/single_variant_match_ice.rs +++ b/src/test/ui/consts/single_variant_match_ice.rs @@ -2,6 +2,14 @@ enum Foo { Prob, } +const FOO: u32 = match Foo::Prob { + Foo::Prob => 42, //~ ERROR unimplemented expression type +}; + +const BAR: u32 = match Foo::Prob { + x => 42, //~ ERROR unimplemented expression type +}; + impl Foo { pub const fn as_val(&self) -> u8 { use self::Foo::*; diff --git a/src/test/ui/consts/single_variant_match_ice.stderr b/src/test/ui/consts/single_variant_match_ice.stderr index a0222b0d489..f5c2cb5e0e9 100644 --- a/src/test/ui/consts/single_variant_match_ice.stderr +++ b/src/test/ui/consts/single_variant_match_ice.stderr @@ -1,8 +1,21 @@ +error[E0019]: constant contains unimplemented expression type + --> $DIR/single_variant_match_ice.rs:6:5 + | +LL | Foo::Prob => 42, //~ ERROR unimplemented expression type + | ^^^^^^^^^ + +error[E0019]: constant contains unimplemented expression type + --> $DIR/single_variant_match_ice.rs:10:5 + | +LL | x => 42, //~ ERROR unimplemented expression type + | ^ + error: `if`, `match`, `&&` and `||` are not stable in const fn - --> $DIR/single_variant_match_ice.rs:10:13 + --> $DIR/single_variant_match_ice.rs:18:13 | LL | Prob => 0x1, //~ ERROR `if`, `match`, `&&` and `||` are not stable in const fn | ^^^^ -error: aborting due to previous error +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0019`. diff --git a/src/test/ui/deprecation/deprecation-in-future.rs b/src/test/ui/deprecation/deprecation-in-future.rs new file mode 100644 index 00000000000..c6c60177e9d --- /dev/null +++ b/src/test/ui/deprecation/deprecation-in-future.rs @@ -0,0 +1,12 @@ +// ignore-tidy-linelength + +#![deny(deprecated_in_future)] + +#[deprecated(since = "99.99.99", note = "text")] +pub fn deprecated_future() {} + +fn test() { + deprecated_future(); //~ ERROR use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text +} + +fn main() {} diff --git a/src/test/ui/deprecation/deprecation-in-future.stderr b/src/test/ui/deprecation/deprecation-in-future.stderr new file mode 100644 index 00000000000..38392cf9608 --- /dev/null +++ b/src/test/ui/deprecation/deprecation-in-future.stderr @@ -0,0 +1,14 @@ +error: use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text + --> $DIR/deprecation-in-future.rs:9:5 + | +LL | deprecated_future(); //~ ERROR use of item 'deprecated_future' that will be deprecated in future version 99.99.99: text + | ^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/deprecation-in-future.rs:3:9 + | +LL | #![deny(deprecated_in_future)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/extern/auxiliary/invalid-utf8.txt b/src/test/ui/extern/auxiliary/invalid-utf8.txt new file mode 100644 index 00000000000..dc1115b82db --- /dev/null +++ b/src/test/ui/extern/auxiliary/invalid-utf8.txt @@ -0,0 +1 @@ +( \ No newline at end of file diff --git a/src/test/ui/extern/external-doc-error.rs b/src/test/ui/extern/external-doc-error.rs index 5c6f6e49b3d..e17dda65568 100644 --- a/src/test/ui/extern/external-doc-error.rs +++ b/src/test/ui/extern/external-doc-error.rs @@ -2,7 +2,31 @@ #![feature(external_doc)] -#[doc(include = "not-a-file.md")] //~ ERROR: couldn't read -pub struct SomeStruct; +#[doc(include = "not-a-file.md")] +pub struct SomeStruct; //~^ ERROR couldn't read + //~| HELP external doc paths are relative to the crate root + +#[doc(include = "auxiliary/invalid-utf8.txt")] +pub struct InvalidUtf8; //~^ ERROR wasn't a utf-8 file + +#[doc(include)] +pub struct MissingPath; //~^ ERROR expected path + //~| HELP provide a file path with `=` + //~| SUGGESTION include = "<path>" + +#[doc(include("../README.md"))] +pub struct InvalidPathSyntax; //~^ ERROR expected path + //~| HELP provide a file path with `=` + //~| SUGGESTION include = "../README.md" + +#[doc(include = 123)] +pub struct InvalidPathType; //~^ ERROR expected path + //~| HELP provide a file path with `=` + //~| SUGGESTION include = "<path>" + +#[doc(include(123))] +pub struct InvalidPathSyntaxAndType; //~^ ERROR expected path + //~| HELP provide a file path with `=` + //~| SUGGESTION include = "<path>" fn main() {} diff --git a/src/test/ui/extern/external-doc-error.stderr b/src/test/ui/extern/external-doc-error.stderr index 5cc7551ee03..a3be3277de5 100644 --- a/src/test/ui/extern/external-doc-error.stderr +++ b/src/test/ui/extern/external-doc-error.stderr @@ -1,8 +1,40 @@ error: couldn't read $DIR/not-a-file.md: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/external-doc-error.rs:5:1 + --> $DIR/external-doc-error.rs:5:17 | -LL | #[doc(include = "not-a-file.md")] //~ ERROR: couldn't read - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc(include = "not-a-file.md")] + | ^^^^^^^^^^^^^^^ couldn't read file + | + = help: external doc paths are relative to the crate root + +error: $DIR/auxiliary/invalid-utf8.txt wasn't a utf-8 file + --> $DIR/external-doc-error.rs:9:17 + | +LL | #[doc(include = "auxiliary/invalid-utf8.txt")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ contains invalid utf-8 + +error: expected path to external documentation + --> $DIR/external-doc-error.rs:12:7 + | +LL | #[doc(include)] + | ^^^^^^^ help: provide a file path with `=`: `include = "<path>"` + +error: expected path to external documentation + --> $DIR/external-doc-error.rs:17:7 + | +LL | #[doc(include("../README.md"))] + | ^^^^^^^^^^^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "../README.md"` + +error: expected path to external documentation + --> $DIR/external-doc-error.rs:22:7 + | +LL | #[doc(include = 123)] + | ^^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"` + +error: expected path to external documentation + --> $DIR/external-doc-error.rs:27:7 + | +LL | #[doc(include(123))] + | ^^^^^^^^^^^^ help: provide a file path with `=`: `include = "<path>"` -error: aborting due to previous error +error: aborting due to 6 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-const_let.rs b/src/test/ui/feature-gates/feature-gate-const_let.rs index 05d02e62bc8..9bf957a5f1e 100644 --- a/src/test/ui/feature-gates/feature-gate-const_let.rs +++ b/src/test/ui/feature-gates/feature-gate-const_let.rs @@ -10,13 +10,22 @@ // Test use of const let without feature gate. -#![feature(const_fn)] +const FOO: usize = { + //~^ ERROR statements in constants are unstable + //~| ERROR: let bindings in constants are unstable + let x = 42; + //~^ ERROR statements in constants are unstable + //~| ERROR: let bindings in constants are unstable + 42 +}; -const fn foo() -> usize { +static BAR: usize = { + //~^ ERROR statements in statics are unstable + //~| ERROR: let bindings in statics are unstable let x = 42; - //~^ ERROR statements in constant functions are unstable - //~| ERROR: let bindings in constant functions are unstable + //~^ ERROR statements in statics are unstable + //~| ERROR: let bindings in statics are unstable 42 -} +}; fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_let.stderr b/src/test/ui/feature-gates/feature-gate-const_let.stderr index 6a7f6255678..acb5165918e 100644 --- a/src/test/ui/feature-gates/feature-gate-const_let.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_let.stderr @@ -1,4 +1,4 @@ -error[E0658]: let bindings in constant functions are unstable (see issue #48821) +error[E0658]: let bindings in constants are unstable (see issue #48821) --> $DIR/feature-gate-const_let.rs:16:13 | LL | let x = 42; @@ -6,7 +6,7 @@ LL | let x = 42; | = help: add #![feature(const_let)] to the crate attributes to enable -error[E0658]: statements in constant functions are unstable (see issue #48821) +error[E0658]: statements in constants are unstable (see issue #48821) --> $DIR/feature-gate-const_let.rs:16:13 | LL | let x = 42; @@ -14,6 +14,78 @@ LL | let x = 42; | = help: add #![feature(const_let)] to the crate attributes to enable -error: aborting due to 2 previous errors +error[E0658]: let bindings in constants are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:13:1 + | +LL | / const FOO: usize = { +LL | | //~^ ERROR statements in constants are unstable +LL | | //~| ERROR: let bindings in constants are unstable +LL | | let x = 42; +... | +LL | | 42 +LL | | }; + | |__^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: statements in constants are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:13:1 + | +LL | / const FOO: usize = { +LL | | //~^ ERROR statements in constants are unstable +LL | | //~| ERROR: let bindings in constants are unstable +LL | | let x = 42; +... | +LL | | 42 +LL | | }; + | |__^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: let bindings in statics are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:25:13 + | +LL | let x = 42; + | ^^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: statements in statics are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:25:13 + | +LL | let x = 42; + | ^^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: let bindings in statics are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:22:1 + | +LL | / static BAR: usize = { +LL | | //~^ ERROR statements in statics are unstable +LL | | //~| ERROR: let bindings in statics are unstable +LL | | let x = 42; +... | +LL | | 42 +LL | | }; + | |__^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error[E0658]: statements in statics are unstable (see issue #48821) + --> $DIR/feature-gate-const_let.rs:22:1 + | +LL | / static BAR: usize = { +LL | | //~^ ERROR statements in statics are unstable +LL | | //~| ERROR: let bindings in statics are unstable +LL | | let x = 42; +... | +LL | | 42 +LL | | }; + | |__^ + | + = help: add #![feature(const_let)] to the crate attributes to enable + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-underscore-imports.rs b/src/test/ui/feature-gates/feature-gate-underscore-imports.rs deleted file mode 100644 index ceb8afe124a..00000000000 --- a/src/test/ui/feature-gates/feature-gate-underscore-imports.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern crate std as _; //~ ERROR renaming extern crates with `_` is unstable -use std::vec as _; //~ ERROR renaming imports with `_` is unstable - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-underscore-imports.stderr b/src/test/ui/feature-gates/feature-gate-underscore-imports.stderr deleted file mode 100644 index 2eea95260d5..00000000000 --- a/src/test/ui/feature-gates/feature-gate-underscore-imports.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: renaming extern crates with `_` is unstable (see issue #48216) - --> $DIR/feature-gate-underscore-imports.rs:11:1 - | -LL | extern crate std as _; //~ ERROR renaming extern crates with `_` is unstable - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add #![feature(underscore_imports)] to the crate attributes to enable - -error[E0658]: renaming imports with `_` is unstable (see issue #48216) - --> $DIR/feature-gate-underscore-imports.rs:12:5 - | -LL | use std::vec as _; //~ ERROR renaming imports with `_` is unstable - | ^^^^^^^^^^^^^ - | - = help: add #![feature(underscore_imports)] to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-33140.rs b/src/test/ui/issues/issue-33140.rs new file mode 100644 index 00000000000..fef5a82d9f8 --- /dev/null +++ b/src/test/ui/issues/issue-33140.rs @@ -0,0 +1,62 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(order_dependent_trait_objects)] + +trait Trait { + fn xyz() -> bool; +} + +impl Trait for dyn Send + Sync { + fn xyz() -> bool { false } +} + +impl Trait for dyn Sync + Send { +//~^ ERROR conflicting implementations +//~| hard error + fn xyz() -> bool { true } +} + +trait Trait2 { + fn uvw() -> bool; +} + +impl Trait2 for dyn Send + Sync { + fn uvw() -> bool { false } +} + +impl Trait2 for dyn Sync + Send + Sync { +//~^ ERROR conflicting implementations +//~| hard error + fn uvw() -> bool { true } +} + +struct Foo<T: ?Sized>(T); +impl Foo<dyn Send + Sync> { + fn abc() -> bool { //~ ERROR duplicate definitions with name `abc` + //~| hard error + false + } +} + +impl Foo<dyn Sync + Send> { + fn abc() -> bool { + true + } +} + +fn main() { + assert_eq!(<Send+Sync>::xyz(), false); + assert_eq!(<Sync+Send>::xyz(), true); + assert_eq!(<Send+Sync>::uvw(), false); + assert_eq!(<Sync+Send+Sync>::uvw(), true); + assert_eq!(<Foo<Send+Sync>>::abc(), false); + assert_eq!(<Foo<Sync+Send>>::abc(), true); +} diff --git a/src/test/ui/issues/issue-33140.stderr b/src/test/ui/issues/issue-33140.stderr new file mode 100644 index 00000000000..240137f863a --- /dev/null +++ b/src/test/ui/issues/issue-33140.stderr @@ -0,0 +1,48 @@ +error: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) + --> $DIR/issue-33140.rs:21:1 + | +LL | impl Trait for dyn Send + Sync { + | ------------------------------ first implementation here +... +LL | impl Trait for dyn Sync + Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` + | +note: lint level defined here + --> $DIR/issue-33140.rs:11:9 + | +LL | #![deny(order_dependent_trait_objects)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 #56484 <https://github.com/rust-lang/rust/issues/56484> + +error: conflicting implementations of trait `Trait2` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119) + --> $DIR/issue-33140.rs:35:1 + | +LL | impl Trait2 for dyn Send + Sync { + | ------------------------------- first implementation here +... +LL | impl Trait2 for dyn Sync + Send + Sync { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)` + | + = 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 #56484 <https://github.com/rust-lang/rust/issues/56484> + +error: duplicate definitions with name `abc` (E0592) + --> $DIR/issue-33140.rs:43:5 + | +LL | / fn abc() -> bool { //~ ERROR duplicate definitions with name `abc` +LL | | //~| hard error +LL | | false +LL | | } + | |_____^ duplicate definitions for `abc` +... +LL | / fn abc() -> bool { +LL | | true +LL | | } + | |_____- other definition for `abc` + | + = 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 #56484 <https://github.com/rust-lang/rust/issues/56484> + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/issues/issue-37550.rs b/src/test/ui/issues/issue-37550.rs index af1f6ef5ed4..a2f40b3f539 100644 --- a/src/test/ui/issues/issue-37550.rs +++ b/src/test/ui/issues/issue-37550.rs @@ -8,15 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(const_fn)] - const fn x() { - let t = true; - //~^ ERROR let bindings in constant functions are unstable - //~| ERROR statements in constant functions are unstable + let t = true; //~ ERROR local variables in const fn let x = || t; - //~^ ERROR let bindings in constant functions are unstable - //~| ERROR statements in constant functions are unstable } fn main() {} diff --git a/src/test/ui/issues/issue-37550.stderr b/src/test/ui/issues/issue-37550.stderr index 7468510de6a..5a7d1ad043e 100644 --- a/src/test/ui/issues/issue-37550.stderr +++ b/src/test/ui/issues/issue-37550.stderr @@ -1,35 +1,8 @@ -error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/issue-37550.rs:14:13 +error: local variables in const fn are unstable + --> $DIR/issue-37550.rs:12:9 | -LL | let t = true; - | ^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable - -error[E0658]: statements in constant functions are unstable (see issue #48821) - --> $DIR/issue-37550.rs:14:13 - | -LL | let t = true; - | ^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable - -error[E0658]: let bindings in constant functions are unstable (see issue #48821) - --> $DIR/issue-37550.rs:17:13 - | -LL | let x = || t; - | ^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable - -error[E0658]: statements in constant functions are unstable (see issue #48821) - --> $DIR/issue-37550.rs:17:13 - | -LL | let x = || t; - | ^^^^ - | - = help: add #![feature(const_let)] to the crate attributes to enable +LL | let t = true; //~ ERROR local variables in const fn + | ^ -error: aborting due to 4 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-56199.rs b/src/test/ui/issues/issue-56199.rs new file mode 100644 index 00000000000..83d4e31b5d1 --- /dev/null +++ b/src/test/ui/issues/issue-56199.rs @@ -0,0 +1,23 @@ + +enum Foo {} +struct Bar {} + +impl Foo { + fn foo() { + let _ = Self; + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + let _ = Self(); + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + } +} + +impl Bar { + fn bar() { + let _ = Self; + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + let _ = Self(); + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-56199.stderr b/src/test/ui/issues/issue-56199.stderr new file mode 100644 index 00000000000..6e3c7fd17b4 --- /dev/null +++ b/src/test/ui/issues/issue-56199.stderr @@ -0,0 +1,30 @@ +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/issue-56199.rs:7:17 + | +LL | let _ = Self; + | ^^^^ + | + = note: did you mean to use one of the enum's variants? + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/issue-56199.rs:9:17 + | +LL | let _ = Self(); + | ^^^^ + | + = note: did you mean to use one of the enum's variants? + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/issue-56199.rs:16:17 + | +LL | let _ = Self; + | ^^^^ did you mean `Self { /* fields */ }`? + +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/issue-56199.rs:18:17 + | +LL | let _ = Self(); + | ^^^^ did you mean `Self { /* fields */ }`? + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/issues/issue-56835.rs b/src/test/ui/issues/issue-56835.rs new file mode 100644 index 00000000000..c16550e3701 --- /dev/null +++ b/src/test/ui/issues/issue-56835.rs @@ -0,0 +1,10 @@ + +pub struct Foo {} + +impl Foo { + fn bar(Self(foo): Self) {} + //~^ ERROR the `Self` constructor can only be used with tuple or unit structs + //~^^ ERROR expected tuple struct/variant, found self constructor `Self` [E0164] +} + +fn main() {} diff --git a/src/test/ui/issues/issue-56835.stderr b/src/test/ui/issues/issue-56835.stderr new file mode 100644 index 00000000000..b7c3b142ec4 --- /dev/null +++ b/src/test/ui/issues/issue-56835.stderr @@ -0,0 +1,15 @@ +error: the `Self` constructor can only be used with tuple or unit structs + --> $DIR/issue-56835.rs:5:12 + | +LL | fn bar(Self(foo): Self) {} + | ^^^^^^^^^ did you mean `Self { /* fields */ }`? + +error[E0164]: expected tuple struct/variant, found self constructor `Self` + --> $DIR/issue-56835.rs:5:12 + | +LL | fn bar(Self(foo): Self) {} + | ^^^^^^^^^ not a tuple variant or struct + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0164`. diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr index a8b0e3e4250..6b9e1dc7057 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr @@ -55,6 +55,7 @@ note: lint level defined here LL | #![warn(unused)] // UI tests pass `-A unused` (#43896) | ^^^^^^ = note: #[warn(unused_assignments)] implied by #[warn(unused)] + = help: maybe it is overwritten before being read? warning: unused variable: `fire` --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:54:32 diff --git a/src/test/ui/liveness/liveness-dead.stderr b/src/test/ui/liveness/liveness-dead.stderr index 6709fee0abb..6e43cccdccf 100644 --- a/src/test/ui/liveness/liveness-dead.stderr +++ b/src/test/ui/liveness/liveness-dead.stderr @@ -9,24 +9,31 @@ note: lint level defined here | LL | #![deny(unused_assignments)] | ^^^^^^^^^^^^^^^^^^ + = help: maybe it is overwritten before being read? error: value assigned to `x` is never read --> $DIR/liveness-dead.rs:27:5 | LL | x = 4; //~ ERROR: value assigned to `x` is never read | ^ + | + = help: maybe it is overwritten before being read? error: value passed to `x` is never read --> $DIR/liveness-dead.rs:30:11 | LL | fn f4(mut x: i32) { //~ ERROR: value passed to `x` is never read | ^ + | + = help: maybe it is overwritten before being read? error: value assigned to `x` is never read --> $DIR/liveness-dead.rs:37:5 | LL | x = 4; //~ ERROR: value assigned to `x` is never read | ^ + | + = help: maybe it is overwritten before being read? error: aborting due to 4 previous errors diff --git a/src/test/ui/liveness/liveness-unused.stderr b/src/test/ui/liveness/liveness-unused.stderr index 2846f242fbe..35ccc79a19a 100644 --- a/src/test/ui/liveness/liveness-unused.stderr +++ b/src/test/ui/liveness/liveness-unused.stderr @@ -60,6 +60,7 @@ note: lint level defined here | LL | #![deny(unused_assignments)] | ^^^^^^^^^^^^^^^^^^ + = help: maybe it is overwritten before being read? error: variable `z` is assigned to, but never used --> $DIR/liveness-unused.rs:47:13 @@ -106,6 +107,8 @@ error: value assigned to `x` is never read | LL | x = 0; //~ ERROR value assigned to `x` is never read | ^ + | + = help: maybe it is overwritten before being read? error: aborting due to 13 previous errors diff --git a/src/test/ui/nll/match-on-borrowed.rs b/src/test/ui/nll/match-on-borrowed.rs index 6a8ce03e8fd..edce2b185df 100644 --- a/src/test/ui/nll/match-on-borrowed.rs +++ b/src/test/ui/nll/match-on-borrowed.rs @@ -46,9 +46,9 @@ fn enum_example(mut e: E) { E::V(ref mut x, _) => x, E::W => panic!(), }; - match e { // OK, no access of borrowed data + match e { // Don't know that E uses a tag for its discriminant _ if false => (), - E::V(_, r) => (), + E::V(_, r) => (), //~ ERROR E::W => (), } x; @@ -59,9 +59,9 @@ fn indirect_enum_example(mut f: &mut E) { E::V(ref mut x, _) => x, E::W => panic!(), }; - match f { // OK, no access of borrowed data + match f { // Don't know that E uses a tag for its discriminant _ if false => (), - E::V(_, r) => (), + E::V(_, r) => (), //~ ERROR E::W => (), } x; diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr index cdff29d44b8..2d34dd7805d 100644 --- a/src/test/ui/nll/match-on-borrowed.stderr +++ b/src/test/ui/nll/match-on-borrowed.stderr @@ -1,3 +1,27 @@ +error[E0503]: cannot use `e` because it was mutably borrowed + --> $DIR/match-on-borrowed.rs:51:9 + | +LL | E::V(ref mut x, _) => x, + | --------- borrow of `e.0` occurs here +... +LL | E::V(_, r) => (), //~ ERROR + | ^^^^^^^^^^ use of borrowed `e.0` +... +LL | x; + | - borrow later used here + +error[E0503]: cannot use `*f` because it was mutably borrowed + --> $DIR/match-on-borrowed.rs:64:9 + | +LL | E::V(ref mut x, _) => x, + | --------- borrow of `f.0` occurs here +... +LL | E::V(_, r) => (), //~ ERROR + | ^^^^^^^^^^ use of borrowed `f.0` +... +LL | x; + | - borrow later used here + error[E0503]: cannot use `t` because it was mutably borrowed --> $DIR/match-on-borrowed.rs:82:9 | @@ -16,7 +40,7 @@ error[E0381]: use of possibly uninitialized variable: `n` LL | match n {} //~ ERROR | ^ use of possibly uninitialized `n` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors Some errors occurred: E0381, E0503. For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/rfc-2166-underscore-imports/auxiliary/underscore-imports.rs b/src/test/ui/rfc-2166-underscore-imports/auxiliary/underscore-imports.rs index 70de9167332..c335336bee8 100644 --- a/src/test/ui/rfc-2166-underscore-imports/auxiliary/underscore-imports.rs +++ b/src/test/ui/rfc-2166-underscore-imports/auxiliary/underscore-imports.rs @@ -1,5 +1,3 @@ -#![feature(underscore_imports)] - #[macro_export] macro_rules! do_nothing { () => () diff --git a/src/test/ui/rfc-2166-underscore-imports/basic.rs b/src/test/ui/rfc-2166-underscore-imports/basic.rs index 64a8d0720d6..93b246fb92d 100644 --- a/src/test/ui/rfc-2166-underscore-imports/basic.rs +++ b/src/test/ui/rfc-2166-underscore-imports/basic.rs @@ -11,7 +11,6 @@ // compile-pass // aux-build:underscore-imports.rs -#![feature(underscore_imports)] #![warn(unused_imports, unused_extern_crates)] #[macro_use] diff --git a/src/test/ui/rfc-2166-underscore-imports/basic.stderr b/src/test/ui/rfc-2166-underscore-imports/basic.stderr index e1fe5cc0783..f2b8cc411ff 100644 --- a/src/test/ui/rfc-2166-underscore-imports/basic.stderr +++ b/src/test/ui/rfc-2166-underscore-imports/basic.stderr @@ -1,17 +1,17 @@ warning: unused import: `m::Tr1 as _` - --> $DIR/basic.rs:37:9 + --> $DIR/basic.rs:36:9 | LL | use m::Tr1 as _; //~ WARN unused import | ^^^^^^^^^^^ | note: lint level defined here - --> $DIR/basic.rs:15:9 + --> $DIR/basic.rs:14:9 | LL | #![warn(unused_imports, unused_extern_crates)] | ^^^^^^^^^^^^^^ warning: unused import: `S as _` - --> $DIR/basic.rs:38:9 + --> $DIR/basic.rs:37:9 | LL | use S as _; //~ WARN unused import | ^^^^^^ diff --git a/src/test/ui/rfc-2166-underscore-imports/duplicate.rs b/src/test/ui/rfc-2166-underscore-imports/duplicate.rs index 92615c4966d..95f7cae0b87 100644 --- a/src/test/ui/rfc-2166-underscore-imports/duplicate.rs +++ b/src/test/ui/rfc-2166-underscore-imports/duplicate.rs @@ -1,8 +1,6 @@ // compile-pass // aux-build:duplicate.rs -#![feature(underscore_imports)] - extern crate duplicate; #[duplicate::duplicate] diff --git a/src/test/ui/rfc-2166-underscore-imports/unused-2018.rs b/src/test/ui/rfc-2166-underscore-imports/unused-2018.rs index 611eb3c67ca..d06a26a5f11 100644 --- a/src/test/ui/rfc-2166-underscore-imports/unused-2018.rs +++ b/src/test/ui/rfc-2166-underscore-imports/unused-2018.rs @@ -1,6 +1,5 @@ // edition:2018 -#![feature(underscore_imports)] #![deny(unused_imports)] mod multi_segment { diff --git a/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr b/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr index 02b29b3f4fe..4163c287607 100644 --- a/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr +++ b/src/test/ui/rfc-2166-underscore-imports/unused-2018.stderr @@ -1,17 +1,17 @@ error: unused import: `core::any` - --> $DIR/unused-2018.rs:7:9 + --> $DIR/unused-2018.rs:6:9 | LL | use core::any; //~ ERROR unused import: `core::any` | ^^^^^^^^^ | note: lint level defined here - --> $DIR/unused-2018.rs:4:9 + --> $DIR/unused-2018.rs:3:9 | LL | #![deny(unused_imports)] | ^^^^^^^^^^^^^^ error: unused import: `core` - --> $DIR/unused-2018.rs:11:9 + --> $DIR/unused-2018.rs:10:9 | LL | use core; //~ ERROR unused import: `core` | ^^^^ diff --git a/src/test/ui/rust-2018/future-proofing-locals.rs b/src/test/ui/rust-2018/future-proofing-locals.rs index d2e6dbbb954..4f0cadaae5d 100644 --- a/src/test/ui/rust-2018/future-proofing-locals.rs +++ b/src/test/ui/rust-2018/future-proofing-locals.rs @@ -1,6 +1,6 @@ // edition:2018 -#![feature(uniform_paths, underscore_imports)] +#![feature(uniform_paths)] mod T { pub struct U; diff --git a/src/test/ui/rust-2018/uniform-paths/macro-rules.rs b/src/test/ui/rust-2018/uniform-paths/macro-rules.rs index e8098a46790..fc433c201b0 100644 --- a/src/test/ui/rust-2018/uniform-paths/macro-rules.rs +++ b/src/test/ui/rust-2018/uniform-paths/macro-rules.rs @@ -2,7 +2,7 @@ // For the time being `macro_rules` items are treated as *very* private... -#![feature(underscore_imports, decl_macro, uniform_paths)] +#![feature(decl_macro, uniform_paths)] mod m1 { macro_rules! legacy_macro { () => () } diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs index 2a2d35e7bd9..31ec8a7dc1c 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs @@ -54,8 +54,14 @@ fn main() { simd_select(z, z, z); //~^ ERROR mask element type is `f32`, expected `i_` + simd_select(m4, 0u32, 1u32); + //~^ ERROR found non-SIMD `u32` + simd_select_bitmask(0u8, x, x); //~^ ERROR mask length `8` != other vector length `4` + // + simd_select_bitmask(0u8, 1u32, 2u32); + //~^ ERROR found non-SIMD `u32` simd_select_bitmask(0.0f32, x, x); //~^ ERROR `f32` is not an integral type diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr index 584f3d53921..05317da2475 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr @@ -16,24 +16,36 @@ error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element LL | simd_select(z, z, z); | ^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4` +error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32` --> $DIR/simd-intrinsic-generic-select.rs:57:9 | +LL | simd_select(m4, 0u32, 1u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4` + --> $DIR/simd-intrinsic-generic-select.rs:60:9 + | LL | simd_select_bitmask(0u8, x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32` + --> $DIR/simd-intrinsic-generic-select.rs:63:9 + | +LL | simd_select_bitmask(0u8, 1u32, 2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `f32` is not an integral type - --> $DIR/simd-intrinsic-generic-select.rs:60:9 + --> $DIR/simd-intrinsic-generic-select.rs:66:9 | LL | simd_select_bitmask(0.0f32, x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: `&str` is not an integral type - --> $DIR/simd-intrinsic-generic-select.rs:63:9 + --> $DIR/simd-intrinsic-generic-select.rs:69:9 | LL | simd_select_bitmask("x", x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/suggestions/path-display.rs b/src/test/ui/suggestions/path-display.rs new file mode 100644 index 00000000000..62fc9e79f7a --- /dev/null +++ b/src/test/ui/suggestions/path-display.rs @@ -0,0 +1,7 @@ +use std::path::Path; + +fn main() { + let path = Path::new("/tmp/foo/bar.txt"); + println!("{}", path); + //~^ ERROR E0277 +} diff --git a/src/test/ui/suggestions/path-display.stderr b/src/test/ui/suggestions/path-display.stderr new file mode 100644 index 00000000000..39d236af4f3 --- /dev/null +++ b/src/test/ui/suggestions/path-display.stderr @@ -0,0 +1,14 @@ +error[E0277]: `std::path::Path` doesn't implement `std::fmt::Display` + --> $DIR/path-display.rs:5:20 + | +LL | println!("{}", path); + | ^^^^ `std::path::Path` cannot be formatted with the default formatter; call `.display()` on it + | + = help: the trait `std::fmt::Display` is not implemented for `std::path::Path` + = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data + = note: required because of the requirements on the impl of `std::fmt::Display` for `&std::path::Path` + = note: required by `std::fmt::Display::fmt` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/target-feature-gate.rs b/src/test/ui/target-feature-gate.rs index 8a045884cae..2d0fb78897d 100644 --- a/src/test/ui/target-feature-gate.rs +++ b/src/test/ui/target-feature-gate.rs @@ -24,7 +24,6 @@ // gate-test-mips_target_feature // gate-test-mmx_target_feature // gate-test-wasm_target_feature -// min-llvm-version 6.0 #[target_feature(enable = "avx512bw")] //~^ ERROR: currently unstable diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature-gate.stderr index f18bebc0c29..24141d0064f 100644 --- a/src/test/ui/target-feature-gate.stderr +++ b/src/test/ui/target-feature-gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable (see issue #44839) - --> $DIR/target-feature-gate.rs:29:18 + --> $DIR/target-feature-gate.rs:28:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy b/src/tools/clippy -Subproject b7a431ea1ddb96a396921bf9b5f2f6d8690cd47 +Subproject a416c5e0f7c4c9473069a58410d3ec3e86b1ac0 diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 00383998242..8b3023e63df 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -873,3 +873,29 @@ fn parse_normalization_string(line: &mut &str) -> Option<String> { *line = &line[end + 1..]; Some(result) } + +#[test] +fn test_parse_normalization_string() { + let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits)\"."; + let first = parse_normalization_string(&mut s); + assert_eq!(first, Some("something (32 bits)".to_owned())); + assert_eq!(s, " -> \"something ($WORD bits)\"."); + + // Nothing to normalize (No quotes) + let mut s = "normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)."; + let first = parse_normalization_string(&mut s); + assert_eq!(first, None); + assert_eq!(s, r#"normalize-stderr-32bit: something (32 bits) -> something ($WORD bits)."#); + + // Nothing to normalize (Only a single quote) + let mut s = "normalize-stderr-32bit: \"something (32 bits) -> something ($WORD bits)."; + let first = parse_normalization_string(&mut s); + assert_eq!(first, None); + assert_eq!(s, "normalize-stderr-32bit: \"something (32 bits) -> something ($WORD bits)."); + + // Nothing to normalize (Three quotes) + let mut s = "normalize-stderr-32bit: \"something (32 bits)\" -> \"something ($WORD bits)."; + let first = parse_normalization_string(&mut s); + assert_eq!(first, Some("something (32 bits)".to_owned())); + assert_eq!(s, " -> \"something ($WORD bits)."); +} diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 2a716970ca7..381d808e802 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -86,6 +86,8 @@ pub fn matches_os(triple: &str, name: &str) -> bool { } 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 { @@ -151,3 +153,29 @@ impl PathBufExt for PathBuf { } } } + +#[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")); +} + +#[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")); +} diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index e6bf9a28572..1aa647a6a1b 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -137,7 +137,6 @@ fn check(cache: &mut Cache, file.ends_with("symbol/struct.InternedString.html") || file.ends_with("ast/struct.ThinVec.html") || file.ends_with("util/struct.ThinVec.html") || - file.ends_with("util/struct.RcSlice.html") || file.ends_with("layout/struct.TyLayout.html") || file.ends_with("humantime/struct.Timestamp.html") || file.ends_with("log/index.html") || diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index a65d263d2e3..4ade87f5d65 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -34,16 +34,6 @@ MAINTAINERS = { 'rust-by-example': '@steveklabnik @marioidival @projektir', } -EMOJI = { - 'miri': '🛰️', - 'clippy-driver': '📎', - 'rls': '💻', - 'rustfmt': '📝', - 'book': '📖', - 'nomicon': '👿', - 'reference': '📚', - 'rust-by-example': '👩🏫', -} def read_current_status(current_commit, path): '''Reads build status of `current_commit` from content of `history/*.tsv` @@ -73,12 +63,13 @@ def update_latest( } slug = 'rust-lang/rust' - long_message = textwrap.dedent('''\ + message = textwrap.dedent('''\ + 📣 Toolstate changed by {}! + Tested on commit {}@{}. Direct link to PR: <{}> - ''').format(slug, current_commit, relevant_pr_url) - emoji_status = [] + ''').format(relevant_pr_number, slug, current_commit, relevant_pr_url) anything_changed = False for status in latest: tool = status['tool'] @@ -90,18 +81,12 @@ def update_latest( status[os] = new if new > old: changed = True - long_message += '🎉 {} on {}: {} → {}.\n' \ - .format(tool, os, old, new) - emoji = "{}🎉".format(EMOJI.get(tool)) - if msg not in emoji_status: - emoji_status += [msg] + message += '🎉 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \ + .format(tool, os, old, new, MAINTAINERS.get(tool)) elif new < old: changed = True - long_message += '💔 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \ + message += '💔 {} on {}: {} → {} (cc {}, @rust-lang/infra).\n' \ .format(tool, os, old, new, MAINTAINERS.get(tool)) - emoji = "{}💔".format(EMOJI.get(tool)) - if msg not in emoji_status: - emoji_status += [msg] if changed: status['commit'] = current_commit @@ -111,9 +96,6 @@ def update_latest( if not anything_changed: return '' - short_message = "📣 Toolstate changed by {}! ({})" - .format(relevant_pr_number, '/'.join(emoji_status)) - message = short_message + "\n\n" + long_message f.seek(0) f.truncate(0) json.dump(latest, f, indent=4, separators=(',', ': ')) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 2b5cff6e07b..d1e4387166c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -79,6 +79,7 @@ const WHITELIST: &[Crate] = &[ Crate("chalk-macros"), Crate("cloudabi"), Crate("cmake"), + Crate("compiler_builtins"), Crate("crc"), Crate("crc32fast"), Crate("crossbeam-deque"), |
