diff options
Diffstat (limited to 'src')
601 files changed, 11639 insertions, 4697 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock index e7896d247b4..e5297d1482e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -13,14 +13,12 @@ dependencies = [ "compiler_builtins 0.0.0", "core 0.0.0", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "std_unicode 0.0.0", ] [[package]] name = "alloc_jemalloc" version = "0.0.0" dependencies = [ - "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -33,7 +31,6 @@ dependencies = [ name = "alloc_system" version = "0.0.0" dependencies = [ - "alloc 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", "dlmalloc 0.0.0", @@ -286,11 +283,11 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.191" +version = "0.0.193" dependencies = [ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_lints 0.0.191", + "clippy_lints 0.0.193", "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -306,7 +303,7 @@ version = "0.2.0" [[package]] name = "clippy_lints" -version = "0.0.191" +version = "0.0.193" dependencies = [ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -543,7 +540,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "dlmalloc" version = "0.0.0" dependencies = [ - "alloc 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1579,7 +1575,7 @@ version = "0.126.0" dependencies = [ "cargo 0.27.0", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.191", + "clippy_lints 0.0.193", "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 6701f58ba8e..3dd9b684059 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -279,6 +279,10 @@ fn main() { cmd.arg("--color=always"); } + if env::var_os("RUSTC_DENY_WARNINGS").is_some() { + cmd.arg("-Dwarnings"); + } + if verbose > 1 { eprintln!("rustc command: {:?}", cmd); eprintln!("sysroot: {:?}", sysroot); diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 3f5ec4933d0..7ff64af9196 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -698,6 +698,11 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); + // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful. + if self.config.deny_warnings && !(mode == Mode::Libstd && stage == 0) { + cargo.env("RUSTC_DENY_WARNINGS", "1"); + } + // Throughout the build Cargo can execute a number of build scripts // compiling C/C++ code and we need to pass compilers, archivers, flags, etc // obtained previously to those build scripts. diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 9cc18464fea..b411b19bd53 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1167,7 +1167,9 @@ pub fn stream_cargo( cargo.arg("--message-format").arg("json") .stdout(Stdio::piped()); - if stderr_isatty() && build.ci_env == CiEnv::None { + if stderr_isatty() && build.ci_env == CiEnv::None && + // if the terminal is reported as dumb, then we don't want to enable color for rustc + env::var_os("TERM").map(|t| t != *"dumb").unwrap_or(true) { // since we pass message-format=json to cargo, we need to tell the rustc // wrapper to give us colored output if necessary. This is because we // only want Cargo's JSON output, not rustcs. diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 95baf4f8cca..239316d45c4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -71,6 +71,8 @@ pub struct Config { pub incremental: bool, pub dry_run: bool, + pub deny_warnings: bool, + // llvm codegen options pub llvm_enabled: bool, pub llvm_assertions: bool, @@ -301,6 +303,7 @@ struct Rust { codegen_backends_dir: Option<String>, wasm_syscall: Option<bool>, lld: Option<bool>, + deny_warnings: Option<bool>, } /// TOML representation of how each build target is configured. @@ -340,6 +343,7 @@ impl Config { config.test_miri = false; config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")]; config.rust_codegen_backends_dir = "codegen-backends".to_owned(); + config.deny_warnings = true; // set by bootstrap.py config.src = env::var_os("SRC").map(PathBuf::from).expect("'SRC' to be set"); @@ -366,6 +370,9 @@ impl Config { config.incremental = flags.incremental; config.dry_run = flags.dry_run; config.keep_stage = flags.keep_stage; + if let Some(value) = flags.warnings { + config.deny_warnings = value; + } if config.dry_run { let dir = config.out.join("tmp-dry-run"); @@ -511,6 +518,7 @@ impl Config { config.rustc_default_linker = rust.default_linker.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); + set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings)); if let Some(ref backends) = rust.codegen_backends { config.rust_codegen_backends = backends.iter() diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index ef902c68d12..3eb9dca2aa8 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -42,6 +42,9 @@ pub struct Flags { pub exclude: Vec<PathBuf>, pub rustc_error_format: Option<String>, pub dry_run: bool, + + // true => deny + pub warnings: Option<bool>, } pub enum Subcommand { @@ -118,6 +121,8 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`"); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); + opts.optopt("", "warnings", "if value is deny, will deny warnings, otherwise use default", + "VALUE"); opts.optopt("", "error-format", "rustc error format", "FORMAT"); // fn usage() @@ -374,6 +379,7 @@ Arguments: incremental: matches.opt_present("incremental"), exclude: split(matches.opt_strs("exclude")) .into_iter().map(|p| p.into()).collect::<Vec<_>>(), + warnings: matches.opt_str("warnings").map(|v| v == "deny"), } } } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 5a12afd03e1..2f9953330f4 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - use std::fs::File; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -use std::{fs, env}; use std::time::{SystemTime, UNIX_EPOCH}; +use std::{env, fs}; /// A helper macro to `unwrap` a result except also print out details like: /// @@ -26,10 +24,12 @@ use std::time::{SystemTime, UNIX_EPOCH}; /// using a `Result` with `try!`, but this may change one day... #[macro_export] macro_rules! t { - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {}", stringify!($e), e), - }) + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; } pub fn run(cmd: &mut Command) { @@ -46,14 +46,17 @@ pub fn run_silent(cmd: &mut Command) { pub fn try_run_silent(cmd: &mut Command) -> bool { let status = match cmd.status() { Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", - cmd, e)), + Err(e) => fail(&format!( + "failed to execute command: {:?}\nerror: {}", + cmd, e + )), }; if !status.success() { - println!("\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n", - cmd, - status); + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n", + cmd, status + ); } status.success() } @@ -67,18 +70,22 @@ pub fn run_suppressed(cmd: &mut Command) { pub fn try_run_suppressed(cmd: &mut Command) -> bool { let output = match cmd.output() { Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", - cmd, e)), + Err(e) => fail(&format!( + "failed to execute command: {:?}\nerror: {}", + cmd, e + )), }; if !output.status.success() { - println!("\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n\ - stdout ----\n{}\n\ - stderr ----\n{}\n\n", - cmd, - output.status, - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr)); + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n\ + stdout ----\n{}\n\ + stderr ----\n{}\n\n", + cmd, + output.status, + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); } output.status.success() } @@ -94,9 +101,9 @@ pub fn gnu_target(target: &str) -> String { } pub fn make(host: &str) -> PathBuf { - if host.contains("bitrig") || host.contains("dragonfly") || - host.contains("freebsd") || host.contains("netbsd") || - host.contains("openbsd") { + if host.contains("bitrig") || host.contains("dragonfly") || host.contains("freebsd") + || host.contains("netbsd") || host.contains("openbsd") + { PathBuf::from("gmake") } else { PathBuf::from("make") @@ -106,23 +113,27 @@ pub fn make(host: &str) -> PathBuf { pub fn output(cmd: &mut Command) -> String { let output = match cmd.stderr(Stdio::inherit()).output() { Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", - cmd, e)), + Err(e) => fail(&format!( + "failed to execute command: {:?}\nerror: {}", + cmd, e + )), }; if !output.status.success() { - panic!("command did not execute successfully: {:?}\n\ - expected success, got: {}", - cmd, - output.status); + panic!( + "command did not execute successfully: {:?}\n\ + expected success, got: {}", + cmd, output.status + ); } String::from_utf8(output.stdout).unwrap() } pub fn rerun_if_changed_anything_in_dir(dir: &Path) { - let mut stack = dir.read_dir().unwrap() - .map(|e| e.unwrap()) - .filter(|e| &*e.file_name() != ".git") - .collect::<Vec<_>>(); + let mut stack = dir.read_dir() + .unwrap() + .map(|e| e.unwrap()) + .filter(|e| &*e.file_name() != ".git") + .collect::<Vec<_>>(); while let Some(entry) = stack.pop() { let path = entry.path(); if entry.file_type().unwrap().is_dir() { @@ -135,7 +146,9 @@ pub fn rerun_if_changed_anything_in_dir(dir: &Path) { /// Returns the last-modified time for `path`, or zero if it doesn't exist. pub fn mtime(path: &Path) -> SystemTime { - fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH) + fs::metadata(path) + .and_then(|f| f.modified()) + .unwrap_or(UNIX_EPOCH) } /// Returns whether `dst` is up to date given that the file or files in `src` @@ -176,11 +189,12 @@ impl Drop for NativeLibBoilerplate { // If Err is returned, then everything is up-to-date and further build actions can be skipped. // Timestamps are created automatically when the result of `native_lib_boilerplate` goes out // of scope, so all the build actions should be completed until then. -pub fn native_lib_boilerplate(src_name: &str, - out_name: &str, - link_name: &str, - search_subdir: &str) - -> Result<NativeLibBoilerplate, ()> { +pub fn native_lib_boilerplate( + src_name: &str, + out_name: &str, + link_name: &str, + search_subdir: &str, +) -> Result<NativeLibBoilerplate, ()> { let current_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); let src_dir = current_dir.join("..").join(src_name); rerun_if_changed_anything_in_dir(&src_dir); @@ -193,11 +207,17 @@ pub fn native_lib_boilerplate(src_name: &str, } else { println!("cargo:rustc-link-lib=static={}", link_name); } - println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display()); + println!( + "cargo:rustc-link-search=native={}", + out_dir.join(search_subdir).display() + ); let timestamp = out_dir.join("rustbuild.timestamp"); if !up_to_date(Path::new("build.rs"), ×tamp) || !up_to_date(&src_dir, ×tamp) { - Ok(NativeLibBoilerplate { src_dir: src_dir, out_dir: out_dir }) + Ok(NativeLibBoilerplate { + src_dir: src_dir, + out_dir: out_dir, + }) } else { Err(()) } @@ -215,10 +235,12 @@ pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoiler ), _ => return Err(()), }; - native_lib_boilerplate("libcompiler_builtins/compiler-rt", - sanitizer_name, - &link_name, - search_path) + native_lib_boilerplate( + "libcompiler_builtins/compiler-rt", + sanitizer_name, + &link_name, + search_path, + ) } fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index fb0bd06ce30..f87ba8fe4e6 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -40,7 +40,7 @@ if [ ! -d $MUSL ]; then fi cd $MUSL -./configure --disable-shared --prefix=/musl-$TAG $@ +./configure --enable-optimize --enable-debug --disable-shared --prefix=/musl-$TAG $@ if [ "$TAG" = "i586" -o "$TAG" = "i686" ]; then hide_output make -j$(nproc) AR=ar RANLIB=ranlib else diff --git a/src/ci/docker/wasm32-unknown/Dockerfile b/src/ci/docker/wasm32-unknown/Dockerfile index 6c0ec1ad9d4..853923ad947 100644 --- a/src/ci/docker/wasm32-unknown/Dockerfile +++ b/src/ci/docker/wasm32-unknown/Dockerfile @@ -34,4 +34,3 @@ ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \ src/test/mir-opt \ src/test/codegen-units \ src/libcore \ - src/libstd_unicode/ \ diff --git a/src/dlmalloc b/src/dlmalloc -Subproject 9b2dcac06c3e23235f8997b3c5f2325a6d3382d +Subproject c99638dc2ecfc750cc1656f6edb2bd062c1e098 diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 6a8f0a27e9a58c55c89d07bc43a176fdae5e051 +Subproject 3c56329d1bd9038e5341f1962bcd8d043312a71 diff --git a/src/doc/unstable-book/src/language-features/catch-expr.md b/src/doc/unstable-book/src/language-features/catch-expr.md index fbd213dca56..247333d841a 100644 --- a/src/doc/unstable-book/src/language-features/catch-expr.md +++ b/src/doc/unstable-book/src/language-features/catch-expr.md @@ -15,16 +15,16 @@ expression creates a new scope one can use the `?` operator in. use std::num::ParseIntError; let result: Result<i32, ParseIntError> = do catch { - Ok("1".parse::<i32>()? + "1".parse::<i32>()? + "2".parse::<i32>()? - + "3".parse::<i32>()?) + + "3".parse::<i32>()? }; assert_eq!(result, Ok(6)); let result: Result<i32, ParseIntError> = do catch { - Ok("1".parse::<i32>()? + "1".parse::<i32>()? + "foo".parse::<i32>()? - + "3".parse::<i32>()?) + + "3".parse::<i32>()? }; assert!(result.is_err()); ``` diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md index b3e6925b666..031b6347445 100644 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -29,16 +29,17 @@ looks like: ```rust #![feature(global_allocator, allocator_api, heap_api)] -use std::heap::{Alloc, System, Layout, AllocErr}; +use std::alloc::{GlobalAlloc, System, Layout, Opaque}; +use std::ptr::NonNull; struct MyAllocator; -unsafe impl<'a> Alloc for &'a MyAllocator { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { +unsafe impl GlobalAlloc for MyAllocator { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { System.alloc(layout) } - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { System.dealloc(ptr, layout) } } diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index c5167418614..6a7aea7f1c2 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -243,7 +243,7 @@ the source code. - `usize`: `libcore/num/mod.rs` - `f32`: `libstd/f32.rs` - `f64`: `libstd/f64.rs` - - `char`: `libstd_unicode/char.rs` + - `char`: `libcore/char.rs` - `slice`: `liballoc/slice.rs` - `str`: `liballoc/str.rs` - `const_ptr`: `libcore/ptr.rs` diff --git a/src/doc/unstable-book/src/language-features/repr-packed.md b/src/doc/unstable-book/src/language-features/repr-packed.md new file mode 100644 index 00000000000..2dd763d04b0 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/repr-packed.md @@ -0,0 +1,8 @@ +# `repr_packed` + +The tracking issue for this feature is [#33158] + +[#33158]: https://github.com/rust-lang/rust/issues/33158 + +------------------------ + diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 2eb8ea12604..6383bd1e941 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -9,7 +9,6 @@ path = "lib.rs" [dependencies] core = { path = "../libcore" } -std_unicode = { path = "../libstd_unicode" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } [dev-dependencies] diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs new file mode 100644 index 00000000000..68a617e0ffe --- /dev/null +++ b/src/liballoc/alloc.rs @@ -0,0 +1,215 @@ +// Copyright 2014-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. + +#![unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked \ + slightly, especially to possibly take into account the \ + types being stored to make room for a future \ + tracing garbage collector", + issue = "32838")] + +use core::intrinsics::{min_align_of_val, size_of_val}; +use core::ptr::NonNull; +use core::usize; + +#[doc(inline)] +pub use core::alloc::*; + +#[cfg(stage0)] +extern "Rust" { + #[allocator] + #[rustc_allocator_nounwind] + fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; + #[cold] + #[rustc_allocator_nounwind] + fn __rust_oom(err: *const u8) -> !; + #[rustc_allocator_nounwind] + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); + #[rustc_allocator_nounwind] + fn __rust_realloc(ptr: *mut u8, + old_size: usize, + old_align: usize, + new_size: usize, + new_align: usize, + err: *mut u8) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; +} + +#[cfg(not(stage0))] +extern "Rust" { + #[allocator] + #[rustc_allocator_nounwind] + fn __rust_alloc(size: usize, align: usize) -> *mut u8; + #[cold] + #[rustc_allocator_nounwind] + fn __rust_oom() -> !; + #[rustc_allocator_nounwind] + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); + #[rustc_allocator_nounwind] + fn __rust_realloc(ptr: *mut u8, + old_size: usize, + align: usize, + new_size: usize) -> *mut u8; + #[rustc_allocator_nounwind] + fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; +} + +#[derive(Copy, Clone, Default, Debug)] +pub struct Global; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] +pub type Heap = Global; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] +#[allow(non_upper_case_globals)] +pub const Heap: Global = Global; + +unsafe impl GlobalAlloc for Global { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + #[cfg(not(stage0))] + let ptr = __rust_alloc(layout.size(), layout.align()); + #[cfg(stage0)] + let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0); + ptr as *mut Opaque + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + __rust_dealloc(ptr as *mut u8, layout.size(), layout.align()) + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + #[cfg(not(stage0))] + let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size); + #[cfg(stage0)] + let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), + new_size, layout.align(), &mut 0); + ptr as *mut Opaque + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + #[cfg(not(stage0))] + let ptr = __rust_alloc_zeroed(layout.size(), layout.align()); + #[cfg(stage0)] + let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); + ptr as *mut Opaque + } + + #[inline] + fn oom(&self) -> ! { + unsafe { + #[cfg(not(stage0))] + __rust_oom(); + #[cfg(stage0)] + __rust_oom(&mut 0); + } + } +} + +unsafe impl Alloc for Global { + #[inline] + unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { + NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) + } + + #[inline] + unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) { + GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) + } + + #[inline] + unsafe fn realloc(&mut self, + ptr: NonNull<Opaque>, + layout: Layout, + new_size: usize) + -> Result<NonNull<Opaque>, AllocErr> + { + NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) + } + + #[inline] + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { + NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) + } + + #[inline] + fn oom(&mut self) -> ! { + GlobalAlloc::oom(self) + } +} + +/// The allocator for unique pointers. +// This function must not unwind. If it does, MIR trans will fail. +#[cfg(not(test))] +#[lang = "exchange_malloc"] +#[inline] +unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { + if size == 0 { + align as *mut u8 + } else { + let layout = Layout::from_size_align_unchecked(size, align); + let ptr = Global.alloc(layout); + if !ptr.is_null() { + ptr as *mut u8 + } else { + Global.oom() + } + } +} + +#[cfg_attr(not(test), lang = "box_free")] +#[inline] +pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) { + let size = size_of_val(&*ptr); + let align = min_align_of_val(&*ptr); + // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary. + if size != 0 { + let layout = Layout::from_size_align_unchecked(size, align); + Global.dealloc(ptr as *mut Opaque, layout); + } +} + +#[cfg(test)] +mod tests { + extern crate test; + use self::test::Bencher; + use boxed::Box; + use alloc::{Global, Alloc, Layout}; + + #[test] + fn allocate_zeroed() { + unsafe { + let layout = Layout::from_size_align(1024, 1).unwrap(); + let ptr = Global.alloc_zeroed(layout.clone()) + .unwrap_or_else(|_| Global.oom()); + + let mut i = ptr.cast::<u8>().as_ptr(); + let end = i.offset(layout.size() as isize); + while i < end { + assert_eq!(*i, 0); + i = i.offset(1); + } + Global.dealloc(ptr, layout); + } + } + + #[bench] + fn alloc_owned_small(b: &mut Bencher) { + b.iter(|| { + let _: Box<_> = box 10; + }) + } +} diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index ccf2e2768d1..225b055d8ee 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -21,7 +21,6 @@ use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; use core::borrow; use core::fmt; use core::cmp::Ordering; -use core::heap::{Alloc, Layout}; use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val, uninitialized}; use core::ops::Deref; @@ -32,7 +31,7 @@ use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; -use heap::{Heap, box_free}; +use alloc::{Global, Alloc, Layout, box_free}; use boxed::Box; use string::String; use vec::Vec; @@ -513,15 +512,13 @@ impl<T: ?Sized> Arc<T> { // Non-inlined part of `drop`. #[inline(never)] unsafe fn drop_slow(&mut self) { - let ptr = self.ptr.as_ptr(); - // Destroy the data at this time, even though we may not free the box // allocation itself (there may still be weak pointers lying around). ptr::drop_in_place(&mut self.ptr.as_mut().data); if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); - Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) } } @@ -555,11 +552,11 @@ impl<T: ?Sized> Arc<T> { let layout = Layout::for_value(&*fake_ptr); - let mem = Heap.alloc(layout) - .unwrap_or_else(|e| Heap.oom(e)); + let mem = Global.alloc(layout) + .unwrap_or_else(|_| Global.oom()); // Initialize the real ArcInner - let inner = set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>; + let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner<T>; ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); @@ -626,7 +623,7 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> { // In the event of a panic, elements that have been written // into the new ArcInner will be dropped, then the memory freed. struct Guard<T> { - mem: *mut u8, + mem: NonNull<u8>, elems: *mut T, layout: Layout, n_elems: usize, @@ -640,7 +637,7 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Heap.dealloc(self.mem, self.layout.clone()); + Global.dealloc(self.mem.as_opaque(), self.layout.clone()); } } } @@ -656,7 +653,7 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> { let elems = &mut (*ptr).data as *mut [T] as *mut T; let mut guard = Guard{ - mem: mem, + mem: NonNull::new_unchecked(mem), elems: elems, layout: layout, n_elems: 0, @@ -1148,8 +1145,6 @@ impl<T: ?Sized> Drop for Weak<T> { /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { - let ptr = self.ptr.as_ptr(); - // If we find out that we were the last weak pointer, then its time to // deallocate the data entirely. See the discussion in Arc::drop() about // the memory orderings @@ -1161,7 +1156,7 @@ impl<T: ?Sized> Drop for Weak<T> { if self.inner().weak.fetch_sub(1, Release) == 1 { atomic::fence(Acquire); unsafe { - Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)) + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) } } } diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 4d92fc67b2a..4f69aa6670b 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(rand)] #![feature(repr_simd)] #![feature(slice_sort_by_cached_key)] diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs index 49109d522e9..d6346662314 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -41,14 +41,13 @@ // - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges. // This implies that even an empty internal node has at least one edge. -use core::heap::{Alloc, Layout}; use core::marker::PhantomData; use core::mem; use core::ptr::{self, Unique, NonNull}; use core::slice; +use alloc::{Global, Alloc, Layout}; use boxed::Box; -use heap::Heap; const B: usize = 6; pub const MIN_LEN: usize = B - 1; @@ -237,7 +236,7 @@ impl<K, V> Root<K, V> { pub fn pop_level(&mut self) { debug_assert!(self.height > 0); - let top = self.node.ptr.as_ptr() as *mut u8; + let top = self.node.ptr; self.node = unsafe { BoxedNode::from_ptr(self.as_mut() @@ -250,7 +249,7 @@ impl<K, V> Root<K, V> { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Heap.dealloc(top, Layout::new::<InternalNode<K, V>>()); + Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::<InternalNode<K, V>>()); } } } @@ -434,9 +433,9 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> { marker::Edge > > { - let ptr = self.as_leaf() as *const LeafNode<K, V> as *const u8 as *mut u8; + let node = self.node; let ret = self.ascend().ok(); - Heap.dealloc(ptr, Layout::new::<LeafNode<K, V>>()); + Global.dealloc(node.as_opaque(), Layout::new::<LeafNode<K, V>>()); ret } } @@ -455,9 +454,9 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> { marker::Edge > > { - let ptr = self.as_internal() as *const InternalNode<K, V> as *const u8 as *mut u8; + let node = self.node; let ret = self.ascend().ok(); - Heap.dealloc(ptr, Layout::new::<InternalNode<K, V>>()); + Global.dealloc(node.as_opaque(), Layout::new::<InternalNode<K, V>>()); ret } } @@ -1239,13 +1238,13 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker:: ).correct_parent_link(); } - Heap.dealloc( - right_node.node.as_ptr() as *mut u8, + Global.dealloc( + right_node.node.as_opaque(), Layout::new::<InternalNode<K, V>>(), ); } else { - Heap.dealloc( - right_node.node.as_ptr() as *mut u8, + Global.dealloc( + right_node.node.as_opaque(), Layout::new::<LeafNode<K, V>>(), ); } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 9296a113071..faac38ca7ce 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -8,282 +8,103 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] +#![allow(deprecated)] -use core::intrinsics::{min_align_of_val, size_of_val}; -use core::mem::{self, ManuallyDrop}; -use core::usize; +pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Opaque}; +use core::alloc::Alloc as CoreAlloc; +use core::ptr::NonNull; -pub use core::heap::*; #[doc(hidden)] pub mod __core { pub use core::*; } -extern "Rust" { - #[allocator] - #[rustc_allocator_nounwind] - fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom(err: *const u8) -> !; - #[rustc_allocator_nounwind] - fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); - #[rustc_allocator_nounwind] - fn __rust_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize); - #[rustc_allocator_nounwind] - fn __rust_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8; - #[rustc_allocator_nounwind] - fn __rust_shrink_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8; -} +#[derive(Debug)] +pub struct Excess(pub *mut u8, pub usize); -#[derive(Copy, Clone, Default, Debug)] -pub struct Heap; +/// Compatibility with older versions of #[global_allocator] during bootstrap +pub unsafe trait Alloc { + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); + fn oom(&mut self, err: AllocErr) -> !; + fn usable_size(&self, layout: &Layout) -> (usize, usize); + unsafe fn realloc(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<*mut u8, AllocErr>; + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr>; + unsafe fn realloc_excess(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<Excess, AllocErr>; + unsafe fn grow_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace>; + unsafe fn shrink_in_place(&mut self, + ptr: *mut u8, + layout: Layout, + new_layout: Layout) -> Result<(), CannotReallocInPlace>; +} -unsafe impl Alloc for Heap { - #[inline] +unsafe impl<T> Alloc for T where T: CoreAlloc { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); - let ptr = __rust_alloc(layout.size(), - layout.align(), - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(ptr) - } + CoreAlloc::alloc(self, layout).map(|ptr| ptr.cast().as_ptr()) } - #[inline] - #[cold] - fn oom(&mut self, err: AllocErr) -> ! { - unsafe { - __rust_oom(&err as *const AllocErr as *const u8) - } + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + CoreAlloc::dealloc(self, ptr, layout) } - #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - __rust_dealloc(ptr, layout.size(), layout.align()) + fn oom(&mut self, _: AllocErr) -> ! { + CoreAlloc::oom(self) } - #[inline] fn usable_size(&self, layout: &Layout) -> (usize, usize) { - let mut min = 0; - let mut max = 0; - unsafe { - __rust_usable_size(layout as *const Layout as *const u8, - &mut min, - &mut max); - } - (min, max) + CoreAlloc::usable_size(self, layout) } - #[inline] unsafe fn realloc(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) - -> Result<*mut u8, AllocErr> - { - let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); - let ptr = __rust_realloc(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align(), - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - mem::forget(err); - Ok(ptr) - } + new_layout: Layout) -> Result<*mut u8, AllocErr> { + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) } - #[inline] unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); - let ptr = __rust_alloc_zeroed(layout.size(), - layout.align(), - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(ptr) - } + CoreAlloc::alloc_zeroed(self, layout).map(|ptr| ptr.cast().as_ptr()) } - #[inline] unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); - let mut size = 0; - let ptr = __rust_alloc_excess(layout.size(), - layout.align(), - &mut size, - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(Excess(ptr, size)) - } + CoreAlloc::alloc_excess(self, layout) + .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } - #[inline] unsafe fn realloc_excess(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<Excess, AllocErr> { - let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>()); - let mut size = 0; - let ptr = __rust_realloc_excess(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align(), - &mut size, - &mut *err as *mut AllocErr as *mut u8); - if ptr.is_null() { - Err(ManuallyDrop::into_inner(err)) - } else { - Ok(Excess(ptr, size)) - } + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) + .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) } - #[inline] unsafe fn grow_in_place(&mut self, ptr: *mut u8, layout: Layout, - new_layout: Layout) - -> Result<(), CannotReallocInPlace> - { - debug_assert!(new_layout.size() >= layout.size()); - debug_assert!(new_layout.align() == layout.align()); - let ret = __rust_grow_in_place(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align()); - if ret != 0 { - Ok(()) - } else { - Err(CannotReallocInPlace) - } + new_layout: Layout) -> Result<(), CannotReallocInPlace> { + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) } - #[inline] unsafe fn shrink_in_place(&mut self, ptr: *mut u8, layout: Layout, new_layout: Layout) -> Result<(), CannotReallocInPlace> { - debug_assert!(new_layout.size() <= layout.size()); - debug_assert!(new_layout.align() == layout.align()); - let ret = __rust_shrink_in_place(ptr, - layout.size(), - layout.align(), - new_layout.size(), - new_layout.align()); - if ret != 0 { - Ok(()) - } else { - Err(CannotReallocInPlace) - } - } -} - -/// The allocator for unique pointers. -// This function must not unwind. If it does, MIR trans will fail. -#[cfg(not(test))] -#[lang = "exchange_malloc"] -#[inline] -unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { - if size == 0 { - align as *mut u8 - } else { - let layout = Layout::from_size_align_unchecked(size, align); - Heap.alloc(layout).unwrap_or_else(|err| { - Heap.oom(err) - }) - } -} - -#[cfg_attr(not(test), lang = "box_free")] -#[inline] -pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) { - let size = size_of_val(&*ptr); - let align = min_align_of_val(&*ptr); - // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary. - if size != 0 { - let layout = Layout::from_size_align_unchecked(size, align); - Heap.dealloc(ptr as *mut u8, layout); - } -} - -#[cfg(test)] -mod tests { - extern crate test; - use self::test::Bencher; - use boxed::Box; - use heap::{Heap, Alloc, Layout}; - - #[test] - fn allocate_zeroed() { - unsafe { - let layout = Layout::from_size_align(1024, 1).unwrap(); - let ptr = Heap.alloc_zeroed(layout.clone()) - .unwrap_or_else(|e| Heap.oom(e)); - - let end = ptr.offset(layout.size() as isize); - let mut i = ptr; - while i < end { - assert_eq!(*i, 0); - i = i.offset(1); - } - Heap.dealloc(ptr, layout); - } - } - - #[bench] - fn alloc_owned_small(b: &mut Bencher) { - b.iter(|| { - let _: Box<_> = box 10; - }) + let ptr = NonNull::new_unchecked(ptr as *mut Opaque); + CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index da26e7c852c..3a106a2ff5c 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -57,7 +57,7 @@ //! //! ## Heap interfaces //! -//! The [`heap`](heap/index.html) module defines the low-level interface to the +//! The [`alloc`](alloc/index.html) module defines the low-level interface to the //! default global allocator. It is not compatible with the libc allocator API. #![allow(unused_attributes)] @@ -72,7 +72,6 @@ test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] #![no_std] #![needs_allocator] -#![deny(warnings)] #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand @@ -98,13 +97,15 @@ #![feature(from_ref)] #![feature(fundamental)] #![feature(lang_items)] +#![feature(libc)] #![feature(needs_allocator)] +#![feature(nonnull_cast)] #![feature(nonzero)] -#![feature(offset_to)] #![feature(optin_builtin_traits)] #![feature(pattern)] #![feature(pin)] #![feature(ptr_internals)] +#![feature(ptr_offset_from)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] #![feature(slice_rsplit)] @@ -114,7 +115,7 @@ #![feature(trusted_len)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] +#![feature(unicode_internals)] #![feature(unsize)] #![feature(allocator_internals)] #![feature(on_unimplemented)] @@ -136,18 +137,32 @@ extern crate test; #[cfg(test)] extern crate rand; -extern crate std_unicode; - // Module with internal macros used by other modules (needs to be included before other modules). #[macro_use] mod macros; #[rustc_deprecated(since = "1.27.0", reason = "use the heap module in core, alloc, or std instead")] #[unstable(feature = "allocator_api", issue = "32838")] -pub use core::heap as allocator; +/// Use the `alloc` module instead. +pub mod allocator { + pub use alloc::*; +} // Heaps provided for low-level allocation strategies +pub mod alloc; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +/// Use the `alloc` module instead. +#[cfg(not(stage0))] +pub mod heap { + pub use alloc::*; +} + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +#[cfg(stage0)] pub mod heap; // Primitive types using the heaps above diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 3edce8aebdf..214cc7d7d0c 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use alloc::{Alloc, Layout, Global}; use core::cmp; -use core::heap::{Alloc, Layout}; use core::mem; use core::ops::Drop; -use core::ptr::{self, Unique}; +use core::ptr::{self, NonNull, Unique}; use core::slice; -use heap::Heap; use super::boxed::Box; use super::allocator::CollectionAllocErr; use super::allocator::CollectionAllocErr::*; @@ -47,7 +46,7 @@ use super::allocator::CollectionAllocErr::*; /// field. This allows zero-sized types to not be special-cased by consumers of /// this type. #[allow(missing_debug_implementations)] -pub struct RawVec<T, A: Alloc = Heap> { +pub struct RawVec<T, A: Alloc = Global> { ptr: Unique<T>, cap: usize, a: A, @@ -91,7 +90,7 @@ impl<T, A: Alloc> RawVec<T, A> { // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { - mem::align_of::<T>() as *mut u8 + NonNull::<T>::dangling().as_opaque() } else { let align = mem::align_of::<T>(); let result = if zeroed { @@ -101,12 +100,12 @@ impl<T, A: Alloc> RawVec<T, A> { }; match result { Ok(ptr) => ptr, - Err(err) => a.oom(err), + Err(_) => a.oom(), } }; RawVec { - ptr: Unique::new_unchecked(ptr as *mut _), + ptr: ptr.cast().into(), cap, a, } @@ -114,14 +113,14 @@ impl<T, A: Alloc> RawVec<T, A> { } } -impl<T> RawVec<T, Heap> { +impl<T> RawVec<T, Global> { /// Creates the biggest possible RawVec (on the system heap) /// without allocating. If T has positive size, then this makes a /// RawVec with capacity 0. If T has 0 size, then it makes a /// RawVec with capacity `usize::MAX`. Useful for implementing /// delayed allocation. pub fn new() -> Self { - Self::new_in(Heap) + Self::new_in(Global) } /// Creates a RawVec (on the system heap) with exactly the @@ -141,13 +140,13 @@ impl<T> RawVec<T, Heap> { /// Aborts on OOM #[inline] pub fn with_capacity(cap: usize) -> Self { - RawVec::allocate_in(cap, false, Heap) + RawVec::allocate_in(cap, false, Global) } /// Like `with_capacity` but guarantees the buffer is zeroed. #[inline] pub fn with_capacity_zeroed(cap: usize) -> Self { - RawVec::allocate_in(cap, true, Heap) + RawVec::allocate_in(cap, true, Global) } } @@ -168,7 +167,7 @@ impl<T, A: Alloc> RawVec<T, A> { } } -impl<T> RawVec<T, Heap> { +impl<T> RawVec<T, Global> { /// Reconstitutes a RawVec from a pointer, capacity. /// /// # Undefined Behavior @@ -180,7 +179,7 @@ impl<T> RawVec<T, Heap> { RawVec { ptr: Unique::new_unchecked(ptr), cap, - a: Heap, + a: Global, } } @@ -310,14 +309,13 @@ impl<T, A: Alloc> RawVec<T, A> { // `from_size_align_unchecked`. let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; - let new_layout = Layout::from_size_align_unchecked(new_size, cur.align()); alloc_guard(new_size).expect("capacity overflow"); - let ptr_res = self.a.realloc(self.ptr.as_ptr() as *mut u8, + let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(), cur, - new_layout); + new_size); match ptr_res { - Ok(ptr) => (new_cap, Unique::new_unchecked(ptr as *mut T)), - Err(e) => self.a.oom(e), + Ok(ptr) => (new_cap, ptr.cast().into()), + Err(_) => self.a.oom(), } } None => { @@ -326,7 +324,7 @@ impl<T, A: Alloc> RawVec<T, A> { let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::<T>(new_cap) { Ok(ptr) => (new_cap, ptr.into()), - Err(e) => self.a.oom(e), + Err(_) => self.a.oom(), } } }; @@ -371,9 +369,7 @@ impl<T, A: Alloc> RawVec<T, A> { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).expect("capacity overflow"); - let ptr = self.ptr() as *mut _; - let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); - match self.a.grow_in_place(ptr, old_layout, new_layout) { + match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) { Ok(_) => { // We can't directly divide `size`. self.cap = new_cap; @@ -423,19 +419,19 @@ impl<T, A: Alloc> RawVec<T, A> { // Nothing we can really do about these checks :( let new_cap = used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?; - let new_layout = Layout::array::<T>(new_cap).ok_or(CapacityOverflow)?; + let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?; alloc_guard(new_layout.size())?; let res = match self.current_layout() { Some(layout) => { - let old_ptr = self.ptr.as_ptr() as *mut u8; - self.a.realloc(old_ptr, layout, new_layout) + debug_assert!(new_layout.align() == layout.align()); + self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; - self.ptr = Unique::new_unchecked(res? as *mut T); + self.ptr = res?.cast().into(); self.cap = new_cap; Ok(()) @@ -445,7 +441,7 @@ impl<T, A: Alloc> RawVec<T, A> { pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve_exact(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(e)) => self.a.oom(e), + Err(AllocErr) => self.a.oom(), Ok(()) => { /* yay */ } } } @@ -531,20 +527,20 @@ impl<T, A: Alloc> RawVec<T, A> { } let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?; - let new_layout = Layout::array::<T>(new_cap).ok_or(CapacityOverflow)?; + let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?; // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size())?; let res = match self.current_layout() { Some(layout) => { - let old_ptr = self.ptr.as_ptr() as *mut u8; - self.a.realloc(old_ptr, layout, new_layout) + debug_assert!(new_layout.align() == layout.align()); + self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) } None => self.a.alloc(new_layout), }; - self.ptr = Unique::new_unchecked(res? as *mut T); + self.ptr = res?.cast().into(); self.cap = new_cap; Ok(()) @@ -555,7 +551,7 @@ impl<T, A: Alloc> RawVec<T, A> { pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve(used_cap, needed_extra_cap) { Err(CapacityOverflow) => panic!("capacity overflow"), - Err(AllocErr(e)) => self.a.oom(e), + Err(AllocErr) => self.a.oom(), Ok(()) => { /* yay */ } } } @@ -601,11 +597,12 @@ impl<T, A: Alloc> RawVec<T, A> { // (regardless of whether `self.cap - used_cap` wrapped). // Therefore we can safely call grow_in_place. - let ptr = self.ptr() as *mut _; let new_layout = Layout::new::<T>().repeat(new_cap).unwrap().0; // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size()).expect("capacity overflow"); - match self.a.grow_in_place(ptr, old_layout, new_layout) { + match self.a.grow_in_place( + NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(), + ) { Ok(_) => { self.cap = new_cap; true @@ -665,12 +662,11 @@ impl<T, A: Alloc> RawVec<T, A> { let new_size = elem_size * amount; let align = mem::align_of::<T>(); let old_layout = Layout::from_size_align_unchecked(old_size, align); - let new_layout = Layout::from_size_align_unchecked(new_size, align); - match self.a.realloc(self.ptr.as_ptr() as *mut u8, + match self.a.realloc(NonNull::from(self.ptr).as_opaque(), old_layout, - new_layout) { - Ok(p) => self.ptr = Unique::new_unchecked(p as *mut T), - Err(err) => self.a.oom(err), + new_size) { + Ok(p) => self.ptr = p.cast().into(), + Err(_) => self.a.oom(), } } self.cap = amount; @@ -678,7 +674,7 @@ impl<T, A: Alloc> RawVec<T, A> { } } -impl<T> RawVec<T, Heap> { +impl<T> RawVec<T, Global> { /// Converts the entire buffer into `Box<[T]>`. /// /// While it is not *strictly* Undefined Behavior to call @@ -702,8 +698,7 @@ impl<T, A: Alloc> RawVec<T, A> { let elem_size = mem::size_of::<T>(); if elem_size != 0 { if let Some(layout) = self.current_layout() { - let ptr = self.ptr() as *mut u8; - self.a.dealloc(ptr, layout); + self.a.dealloc(NonNull::from(self.ptr).as_opaque(), layout); } } } @@ -739,6 +734,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { #[cfg(test)] mod tests { use super::*; + use alloc::Opaque; #[test] fn allocator_param() { @@ -758,18 +754,18 @@ mod tests { // before allocation attempts start failing. struct BoundedAlloc { fuel: usize } unsafe impl Alloc for BoundedAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { let size = layout.size(); if size > self.fuel { - return Err(AllocErr::Unsupported { details: "fuel exhausted" }); + return Err(AllocErr); } - match Heap.alloc(layout) { + match Global.alloc(layout) { ok @ Ok(_) => { self.fuel -= size; ok } err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - Heap.dealloc(ptr, layout) + unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) { + Global.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 8bdc57f96a6..de0422d82bb 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -250,7 +250,6 @@ use core::cell::Cell; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; -use core::heap::{Alloc, Layout}; use core::intrinsics::abort; use core::marker; use core::marker::{Unsize, PhantomData}; @@ -260,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use heap::{Heap, box_free}; +use alloc::{Global, Alloc, Layout, Opaque, box_free}; use string::String; use vec::Vec; @@ -668,11 +667,11 @@ impl<T: ?Sized> Rc<T> { let layout = Layout::for_value(&*fake_ptr); - let mem = Heap.alloc(layout) - .unwrap_or_else(|e| Heap.oom(e)); + let mem = Global.alloc(layout) + .unwrap_or_else(|_| Global.oom()); // Initialize the real RcBox - let inner = set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>; + let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox<T>; ptr::write(&mut (*inner).strong, Cell::new(1)); ptr::write(&mut (*inner).weak, Cell::new(1)); @@ -738,7 +737,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> { // In the event of a panic, elements that have been written // into the new RcBox will be dropped, then the memory freed. struct Guard<T> { - mem: *mut u8, + mem: NonNull<Opaque>, elems: *mut T, layout: Layout, n_elems: usize, @@ -752,7 +751,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Heap.dealloc(self.mem, self.layout.clone()); + Global.dealloc(self.mem, self.layout.clone()); } } } @@ -761,14 +760,14 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> { let v_ptr = v as *const [T]; let ptr = Self::allocate_for_ptr(v_ptr); - let mem = ptr as *mut _ as *mut u8; + let mem = ptr as *mut _ as *mut Opaque; let layout = Layout::for_value(&*ptr); // Pointer to first element let elems = &mut (*ptr).value as *mut [T] as *mut T; let mut guard = Guard{ - mem: mem, + mem: NonNull::new_unchecked(mem), elems: elems, layout: layout, n_elems: 0, @@ -835,8 +834,6 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> { /// ``` fn drop(&mut self) { unsafe { - let ptr = self.ptr.as_ptr(); - self.dec_strong(); if self.strong() == 0 { // destroy the contained object @@ -847,7 +844,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> { self.dec_weak(); if self.weak() == 0 { - Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); } } } @@ -1267,13 +1264,11 @@ impl<T: ?Sized> Drop for Weak<T> { /// ``` fn drop(&mut self) { unsafe { - let ptr = self.ptr.as_ptr(); - self.dec_weak(); // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. if self.weak() == 0 { - Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr)); + Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); } } } diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 68f2313843c..56c53fca62c 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -1400,6 +1400,7 @@ impl<T> [T] { let sz_usize = mem::size_of::<(K, usize)>(); let len = self.len(); + if len < 2 { return } if sz_u8 < sz_u16 && len <= ( u8::MAX as usize) { return sort_by_key!( u8, self, f) } if sz_u16 < sz_u32 && len <= (u16::MAX as usize) { return sort_by_key!(u16, self, f) } if sz_u32 < sz_usize && len <= (u32::MAX as usize) { return sort_by_key!(u32, self, f) } diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index d5ef41df0d8..65df93bd3bb 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -45,12 +45,10 @@ use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::ptr; use core::iter::FusedIterator; -use std_unicode::str::{UnicodeStr, Utf16Encoder}; use vec_deque::VecDeque; use borrow::{Borrow, ToOwned}; use string::String; -use std_unicode; use vec::Vec; use slice::{SliceConcatExt, SliceIndex}; use boxed::Box; @@ -75,7 +73,7 @@ pub use core::str::{from_utf8, from_utf8_mut, Chars, CharIndices, Bytes}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError}; #[stable(feature = "rust1", since = "1.0.0")] -pub use std_unicode::str::SplitWhitespace; +pub use core::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; @@ -147,7 +145,8 @@ impl<S: Borrow<str>> SliceConcatExt<str> for [S] { #[derive(Clone)] #[stable(feature = "encode_utf16", since = "1.8.0")] pub struct EncodeUtf16<'a> { - encoder: Utf16Encoder<Chars<'a>>, + chars: Chars<'a>, + extra: u16, } #[stable(feature = "collection_debug", since = "1.17.0")] @@ -163,12 +162,29 @@ impl<'a> Iterator for EncodeUtf16<'a> { #[inline] fn next(&mut self) -> Option<u16> { - self.encoder.next() + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; 2]; + self.chars.next().map(|ch| { + let n = ch.encode_utf16(&mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) } #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - self.encoder.size_hint() + let (low, high) = self.chars.size_hint(); + // every char gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low, high.and_then(|n| n.checked_mul(2))) } } @@ -801,7 +817,7 @@ impl str { #[stable(feature = "split_whitespace", since = "1.1.0")] #[inline] pub fn split_whitespace(&self) -> SplitWhitespace { - UnicodeStr::split_whitespace(self) + StrExt::split_whitespace(self) } /// An iterator over the lines of a string, as string slices. @@ -871,7 +887,7 @@ impl str { /// ``` #[stable(feature = "encode_utf16", since = "1.8.0")] pub fn encode_utf16(&self) -> EncodeUtf16 { - EncodeUtf16 { encoder: Utf16Encoder::new(self[..].chars()) } + EncodeUtf16 { chars: self[..].chars(), extra: 0 } } /// Returns `true` if the given pattern matches a sub-slice of @@ -1571,7 +1587,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim(&self) -> &str { - UnicodeStr::trim(self) + StrExt::trim(self) } /// Returns a string slice with leading whitespace removed. @@ -1607,7 +1623,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_left(&self) -> &str { - UnicodeStr::trim_left(self) + StrExt::trim_left(self) } /// Returns a string slice with trailing whitespace removed. @@ -1643,7 +1659,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_right(&self) -> &str { - UnicodeStr::trim_right(self) + StrExt::trim_right(self) } /// Returns a string slice with all prefixes and suffixes that match a @@ -1960,7 +1976,7 @@ impl str { } fn case_ignoreable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool { - use std_unicode::derived_property::{Cased, Case_Ignorable}; + use core::unicode::derived_property::{Cased, Case_Ignorable}; match iter.skip_while(|&c| Case_Ignorable(c)).next() { Some(c) => Cased(c), None => false, @@ -2142,7 +2158,7 @@ impl str { #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] #[inline] pub fn is_whitespace(&self) -> bool { - UnicodeStr::is_whitespace(self) + StrExt::is_whitespace(self) } /// Returns true if this `str` is entirely alphanumeric, and false otherwise. @@ -2161,7 +2177,7 @@ impl str { #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] #[inline] pub fn is_alphanumeric(&self) -> bool { - UnicodeStr::is_alphanumeric(self) + StrExt::is_alphanumeric(self) } /// Checks if all characters in this string are within the ASCII range. diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index b95aae02894..29d759b1f00 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -56,6 +56,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; @@ -63,8 +64,7 @@ use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; use core::ptr; use core::str::pattern::Pattern; -use std_unicode::lossy; -use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; +use core::str::lossy; use borrow::{Cow, ToOwned}; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; diff --git a/src/liballoc/tests/heap.rs b/src/liballoc/tests/heap.rs index d3ce12056bb..6fa88ce969a 100644 --- a/src/liballoc/tests/heap.rs +++ b/src/liballoc/tests/heap.rs @@ -9,7 +9,7 @@ // except according to those terms. use alloc_system::System; -use std::heap::{Heap, Alloc, Layout}; +use std::alloc::{Global, Alloc, Layout}; /// https://github.com/rust-lang/rust/issues/45955 /// @@ -22,7 +22,7 @@ fn alloc_system_overaligned_request() { #[test] fn std_heap_overaligned_request() { - check_overalign_requests(Heap) + check_overalign_requests(Global) } fn check_overalign_requests<T: Alloc>(mut allocator: T) { @@ -34,7 +34,8 @@ fn check_overalign_requests<T: Alloc>(mut allocator: T) { allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() }).collect(); for &ptr in &pointers { - assert_eq!((ptr as usize) % align, 0, "Got a pointer less aligned than requested") + assert_eq!((ptr.as_ptr() as usize) % align, 0, + "Got a pointer less aligned than requested") } // Clean up diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index a173ef10a81..32272169307 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(allocator_api)] #![feature(alloc_system)] #![feature(attr_literals)] @@ -26,12 +24,11 @@ #![feature(string_retain)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] #![feature(exact_chunks)] #![feature(inclusive_range_fields)] extern crate alloc_system; -extern crate std_unicode; +extern crate core; extern crate rand; use std::hash::{Hash, Hasher}; diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index a14a5d32738..a3f4c385fe2 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -1204,8 +1204,7 @@ fn test_rev_split_char_iterator_no_trailing() { #[test] fn test_utf16_code_units() { - use std_unicode::str::Utf16Encoder; - assert_eq!(Utf16Encoder::new(vec!['é', '\u{1F4A9}'].into_iter()).collect::<Vec<u16>>(), + assert_eq!("é\u{1F4A9}".encode_utf16().collect::<Vec<u16>>(), [0xE9, 0xD83D, 0xDCA9]) } diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index cb4a17a22d8..befb36baeef 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -132,7 +132,7 @@ fn test_from_utf16() { let s_as_utf16 = s.encode_utf16().collect::<Vec<u16>>(); let u_as_string = String::from_utf16(&u).unwrap(); - assert!(::std_unicode::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); + assert!(::core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); assert_eq!(s_as_utf16, u); assert_eq!(u_as_string, s); @@ -575,11 +575,11 @@ fn test_try_reserve() { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocErr(_)) = empty_string.try_reserve(MAX_CAP + 1) { + if let Err(AllocErr) = empty_string.try_reserve(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocErr(_)) = empty_string.try_reserve(MAX_USIZE) { + if let Err(AllocErr) = empty_string.try_reserve(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -599,7 +599,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -637,10 +637,10 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = empty_string.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocErr(_)) = empty_string.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocErr(_)) = empty_string.try_reserve_exact(MAX_USIZE) { + if let Err(AllocErr) = empty_string.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -659,7 +659,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 2895c53009d..e329b45a617 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -1016,11 +1016,11 @@ fn test_try_reserve() { } else { panic!("usize::MAX should trigger an overflow!") } } else { // Check isize::MAX + 1 is an OOM - if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_CAP + 1) { + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } // Check usize::MAX is an OOM - if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_USIZE) { + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -1040,7 +1040,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -1063,7 +1063,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size @@ -1103,10 +1103,10 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = empty_bytes.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an overflow!") } } else { - if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { + if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP + 1) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } - if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_USIZE) { + if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_USIZE) { } else { panic!("usize::MAX should trigger an OOM!") } } } @@ -1125,7 +1125,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { @@ -1146,7 +1146,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 75d3f01f8b6..4d55584e2f4 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1073,7 +1073,7 @@ fn test_try_reserve() { // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocErr(_)) = empty_bytes.try_reserve(MAX_CAP) { + if let Err(AllocErr) = empty_bytes.try_reserve(MAX_CAP) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } @@ -1093,7 +1093,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should always overflow in the add-to-len @@ -1116,7 +1116,7 @@ fn test_try_reserve() { if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } // Should fail in the mul-by-size @@ -1160,7 +1160,7 @@ fn test_try_reserve_exact() { // VecDeque starts with capacity 7, always adds 1 to the capacity // and also rounds the number to next power of 2 so this is the // furthest we can go without triggering CapacityOverflow - if let Err(AllocErr(_)) = empty_bytes.try_reserve_exact(MAX_CAP) { + if let Err(AllocErr) = empty_bytes.try_reserve_exact(MAX_CAP) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } @@ -1179,7 +1179,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { + if let Err(AllocErr) = ten_bytes.try_reserve_exact(MAX_CAP - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_bytes.try_reserve_exact(MAX_USIZE) { @@ -1200,7 +1200,7 @@ fn test_try_reserve_exact() { if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an overflow!"); } } else { - if let Err(AllocErr(_)) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { + if let Err(AllocErr) = ten_u32s.try_reserve_exact(MAX_CAP/4 - 9) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } if let Err(CapacityOverflow) = ten_u32s.try_reserve_exact(MAX_USIZE - 20) { diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 4b883b5bce7..0f74743ca49 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -2394,9 +2394,10 @@ impl<T> Iterator for IntoIter<T> { #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - let exact = match self.ptr.offset_to(self.end) { - Some(x) => x as usize, - None => (self.end as usize).wrapping_sub(self.ptr as usize), + let exact = if mem::size_of::<T>() == 0 { + (self.end as usize).wrapping_sub(self.ptr as usize) + } else { + unsafe { self.end.offset_from(self.ptr) as usize } }; (exact, Some(exact)) } diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index fd4a4553046..02435170374 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -12,7 +12,6 @@ test = false doc = false [dependencies] -alloc = { path = "../liballoc" } alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 7a8d01e4ef8..2b66c293f21 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -14,7 +14,6 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] -#![deny(warnings)] #![feature(alloc_system)] #![feature(libc)] #![feature(linkage)] @@ -31,9 +30,7 @@ extern crate libc; pub use contents::*; #[cfg(not(dummy_jemalloc))] mod contents { - use core::ptr; - - use core::heap::{Alloc, AllocErr, Layout}; + use core::alloc::GlobalAlloc; use alloc_system::System; use libc::{c_int, c_void, size_t}; @@ -55,16 +52,8 @@ mod contents { fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", target_os = "dragonfly", target_os = "windows", target_env = "musl"), - link_name = "je_xallocx")] - fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; - #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_sdallocx")] fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); - #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows", target_env = "musl"), - link_name = "je_nallocx")] - fn nallocx(size: size_t, flags: c_int) -> size_t; } const MALLOCX_ZERO: c_int = 0x40; @@ -105,23 +94,16 @@ mod contents { #[no_mangle] #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_alloc(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { + pub unsafe extern fn __rde_alloc(size: usize, align: usize) -> *mut u8 { let flags = align_to_flags(align, size); let ptr = mallocx(size as size_t, flags) as *mut u8; - if ptr.is_null() { - let layout = Layout::from_size_align_unchecked(size, align); - ptr::write(err as *mut AllocErr, - AllocErr::Exhausted { request: layout }); - } ptr } #[no_mangle] #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_oom(err: *const u8) -> ! { - System.oom((*(err as *const AllocErr)).clone()) + pub unsafe extern fn __rde_oom() -> ! { + System.oom() } #[no_mangle] @@ -135,116 +117,24 @@ mod contents { #[no_mangle] #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize) { - let layout = &*(layout as *const Layout); - let flags = align_to_flags(layout.align(), layout.size()); - let size = nallocx(layout.size(), flags) as usize; - *min = layout.size(); - if size > 0 { - *max = size; - } else { - *max = layout.size(); - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] pub unsafe extern fn __rde_realloc(ptr: *mut u8, _old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8 { - if new_align != old_align { - ptr::write(err as *mut AllocErr, - AllocErr::Unsupported { details: "can't change alignments" }); - return 0 as *mut u8 - } - - let flags = align_to_flags(new_align, new_size); + align: usize, + new_size: usize) -> *mut u8 { + let flags = align_to_flags(align, new_size); let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8; - if ptr.is_null() { - let layout = Layout::from_size_align_unchecked(new_size, new_align); - ptr::write(err as *mut AllocErr, - AllocErr::Exhausted { request: layout }); - } ptr } #[no_mangle] #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_alloc_zeroed(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { + pub unsafe extern fn __rde_alloc_zeroed(size: usize, align: usize) -> *mut u8 { let ptr = if align <= MIN_ALIGN && align <= size { calloc(size as size_t, 1) as *mut u8 } else { let flags = align_to_flags(align, size) | MALLOCX_ZERO; mallocx(size as size_t, flags) as *mut u8 }; - if ptr.is_null() { - let layout = Layout::from_size_align_unchecked(size, align); - ptr::write(err as *mut AllocErr, - AllocErr::Exhausted { request: layout }); - } ptr } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let p = __rde_alloc(size, align, err); - if !p.is_null() { - let flags = align_to_flags(align, size); - *excess = nallocx(size, flags) as usize; - } - return p - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err); - if !p.is_null() { - let flags = align_to_flags(new_align, new_size); - *excess = nallocx(new_size, flags) as usize; - } - p - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - __rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8, - _old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - if old_align == new_align { - let flags = align_to_flags(new_align, new_size); - (xallocx(ptr as *mut c_void, new_size, 0, flags) == new_size) as u8 - } else { - 0 - } - } } diff --git a/src/liballoc_system/Cargo.toml b/src/liballoc_system/Cargo.toml index 936e20a32e1..c34e2f203a8 100644 --- a/src/liballoc_system/Cargo.toml +++ b/src/liballoc_system/Cargo.toml @@ -10,7 +10,6 @@ test = false doc = false [dependencies] -alloc = { path = "../liballoc" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index d4404e564e0..fd8109e2a4a 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![allow(unused_attributes)] -#![deny(warnings)] #![unstable(feature = "alloc_system", reason = "this library is unlikely to be stabilized in its current \ form or name", @@ -42,7 +41,8 @@ const MIN_ALIGN: usize = 8; #[allow(dead_code)] const MIN_ALIGN: usize = 16; -use core::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}; +use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque}; +use core::ptr::NonNull; #[unstable(feature = "allocator_api", issue = "32838")] pub struct System; @@ -50,66 +50,86 @@ pub struct System; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - (&*self).alloc(layout) + unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { + NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) - -> Result<*mut u8, AllocErr> - { - (&*self).alloc_zeroed(layout) + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { + NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - (&*self).dealloc(ptr, layout) + unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) { + GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: *mut u8, - old_layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - (&*self).realloc(ptr, old_layout, new_layout) + ptr: NonNull<Opaque>, + layout: Layout, + new_size: usize) -> Result<NonNull<Opaque>, AllocErr> { + NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } - fn oom(&mut self, err: AllocErr) -> ! { - (&*self).oom(err) + #[inline] + fn oom(&mut self) -> ! { + ::oom() } +} +#[cfg(stage0)] +#[unstable(feature = "allocator_api", issue = "32838")] +unsafe impl<'a> Alloc for &'a System { #[inline] - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - (&self).usable_size(layout) + unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { + NonNull::new(GlobalAlloc::alloc(*self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> { - (&*self).alloc_excess(layout) + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { + NonNull::new(GlobalAlloc::alloc_zeroed(*self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<Excess, AllocErr> { - (&*self).realloc_excess(ptr, layout, new_layout) + unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) { + GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) } #[inline] - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - (&*self).grow_in_place(ptr, layout, new_layout) + unsafe fn realloc(&mut self, + ptr: NonNull<Opaque>, + layout: Layout, + new_size: usize) -> Result<NonNull<Opaque>, AllocErr> { + NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - (&*self).shrink_in_place(ptr, layout, new_layout) + fn oom(&mut self) -> ! { + ::oom() + } +} + +#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] +mod realloc_fallback { + use core::alloc::{GlobalAlloc, Opaque, Layout}; + use core::cmp; + use core::ptr; + + impl super::System { + pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout, + new_size: usize) -> *mut Opaque { + // Docs for GlobalAlloc::realloc require this to be valid: + let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); + + let new_ptr = GlobalAlloc::alloc(self, new_layout); + if !new_ptr.is_null() { + let size = cmp::min(old_layout.size(), new_size); + ptr::copy_nonoverlapping(ptr as *mut u8, new_ptr as *mut u8, size); + GlobalAlloc::dealloc(self, ptr, old_layout); + } + new_ptr + } } } @@ -117,132 +137,62 @@ unsafe impl Alloc for System { mod platform { extern crate libc; - use core::cmp; use core::ptr; use MIN_ALIGN; use System; - use core::heap::{Alloc, AllocErr, Layout}; + use core::alloc::{GlobalAlloc, Layout, Opaque}; #[unstable(feature = "allocator_api", issue = "32838")] - unsafe impl<'a> Alloc for &'a System { + unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut u8 + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::malloc(layout.size()) as *mut Opaque } else { #[cfg(target_os = "macos")] { if layout.align() > (1 << 31) { - return Err(AllocErr::Unsupported { - details: "requested alignment too large" - }) + // FIXME: use Opaque::null_mut + // https://github.com/rust-lang/rust/issues/49659 + return 0 as *mut Opaque } } aligned_malloc(&layout) - }; - if !ptr.is_null() { - Ok(ptr) - } else { - Err(AllocErr::Exhausted { request: layout }) } } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) - -> Result<*mut u8, AllocErr> - { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - let ptr = libc::calloc(layout.size(), 1) as *mut u8; - if !ptr.is_null() { - Ok(ptr) - } else { - Err(AllocErr::Exhausted { request: layout }) - } + libc::calloc(layout.size(), 1) as *mut Opaque } else { - let ret = self.alloc(layout.clone()); - if let Ok(ptr) = ret { - ptr::write_bytes(ptr, 0, layout.size()); + let ptr = self.alloc(layout.clone()); + if !ptr.is_null() { + ptr::write_bytes(ptr as *mut u8, 0, layout.size()); } - ret + ptr } } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, _layout: Layout) { libc::free(ptr as *mut libc::c_void) } #[inline] - unsafe fn realloc(&mut self, - ptr: *mut u8, - old_layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - if old_layout.align() != new_layout.align() { - return Err(AllocErr::Unsupported { - details: "cannot change alignment on `realloc`", - }) - } - - if new_layout.align() <= MIN_ALIGN && new_layout.align() <= new_layout.size(){ - let ptr = libc::realloc(ptr as *mut libc::c_void, new_layout.size()); - if !ptr.is_null() { - Ok(ptr as *mut u8) - } else { - Err(AllocErr::Exhausted { request: new_layout }) - } + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Opaque } else { - let res = self.alloc(new_layout.clone()); - if let Ok(new_ptr) = res { - let size = cmp::min(old_layout.size(), new_layout.size()); - ptr::copy_nonoverlapping(ptr, new_ptr, size); - self.dealloc(ptr, old_layout); - } - res - } - } - - fn oom(&mut self, err: AllocErr) -> ! { - use core::fmt::{self, Write}; - - // Print a message to stderr before aborting to assist with - // debugging. It is critical that this code does not allocate any - // memory since we are in an OOM situation. Any errors are ignored - // while printing since there's nothing we can do about them and we - // are about to exit anyways. - drop(writeln!(Stderr, "fatal runtime error: {}", err)); - unsafe { - ::core::intrinsics::abort(); - } - - struct Stderr; - - impl Write for Stderr { - #[cfg(target_os = "cloudabi")] - fn write_str(&mut self, _: &str) -> fmt::Result { - // CloudABI does not have any reserved file descriptor - // numbers. We should not attempt to write to file - // descriptor #2, as it may be associated with any kind of - // resource. - Ok(()) - } - - #[cfg(not(target_os = "cloudabi"))] - fn write_str(&mut self, s: &str) -> fmt::Result { - unsafe { - libc::write(libc::STDERR_FILENO, - s.as_ptr() as *const libc::c_void, - s.len()); - } - Ok(()) - } + self.realloc_fallback(ptr, layout, new_size) } } } #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { // On android we currently target API level 9 which unfortunately // doesn't have the `posix_memalign` API used below. Instead we use // `memalign`, but this unfortunately has the property on some systems @@ -260,18 +210,19 @@ mod platform { // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut u8 + libc::memalign(layout.align(), layout.size()) as *mut Opaque } #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { let mut out = ptr::null_mut(); let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); if ret != 0 { - ptr::null_mut() + // FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659 + 0 as *mut Opaque } else { - out as *mut u8 + out as *mut Opaque } } } @@ -279,22 +230,15 @@ mod platform { #[cfg(windows)] #[allow(bad_style)] mod platform { - use core::cmp; - use core::ptr; - use MIN_ALIGN; use System; - use core::heap::{Alloc, AllocErr, Layout, CannotReallocInPlace}; + use core::alloc::{GlobalAlloc, Opaque, Layout}; type LPVOID = *mut u8; type HANDLE = LPVOID; type SIZE_T = usize; type DWORD = u32; type BOOL = i32; - type LPDWORD = *mut DWORD; - type LPOVERLAPPED = *mut u8; - - const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; extern "system" { fn GetProcessHeap() -> HANDLE; @@ -302,20 +246,12 @@ mod platform { fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; fn GetLastError() -> DWORD; - fn WriteFile(hFile: HANDLE, - lpBuffer: LPVOID, - nNumberOfBytesToWrite: DWORD, - lpNumberOfBytesWritten: LPDWORD, - lpOverlapped: LPOVERLAPPED) - -> BOOL; - fn GetStdHandle(which: DWORD) -> HANDLE; } #[repr(C)] struct Header(*mut u8); const HEAP_ZERO_MEMORY: DWORD = 0x00000008; - const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010; unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header { &mut *(ptr as *mut Header).offset(-1) @@ -328,9 +264,7 @@ mod platform { } #[inline] - unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) - -> Result<*mut u8, AllocErr> - { + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Opaque { let ptr = if layout.align() <= MIN_ALIGN { HeapAlloc(GetProcessHeap(), flags, layout.size()) } else { @@ -342,35 +276,29 @@ mod platform { align_ptr(ptr, layout.align()) } }; - if ptr.is_null() { - Err(AllocErr::Exhausted { request: layout }) - } else { - Ok(ptr as *mut u8) - } + ptr as *mut Opaque } #[unstable(feature = "allocator_api", issue = "32838")] - unsafe impl<'a> Alloc for &'a System { + unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { allocate_with_flags(layout, 0) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) - -> Result<*mut u8, AllocErr> - { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { allocate_with_flags(layout, HEAP_ZERO_MEMORY) } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { if layout.align() <= MIN_ALIGN { let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); } else { - let header = get_header(ptr); + let header = get_header(ptr as *mut u8); let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); @@ -378,98 +306,11 @@ mod platform { } #[inline] - unsafe fn realloc(&mut self, - ptr: *mut u8, - old_layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - if old_layout.align() != new_layout.align() { - return Err(AllocErr::Unsupported { - details: "cannot change alignment on `realloc`", - }) - } - - if new_layout.align() <= MIN_ALIGN { - let ptr = HeapReAlloc(GetProcessHeap(), - 0, - ptr as LPVOID, - new_layout.size()); - if !ptr.is_null() { - Ok(ptr as *mut u8) - } else { - Err(AllocErr::Exhausted { request: new_layout }) - } - } else { - let res = self.alloc(new_layout.clone()); - if let Ok(new_ptr) = res { - let size = cmp::min(old_layout.size(), new_layout.size()); - ptr::copy_nonoverlapping(ptr, new_ptr, size); - self.dealloc(ptr, old_layout); - } - res - } - } - - #[inline] - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - self.shrink_in_place(ptr, layout, new_layout) - } - - #[inline] - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - old_layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - if old_layout.align() != new_layout.align() { - return Err(CannotReallocInPlace) - } - - let new = if new_layout.align() <= MIN_ALIGN { - HeapReAlloc(GetProcessHeap(), - HEAP_REALLOC_IN_PLACE_ONLY, - ptr as LPVOID, - new_layout.size()) - } else { - let header = get_header(ptr); - HeapReAlloc(GetProcessHeap(), - HEAP_REALLOC_IN_PLACE_ONLY, - header.0 as LPVOID, - new_layout.size() + new_layout.align()) - }; - if new.is_null() { - Err(CannotReallocInPlace) + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + if layout.align() <= MIN_ALIGN { + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque } else { - Ok(()) - } - } - - fn oom(&mut self, err: AllocErr) -> ! { - use core::fmt::{self, Write}; - - // Same as with unix we ignore all errors here - drop(writeln!(Stderr, "fatal runtime error: {}", err)); - unsafe { - ::core::intrinsics::abort(); - } - - struct Stderr; - - impl Write for Stderr { - fn write_str(&mut self, s: &str) -> fmt::Result { - unsafe { - // WriteFile silently fails if it is passed an invalid - // handle, so there is no need to check the result of - // GetStdHandle. - WriteFile(GetStdHandle(STD_ERROR_HANDLE), - s.as_ptr() as LPVOID, - s.len() as DWORD, - ptr::null_mut(), - ptr::null_mut()); - } - Ok(()) - } + self.realloc_fallback(ptr, layout, new_size) } } } @@ -496,69 +337,92 @@ mod platform { mod platform { extern crate dlmalloc; - use core::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}; + use core::alloc::{GlobalAlloc, Layout, Opaque}; use System; - use self::dlmalloc::GlobalDlmalloc; + + // No need for synchronization here as wasm is currently single-threaded + static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT; #[unstable(feature = "allocator_api", issue = "32838")] - unsafe impl<'a> Alloc for &'a System { + unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - GlobalDlmalloc.alloc(layout) + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) - -> Result<*mut u8, AllocErr> - { - GlobalDlmalloc.alloc_zeroed(layout) + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque } #[inline] - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - GlobalDlmalloc.dealloc(ptr, layout) + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&mut self, - ptr: *mut u8, - old_layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - GlobalDlmalloc.realloc(ptr, old_layout, new_layout) + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque } + } +} - #[inline] - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - GlobalDlmalloc.usable_size(layout) - } +#[inline] +fn oom() -> ! { + write_to_stderr("fatal runtime error: memory allocation failed"); + unsafe { + ::core::intrinsics::abort(); + } +} - #[inline] - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> { - GlobalDlmalloc.alloc_excess(layout) - } +#[cfg(any(unix, target_os = "redox"))] +#[inline] +fn write_to_stderr(s: &str) { + extern crate libc; - #[inline] - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<Excess, AllocErr> { - GlobalDlmalloc.realloc_excess(ptr, layout, new_layout) - } + unsafe { + libc::write(libc::STDERR_FILENO, + s.as_ptr() as *const libc::c_void, + s.len()); + } +} - #[inline] - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - GlobalDlmalloc.grow_in_place(ptr, layout, new_layout) - } +#[cfg(windows)] +#[inline] +fn write_to_stderr(s: &str) { + use core::ptr; - #[inline] - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - GlobalDlmalloc.shrink_in_place(ptr, layout, new_layout) - } + type LPVOID = *mut u8; + type HANDLE = LPVOID; + type DWORD = u32; + type BOOL = i32; + type LPDWORD = *mut DWORD; + type LPOVERLAPPED = *mut u8; + + const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; + + extern "system" { + fn WriteFile(hFile: HANDLE, + lpBuffer: LPVOID, + nNumberOfBytesToWrite: DWORD, + lpNumberOfBytesWritten: LPDWORD, + lpOverlapped: LPOVERLAPPED) + -> BOOL; + fn GetStdHandle(which: DWORD) -> HANDLE; + } + + unsafe { + // WriteFile silently fails if it is passed an invalid + // handle, so there is no need to check the result of + // GetStdHandle. + WriteFile(GetStdHandle(STD_ERROR_HANDLE), + s.as_ptr() as LPVOID, + s.len() as DWORD, + ptr::null_mut(), + ptr::null_mut()); } } + +#[cfg(not(any(windows, unix, target_os = "redox")))] +#[inline] +fn write_to_stderr(_: &str) {} diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 7eaf67e6ea6..b319f333342 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -22,7 +22,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(no_crate_inject, attr(deny(warnings))))] -#![deny(warnings)] #![feature(alloc)] #![feature(core_intrinsics)] diff --git a/src/libcore/heap.rs b/src/libcore/alloc.rs index fe19c923a58..8f8849e32e6 100644 --- a/src/libcore/heap.rs +++ b/src/libcore/alloc.rs @@ -21,10 +21,30 @@ use mem; use usize; use ptr::{self, NonNull}; +extern { + /// An opaque, unsized type. Used for pointers to allocated memory. + /// + /// This type can only be used behind a pointer like `*mut Opaque` or `ptr::NonNull<Opaque>`. + /// Such pointers are similar to C’s `void*` type. + pub type Opaque; +} + +impl Opaque { + /// Similar to `std::ptr::null`, which requires `T: Sized`. + pub fn null() -> *const Self { + 0 as _ + } + + /// Similar to `std::ptr::null_mut`, which requires `T: Sized`. + pub fn null_mut() -> *mut Self { + 0 as _ + } +} + /// Represents the combination of a starting address and /// a total capacity of the returned block. #[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); +pub struct Excess(pub NonNull<Opaque>, pub usize); fn size_align<T>() -> (usize, usize) { (mem::size_of::<T>(), mem::align_of::<T>()) @@ -74,9 +94,9 @@ impl Layout { /// must not overflow (i.e. the rounded value must be less than /// `usize::MAX`). #[inline] - pub fn from_size_align(size: usize, align: usize) -> Option<Layout> { + pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> { if !align.is_power_of_two() { - return None; + return Err(LayoutErr { private: () }); } // (power-of-two implies align != 0.) @@ -94,11 +114,11 @@ impl Layout { // Above implies that checking for summation overflow is both // necessary and sufficient. if size > usize::MAX - (align - 1) { - return None; + return Err(LayoutErr { private: () }); } unsafe { - Some(Layout::from_size_align_unchecked(size, align)) + Ok(Layout::from_size_align_unchecked(size, align)) } } @@ -110,7 +130,7 @@ impl Layout { /// a power-of-two nor `size` aligned to `align` fits within the /// address space (i.e. the `Layout::from_size_align` preconditions). #[inline] - pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout { + pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { Layout { size: size, align: align } } @@ -209,15 +229,17 @@ impl Layout { /// /// On arithmetic overflow, returns `None`. #[inline] - pub fn repeat(&self, n: usize) -> Option<(Self, usize)> { - let padded_size = self.size.checked_add(self.padding_needed_for(self.align))?; - let alloc_size = padded_size.checked_mul(n)?; + pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { + let padded_size = self.size.checked_add(self.padding_needed_for(self.align)) + .ok_or(LayoutErr { private: () })?; + let alloc_size = padded_size.checked_mul(n) + .ok_or(LayoutErr { private: () })?; // We can assume that `self.align` is a power-of-two. // Furthermore, `alloc_size` has already been rounded up // to a multiple of `self.align`; therefore, the call to // `Layout::from_size_align` below should never panic. - Some((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) + Ok((Layout::from_size_align(alloc_size, self.align).unwrap(), padded_size)) } /// Creates a layout describing the record for `self` followed by @@ -231,17 +253,19 @@ impl Layout { /// (assuming that the record itself starts at offset 0). /// /// On arithmetic overflow, returns `None`. - pub fn extend(&self, next: Self) -> Option<(Self, usize)> { + pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_align = cmp::max(self.align, next.align); let realigned = Layout::from_size_align(self.size, new_align)?; let pad = realigned.padding_needed_for(next.align); - let offset = self.size.checked_add(pad)?; - let new_size = offset.checked_add(next.size)?; + let offset = self.size.checked_add(pad) + .ok_or(LayoutErr { private: () })?; + let new_size = offset.checked_add(next.size) + .ok_or(LayoutErr { private: () })?; let layout = Layout::from_size_align(new_size, new_align)?; - Some((layout, offset)) + Ok((layout, offset)) } /// Creates a layout describing the record for `n` instances of @@ -256,8 +280,8 @@ impl Layout { /// aligned. /// /// On arithmetic overflow, returns `None`. - pub fn repeat_packed(&self, n: usize) -> Option<Self> { - let size = self.size().checked_mul(n)?; + pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> { + let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; Layout::from_size_align(size, self.align) } @@ -276,16 +300,17 @@ impl Layout { /// `extend`.) /// /// On arithmetic overflow, returns `None`. - pub fn extend_packed(&self, next: Self) -> Option<(Self, usize)> { - let new_size = self.size().checked_add(next.size())?; + pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> { + let new_size = self.size().checked_add(next.size()) + .ok_or(LayoutErr { private: () })?; let layout = Layout::from_size_align(new_size, self.align)?; - Some((layout, self.size())) + Ok((layout, self.size())) } /// Creates a layout describing the record for a `[T; n]`. /// /// On arithmetic overflow, returns `None`. - pub fn array<T>(n: usize) -> Option<Self> { + pub fn array<T>(n: usize) -> Result<Self, LayoutErr> { Layout::new::<T>() .repeat(n) .map(|(k, offs)| { @@ -295,55 +320,31 @@ impl Layout { } } -/// The `AllocErr` error specifies whether an allocation failure is -/// specifically due to resource exhaustion or if it is due to -/// something wrong when combining the given input arguments with this -/// allocator. +/// The parameters given to `Layout::from_size_align` do not satisfy +/// its documented constraints. #[derive(Clone, PartialEq, Eq, Debug)] -pub enum AllocErr { - /// Error due to hitting some resource limit or otherwise running - /// out of memory. This condition strongly implies that *some* - /// series of deallocations would allow a subsequent reissuing of - /// the original allocation request to succeed. - Exhausted { request: Layout }, - - /// Error due to allocator being fundamentally incapable of - /// satisfying the original request. This condition implies that - /// such an allocation request will never succeed on the given - /// allocator, regardless of environment, memory pressure, or - /// other contextual conditions. - /// - /// For example, an allocator that does not support requests for - /// large memory blocks might return this error variant. - Unsupported { details: &'static str }, +pub struct LayoutErr { + private: () } -impl AllocErr { - #[inline] - pub fn invalid_input(details: &'static str) -> Self { - AllocErr::Unsupported { details: details } - } - #[inline] - pub fn is_memory_exhausted(&self) -> bool { - if let AllocErr::Exhausted { .. } = *self { true } else { false } - } - #[inline] - pub fn is_request_unsupported(&self) -> bool { - if let AllocErr::Unsupported { .. } = *self { true } else { false } - } - #[inline] - pub fn description(&self) -> &str { - match *self { - AllocErr::Exhausted { .. } => "allocator memory exhausted", - AllocErr::Unsupported { .. } => "unsupported allocator request", - } +// (we need this for downstream impl of trait Error) +impl fmt::Display for LayoutErr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("invalid parameters to Layout::from_size_align") } } +/// The `AllocErr` error specifies whether an allocation failure is +/// specifically due to resource exhaustion or if it is due to +/// something wrong when combining the given input arguments with this +/// allocator. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct AllocErr; + // (we need this for downstream impl of trait Error) impl fmt::Display for AllocErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) + f.write_str("memory allocation failed") } } @@ -374,13 +375,85 @@ pub enum CollectionAllocErr { /// (usually `isize::MAX` bytes). CapacityOverflow, /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr(AllocErr), + AllocErr, } #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] impl From<AllocErr> for CollectionAllocErr { - fn from(err: AllocErr) -> Self { - CollectionAllocErr::AllocErr(err) + fn from(AllocErr: AllocErr) -> Self { + CollectionAllocErr::AllocErr + } +} + +/// A memory allocator that can be registered to be the one backing `std::alloc::Global` +/// though the `#[global_allocator]` attributes. +pub unsafe trait GlobalAlloc { + /// Allocate memory as described by the given `layout`. + /// + /// Returns a pointer to newly-allocated memory, + /// or NULL to indicate allocation failure. + /// + /// # Safety + /// + /// **FIXME:** what are the exact requirements? + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque; + + /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. + /// + /// # Safety + /// + /// **FIXME:** what are the exact requirements? + /// In particular around layout *fit*. (See docs for the `Alloc` trait.) + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout); + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + let size = layout.size(); + let ptr = self.alloc(layout); + if !ptr.is_null() { + ptr::write_bytes(ptr as *mut u8, 0, size); + } + ptr + } + + /// Shink or grow a block of memory to the given `new_size`. + /// The block is described by the given `ptr` pointer and `layout`. + /// + /// Return a new pointer (which may or may not be the same as `ptr`), + /// or NULL to indicate reallocation failure. + /// + /// If reallocation is successful, the old `ptr` pointer is considered + /// to have been deallocated. + /// + /// # Safety + /// + /// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`, + /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). + /// + /// **FIXME:** what are the exact requirements? + /// In particular around layout *fit*. (See docs for the `Alloc` trait.) + unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + let new_ptr = self.alloc(new_layout); + if !new_ptr.is_null() { + ptr::copy_nonoverlapping( + ptr as *const u8, + new_ptr as *mut u8, + cmp::min(layout.size(), new_size), + ); + self.dealloc(ptr, layout); + } + new_ptr + } + + /// Aborts the thread or process, optionally performing + /// cleanup or logging diagnostic information before panicking or + /// aborting. + /// + /// `oom` is meant to be used by clients unable to cope with an + /// unsatisfied allocation request, and wish to abandon + /// computation rather than attempt to recover locally. + fn oom(&self) -> ! { + unsafe { ::intrinsics::abort() } } } @@ -515,7 +588,7 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; + unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr>; /// Deallocate the memory referenced by `ptr`. /// @@ -532,7 +605,7 @@ pub unsafe trait Alloc { /// * In addition to fitting the block of memory `layout`, the /// alignment of the `layout` must match the alignment used /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); + unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout); /// Allocator-specific method for signaling an out-of-memory /// condition. @@ -542,12 +615,8 @@ pub unsafe trait Alloc { /// aborting. /// /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request (signaled by an error such as - /// `AllocErr::Exhausted`), and wish to abandon computation rather - /// than attempt to recover locally. Such clients should pass the - /// signaling error value back into `oom`, where the allocator - /// may incorporate that error value into its diagnostic report - /// before aborting. + /// unsatisfied allocation request, and wish to abandon + /// computation rather than attempt to recover locally. /// /// Implementations of the `oom` method are discouraged from /// infinitely regressing in nested calls to `oom`. In @@ -560,7 +629,7 @@ pub unsafe trait Alloc { /// instead they should return an appropriate error from the /// invoked method, and let the client decide whether to invoke /// this `oom` method in response. - fn oom(&mut self, _: AllocErr) -> ! { + fn oom(&mut self) -> ! { unsafe { ::intrinsics::abort() } } @@ -602,9 +671,10 @@ pub unsafe trait Alloc { // realloc. alloc_excess, realloc_excess /// Returns a pointer suitable for holding data described by - /// `new_layout`, meeting its size and alignment guarantees. To + /// a new layout with `layout`’s alginment and a size given + /// by `new_size`. To /// accomplish this, this may extend or shrink the allocation - /// referenced by `ptr` to fit `new_layout`. + /// referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then ownership of the memory block /// referenced by `ptr` has been transferred to this @@ -617,12 +687,6 @@ pub unsafe trait Alloc { /// block has not been transferred to this allocator, and the /// contents of the memory block are unaltered. /// - /// For best results, `new_layout` should not impose a different - /// alignment constraint than `layout`. (In other words, - /// `new_layout.align()` should equal `layout.align()`.) However, - /// behavior is well-defined (though underspecified) when this - /// constraint is violated; further discussion below. - /// /// # Safety /// /// This function is unsafe because undefined behavior can result @@ -630,12 +694,13 @@ pub unsafe trait Alloc { /// /// * `ptr` must be currently allocated via this allocator, /// - /// * `layout` must *fit* the `ptr` (see above). (The `new_layout` + /// * `layout` must *fit* the `ptr` (see above). (The `new_size` /// argument need not fit it.) /// - /// * `new_layout` must have size greater than zero. + /// * `new_size` must be greater than zero. /// - /// * the alignment of `new_layout` is non-zero. + /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, + /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g. guarantee a sentinel address or a null pointer @@ -643,18 +708,11 @@ pub unsafe trait Alloc { /// /// # Errors /// - /// Returns `Err` only if `new_layout` does not match the - /// alignment of `layout`, or does not meet the allocator's size + /// Returns `Err` only if the new layout + /// does not meet the allocator's size /// and alignment constraints of the allocator, or if reallocation /// otherwise fails. /// - /// (Note the previous sentence did not say "if and only if" -- in - /// particular, an implementation of this method *can* return `Ok` - /// if `new_layout.align() != old_layout.align()`; or it can - /// return `Err` in that scenario, depending on whether this - /// allocator can dynamically adjust the alignment constraint for - /// the block.) - /// /// Implementations are encouraged to return `Err` on memory /// exhaustion rather than panicking or aborting, but this is not /// a strict requirement. (Specifically: it is *legal* to @@ -665,27 +723,28 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc(&mut self, - ptr: *mut u8, + ptr: NonNull<Opaque>, layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - let new_size = new_layout.size(); + new_size: usize) -> Result<NonNull<Opaque>, AllocErr> { let old_size = layout.size(); - let aligns_match = layout.align == new_layout.align; - if new_size >= old_size && aligns_match { - if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_layout.clone()) { + if new_size >= old_size { + if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_size) { return Ok(ptr); } - } else if new_size < old_size && aligns_match { - if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_layout.clone()) { + } else if new_size < old_size { + if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_size) { return Ok(ptr); } } // otherwise, fall back on alloc + copy + dealloc. + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let result = self.alloc(new_layout); if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size)); + ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, + new_ptr.as_ptr() as *mut u8, + cmp::min(old_size, new_size)); self.dealloc(ptr, layout); } result @@ -707,11 +766,11 @@ pub unsafe trait Alloc { /// Clients wishing to abort computation in response to an /// allocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { let size = layout.size(); let p = self.alloc(layout); if let Ok(p) = p { - ptr::write_bytes(p, 0, size); + ptr::write_bytes(p.as_ptr() as *mut u8, 0, size); } p } @@ -756,19 +815,21 @@ pub unsafe trait Alloc { /// reallocation error are encouraged to call the allocator's `oom` /// method, rather than directly invoking `panic!` or similar. unsafe fn realloc_excess(&mut self, - ptr: *mut u8, + ptr: NonNull<Opaque>, layout: Layout, - new_layout: Layout) -> Result<Excess, AllocErr> { + new_size: usize) -> Result<Excess, AllocErr> { + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let usable_size = self.usable_size(&new_layout); - self.realloc(ptr, layout, new_layout) + self.realloc(ptr, layout, new_size) .map(|p| Excess(p, usable_size.1)) } - /// Attempts to extend the allocation referenced by `ptr` to fit `new_layout`. + /// Attempts to extend the allocation referenced by `ptr` to fit `new_size`. /// /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and thus can - /// be used to carry data of that layout. (The allocator is allowed to + /// memory block referenced by `ptr` now fits `new_size`, and thus can + /// be used to carry data of a layout of that size and same alignment as + /// `layout`. (The allocator is allowed to /// expend effort to accomplish this, such as extending the memory block to /// include successor blocks, or virtual memory tricks.) /// @@ -784,11 +845,9 @@ pub unsafe trait Alloc { /// * `ptr` must be currently allocated via this allocator, /// /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, + /// `new_size` argument need not fit it, /// - /// * `new_layout.size()` must not be less than `layout.size()`, - /// - /// * `new_layout.align()` must equal `layout.align()`. + /// * `new_size` must not be less than `layout.size()`, /// /// # Errors /// @@ -801,26 +860,25 @@ pub unsafe trait Alloc { /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, - ptr: *mut u8, + ptr: NonNull<Opaque>, layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { + new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size >= layout.size); - debug_assert!(new_layout.align == layout.align); + debug_assert!(new_size >= layout.size); let (_l, u) = self.usable_size(&layout); // _l <= layout.size() [guaranteed by usable_size()] // layout.size() <= new_layout.size() [required by this method] - if new_layout.size <= u { + if new_size <= u { return Ok(()); } else { return Err(CannotReallocInPlace); } } - /// Attempts to shrink the allocation referenced by `ptr` to fit `new_layout`. + /// Attempts to shrink the allocation referenced by `ptr` to fit `new_size`. /// /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_layout`, and + /// memory block referenced by `ptr` now fits `new_size`, and /// thus can only be used to carry data of that smaller /// layout. (The allocator is allowed to take advantage of this, /// carving off portions of the block for reuse elsewhere.) The @@ -841,13 +899,11 @@ pub unsafe trait Alloc { /// * `ptr` must be currently allocated via this allocator, /// /// * `layout` must *fit* the `ptr` (see above); note the - /// `new_layout` argument need not fit it, + /// `new_size` argument need not fit it, /// - /// * `new_layout.size()` must not be greater than `layout.size()` + /// * `new_size` must not be greater than `layout.size()` /// (and must be greater than zero), /// - /// * `new_layout.align()` must equal `layout.align()`. - /// /// # Errors /// /// Returns `Err(CannotReallocInPlace)` when the allocator is @@ -859,16 +915,15 @@ pub unsafe trait Alloc { /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, + ptr: NonNull<Opaque>, layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { + new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_layout.size <= layout.size); - debug_assert!(new_layout.align == layout.align); + debug_assert!(new_size <= layout.size); let (l, _u) = self.usable_size(&layout); // layout.size() <= _u [guaranteed by usable_size()] // new_layout.size() <= layout.size() [required by this method] - if l <= new_layout.size { + if l <= new_size { return Ok(()); } else { return Err(CannotReallocInPlace); @@ -911,9 +966,9 @@ pub unsafe trait Alloc { { let k = Layout::new::<T>(); if k.size() > 0 { - unsafe { self.alloc(k).map(|p| NonNull::new_unchecked(p as *mut T)) } + unsafe { self.alloc(k).map(|p| p.cast()) } } else { - Err(AllocErr::invalid_input("zero-sized type invalid for alloc_one")) + Err(AllocErr) } } @@ -937,10 +992,9 @@ pub unsafe trait Alloc { unsafe fn dealloc_one<T>(&mut self, ptr: NonNull<T>) where Self: Sized { - let raw_ptr = ptr.as_ptr() as *mut u8; let k = Layout::new::<T>(); if k.size() > 0 { - self.dealloc(raw_ptr, k); + self.dealloc(ptr.as_opaque(), k); } } @@ -978,15 +1032,12 @@ pub unsafe trait Alloc { where Self: Sized { match Layout::array::<T>(n) { - Some(ref layout) if layout.size() > 0 => { + Ok(ref layout) if layout.size() > 0 => { unsafe { - self.alloc(layout.clone()) - .map(|p| { - NonNull::new_unchecked(p as *mut T) - }) + self.alloc(layout.clone()).map(|p| p.cast()) } } - _ => Err(AllocErr::invalid_input("invalid layout for alloc_array")), + _ => Err(AllocErr), } } @@ -1028,13 +1079,13 @@ pub unsafe trait Alloc { n_new: usize) -> Result<NonNull<T>, AllocErr> where Self: Sized { - match (Layout::array::<T>(n_old), Layout::array::<T>(n_new), ptr.as_ptr()) { - (Some(ref k_old), Some(ref k_new), ptr) if k_old.size() > 0 && k_new.size() > 0 => { - self.realloc(ptr as *mut u8, k_old.clone(), k_new.clone()) - .map(|p| NonNull::new_unchecked(p as *mut T)) + match (Layout::array::<T>(n_old), Layout::array::<T>(n_new)) { + (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { + debug_assert!(k_old.align() == k_new.align()); + self.realloc(ptr.as_opaque(), k_old.clone(), k_new.size()).map(NonNull::cast) } _ => { - Err(AllocErr::invalid_input("invalid layout for realloc_array")) + Err(AllocErr) } } } @@ -1062,13 +1113,12 @@ pub unsafe trait Alloc { unsafe fn dealloc_array<T>(&mut self, ptr: NonNull<T>, n: usize) -> Result<(), AllocErr> where Self: Sized { - let raw_ptr = ptr.as_ptr() as *mut u8; match Layout::array::<T>(n) { - Some(ref k) if k.size() > 0 => { - Ok(self.dealloc(raw_ptr, k.clone())) + Ok(ref k) if k.size() > 0 => { + Ok(self.dealloc(ptr.as_opaque(), k.clone())) } _ => { - Err(AllocErr::invalid_input("invalid layout for dealloc_array")) + Err(AllocErr) } } } diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index c947b003ccb..ced77d77918 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(flt2dec)] #![feature(test)] diff --git a/src/libcore/char.rs b/src/libcore/char.rs deleted file mode 100644 index 718c6b893ed..00000000000 --- a/src/libcore/char.rs +++ /dev/null @@ -1,918 +0,0 @@ -// Copyright 2012-2014 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. - -//! Character manipulation. -//! -//! For more details, see ::std_unicode::char (a.k.a. std::char) - -#![allow(non_snake_case)] -#![stable(feature = "core_char", since = "1.2.0")] - -use char_private::is_printable; -use convert::TryFrom; -use fmt::{self, Write}; -use slice; -use str::{from_utf8_unchecked_mut, FromStr}; -use iter::FusedIterator; -use mem::transmute; - -// UTF-8 ranges and tags for encoding characters -const TAG_CONT: u8 = 0b1000_0000; -const TAG_TWO_B: u8 = 0b1100_0000; -const TAG_THREE_B: u8 = 0b1110_0000; -const TAG_FOUR_B: u8 = 0b1111_0000; -const MAX_ONE_B: u32 = 0x80; -const MAX_TWO_B: u32 = 0x800; -const MAX_THREE_B: u32 = 0x10000; - -/* - Lu Uppercase_Letter an uppercase letter - Ll Lowercase_Letter a lowercase letter - Lt Titlecase_Letter a digraphic character, with first part uppercase - Lm Modifier_Letter a modifier letter - Lo Other_Letter other letters, including syllables and ideographs - Mn Nonspacing_Mark a nonspacing combining mark (zero advance width) - Mc Spacing_Mark a spacing combining mark (positive advance width) - Me Enclosing_Mark an enclosing combining mark - Nd Decimal_Number a decimal digit - Nl Letter_Number a letterlike numeric character - No Other_Number a numeric character of other type - Pc Connector_Punctuation a connecting punctuation mark, like a tie - Pd Dash_Punctuation a dash or hyphen punctuation mark - Ps Open_Punctuation an opening punctuation mark (of a pair) - Pe Close_Punctuation a closing punctuation mark (of a pair) - Pi Initial_Punctuation an initial quotation mark - Pf Final_Punctuation a final quotation mark - Po Other_Punctuation a punctuation mark of other type - Sm Math_Symbol a symbol of primarily mathematical use - Sc Currency_Symbol a currency sign - Sk Modifier_Symbol a non-letterlike modifier symbol - So Other_Symbol a symbol of other type - Zs Space_Separator a space character (of various non-zero widths) - Zl Line_Separator U+2028 LINE SEPARATOR only - Zp Paragraph_Separator U+2029 PARAGRAPH SEPARATOR only - Cc Control a C0 or C1 control code - Cf Format a format control character - Cs Surrogate a surrogate code point - Co Private_Use a private-use character - Cn Unassigned a reserved unassigned code point or a noncharacter -*/ - -/// The highest valid code point a `char` can have. -/// -/// A [`char`] is a [Unicode Scalar Value], which means that it is a [Code -/// Point], but only ones within a certain range. `MAX` is the highest valid -/// code point that's a valid [Unicode Scalar Value]. -/// -/// [`char`]: ../../std/primitive.char.html -/// [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value -/// [Code Point]: http://www.unicode.org/glossary/#code_point -#[stable(feature = "rust1", since = "1.0.0")] -pub const MAX: char = '\u{10ffff}'; - -/// Converts a `u32` to a `char`. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// [`as`]: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value -/// for a [`char`]. -/// -/// [`char`]: ../../std/primitive.char.html -/// [`u32`]: ../../std/primitive.u32.html -/// [`as`]: ../../book/first-edition/casting-between-types.html#as -/// -/// For an unsafe version of this function which ignores these checks, see -/// [`from_u32_unchecked`]. -/// -/// [`from_u32_unchecked`]: fn.from_u32_unchecked.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x2764); -/// -/// assert_eq!(Some('❤'), c); -/// ``` -/// -/// Returning `None` when the input is not a valid [`char`]: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x110000); -/// -/// assert_eq!(None, c); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn from_u32(i: u32) -> Option<char> { - char::try_from(i).ok() -} - -/// Converts a `u32` to a `char`, ignoring validity. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// [`as`]: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to -/// [`char`], possibly creating an invalid one. -/// -/// [`char`]: ../../std/primitive.char.html -/// [`u32`]: ../../std/primitive.u32.html -/// [`as`]: ../../book/first-edition/casting-between-types.html#as -/// -/// # Safety -/// -/// This function is unsafe, as it may construct invalid `char` values. -/// -/// For a safe version of this function, see the [`from_u32`] function. -/// -/// [`from_u32`]: fn.from_u32.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = unsafe { char::from_u32_unchecked(0x2764) }; -/// -/// assert_eq!('❤', c); -/// ``` -#[inline] -#[stable(feature = "char_from_unchecked", since = "1.5.0")] -pub unsafe fn from_u32_unchecked(i: u32) -> char { - transmute(i) -} - -#[stable(feature = "char_convert", since = "1.13.0")] -impl From<char> for u32 { - #[inline] - fn from(c: char) -> Self { - c as u32 - } -} - -/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF. -/// -/// Unicode is designed such that this effectively decodes bytes -/// with the character encoding that IANA calls ISO-8859-1. -/// This encoding is compatible with ASCII. -/// -/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen), -/// which leaves some "blanks", byte values that are not assigned to any character. -/// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes. -/// -/// Note that this is *also* different from Windows-1252 a.k.a. code page 1252, -/// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks -/// to punctuation and various Latin characters. -/// -/// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/) -/// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases -/// for a superset of Windows-1252 that fills the remaining blanks with corresponding -/// C0 and C1 control codes. -#[stable(feature = "char_convert", since = "1.13.0")] -impl From<u8> for char { - #[inline] - fn from(i: u8) -> Self { - i as char - } -} - - -/// An error which can be returned when parsing a char. -#[stable(feature = "char_from_str", since = "1.20.0")] -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ParseCharError { - kind: CharErrorKind, -} - -impl ParseCharError { - #[unstable(feature = "char_error_internals", - reason = "this method should not be available publicly", - issue = "0")] - #[doc(hidden)] - pub fn __description(&self) -> &str { - match self.kind { - CharErrorKind::EmptyString => { - "cannot parse char from empty string" - }, - CharErrorKind::TooManyChars => "too many characters in string" - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum CharErrorKind { - EmptyString, - TooManyChars, -} - -#[stable(feature = "char_from_str", since = "1.20.0")] -impl fmt::Display for ParseCharError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.__description().fmt(f) - } -} - - -#[stable(feature = "char_from_str", since = "1.20.0")] -impl FromStr for char { - type Err = ParseCharError; - - #[inline] - fn from_str(s: &str) -> Result<Self, Self::Err> { - let mut chars = s.chars(); - match (chars.next(), chars.next()) { - (None, _) => { - Err(ParseCharError { kind: CharErrorKind::EmptyString }) - }, - (Some(c), None) => Ok(c), - _ => { - Err(ParseCharError { kind: CharErrorKind::TooManyChars }) - } - } - } -} - - -#[stable(feature = "try_from", since = "1.26.0")] -impl TryFrom<u32> for char { - type Error = CharTryFromError; - - #[inline] - fn try_from(i: u32) -> Result<Self, Self::Error> { - if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { - Err(CharTryFromError(())) - } else { - Ok(unsafe { from_u32_unchecked(i) }) - } - } -} - -/// The error type returned when a conversion from u32 to char fails. -#[stable(feature = "try_from", since = "1.26.0")] -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct CharTryFromError(()); - -#[stable(feature = "try_from", since = "1.26.0")] -impl fmt::Display for CharTryFromError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "converted integer out of range for `char`".fmt(f) - } -} - -/// Converts a digit in the given radix to a `char`. -/// -/// A 'radix' here is sometimes also called a 'base'. A radix of two -/// indicates a binary number, a radix of ten, decimal, and a radix of -/// sixteen, hexadecimal, to give some common values. Arbitrary -/// radices are supported. -/// -/// `from_digit()` will return `None` if the input is not a digit in -/// the given radix. -/// -/// # Panics -/// -/// Panics if given a radix larger than 36. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(4, 10); -/// -/// assert_eq!(Some('4'), c); -/// -/// // Decimal 11 is a single digit in base 16 -/// let c = char::from_digit(11, 16); -/// -/// assert_eq!(Some('b'), c); -/// ``` -/// -/// Returning `None` when the input is not a digit: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(20, 10); -/// -/// assert_eq!(None, c); -/// ``` -/// -/// Passing a large radix, causing a panic: -/// -/// ``` -/// use std::thread; -/// use std::char; -/// -/// let result = thread::spawn(|| { -/// // this panics -/// let c = char::from_digit(1, 37); -/// }).join(); -/// -/// assert!(result.is_err()); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn from_digit(num: u32, radix: u32) -> Option<char> { - if radix > 36 { - panic!("from_digit: radix is too high (maximum 36)"); - } - if num < radix { - let num = num as u8; - if num < 10 { - Some((b'0' + num) as char) - } else { - Some((b'a' + num - 10) as char) - } - } else { - None - } -} - -// NB: the stabilization and documentation for this trait is in -// unicode/char.rs, not here -#[allow(missing_docs)] // docs in libunicode/u_char.rs -#[doc(hidden)] -#[unstable(feature = "core_char_ext", - reason = "the stable interface is `impl char` in later crate", - issue = "32110")] -pub trait CharExt { - #[stable(feature = "core", since = "1.6.0")] - fn is_digit(self, radix: u32) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn to_digit(self, radix: u32) -> Option<u32>; - #[stable(feature = "core", since = "1.6.0")] - fn escape_unicode(self) -> EscapeUnicode; - #[stable(feature = "core", since = "1.6.0")] - fn escape_default(self) -> EscapeDefault; - #[stable(feature = "char_escape_debug", since = "1.20.0")] - fn escape_debug(self) -> EscapeDebug; - #[stable(feature = "core", since = "1.6.0")] - fn len_utf8(self) -> usize; - #[stable(feature = "core", since = "1.6.0")] - fn len_utf16(self) -> usize; - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - fn encode_utf8(self, dst: &mut [u8]) -> &mut str; - #[stable(feature = "unicode_encode_char", since = "1.15.0")] - fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16]; -} - -#[stable(feature = "core", since = "1.6.0")] -impl CharExt for char { - #[inline] - fn is_digit(self, radix: u32) -> bool { - self.to_digit(radix).is_some() - } - - #[inline] - fn to_digit(self, radix: u32) -> Option<u32> { - if radix > 36 { - panic!("to_digit: radix is too high (maximum 36)"); - } - let val = match self { - '0' ... '9' => self as u32 - '0' as u32, - 'a' ... 'z' => self as u32 - 'a' as u32 + 10, - 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, - _ => return None, - }; - if val < radix { Some(val) } - else { None } - } - - #[inline] - fn escape_unicode(self) -> EscapeUnicode { - let c = self as u32; - - // or-ing 1 ensures that for c==0 the code computes that one - // digit should be printed and (which is the same) avoids the - // (31 - 32) underflow - let msb = 31 - (c | 1).leading_zeros(); - - // the index of the most significant hex digit - let ms_hex_digit = msb / 4; - EscapeUnicode { - c: self, - state: EscapeUnicodeState::Backslash, - hex_digit_idx: ms_hex_digit as usize, - } - } - - #[inline] - fn escape_default(self) -> EscapeDefault { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - '\x20' ... '\x7e' => EscapeDefaultState::Char(self), - _ => EscapeDefaultState::Unicode(self.escape_unicode()) - }; - EscapeDefault { state: init_state } - } - - #[inline] - fn escape_debug(self) -> EscapeDebug { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - c if is_printable(c) => EscapeDefaultState::Char(c), - c => EscapeDefaultState::Unicode(c.escape_unicode()), - }; - EscapeDebug(EscapeDefault { state: init_state }) - } - - #[inline] - fn len_utf8(self) -> usize { - let code = self as u32; - if code < MAX_ONE_B { - 1 - } else if code < MAX_TWO_B { - 2 - } else if code < MAX_THREE_B { - 3 - } else { - 4 - } - } - - #[inline] - fn len_utf16(self) -> usize { - let ch = self as u32; - if (ch & 0xFFFF) == ch { 1 } else { 2 } - } - - #[inline] - fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - let code = self as u32; - unsafe { - let len = - if code < MAX_ONE_B && !dst.is_empty() { - *dst.get_unchecked_mut(0) = code as u8; - 1 - } else if code < MAX_TWO_B && dst.len() >= 2 { - *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; - 2 - } else if code < MAX_THREE_B && dst.len() >= 3 { - *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; - 3 - } else if dst.len() >= 4 { - *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; - 4 - } else { - panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf8(), - code, - dst.len()) - }; - from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) - } - } - - #[inline] - fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { - let mut code = self as u32; - unsafe { - if (code & 0xFFFF) == code && !dst.is_empty() { - // The BMP falls through (assuming non-surrogate, as it should) - *dst.get_unchecked_mut(0) = code as u16; - slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) - } else if dst.len() >= 2 { - // Supplementary planes break into surrogates. - code -= 0x1_0000; - *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); - *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); - slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) - } else { - panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", - from_u32_unchecked(code).len_utf16(), - code, - dst.len()) - } - } - } -} - -/// Returns an iterator that yields the hexadecimal Unicode escape of a -/// character, as `char`s. -/// -/// This `struct` is created by the [`escape_unicode`] method on [`char`]. See -/// its documentation for more. -/// -/// [`escape_unicode`]: ../../std/primitive.char.html#method.escape_unicode -/// [`char`]: ../../std/primitive.char.html -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct EscapeUnicode { - c: char, - state: EscapeUnicodeState, - - // The index of the next hex digit to be printed (0 if none), - // i.e. the number of remaining hex digits to be printed; - // increasing from the least significant digit: 0x543210 - hex_digit_idx: usize, -} - -// The enum values are ordered so that their representation is the -// same as the remaining length (besides the hexadecimal digits). This -// likely makes `len()` a single load from memory) and inline-worth. -#[derive(Clone, Debug)] -enum EscapeUnicodeState { - Done, - RightBrace, - Value, - LeftBrace, - Type, - Backslash, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for EscapeUnicode { - type Item = char; - - fn next(&mut self) -> Option<char> { - match self.state { - EscapeUnicodeState::Backslash => { - self.state = EscapeUnicodeState::Type; - Some('\\') - } - EscapeUnicodeState::Type => { - self.state = EscapeUnicodeState::LeftBrace; - Some('u') - } - EscapeUnicodeState::LeftBrace => { - self.state = EscapeUnicodeState::Value; - Some('{') - } - EscapeUnicodeState::Value => { - let hex_digit = ((self.c as u32) >> (self.hex_digit_idx * 4)) & 0xf; - let c = from_digit(hex_digit, 16).unwrap(); - if self.hex_digit_idx == 0 { - self.state = EscapeUnicodeState::RightBrace; - } else { - self.hex_digit_idx -= 1; - } - Some(c) - } - EscapeUnicodeState::RightBrace => { - self.state = EscapeUnicodeState::Done; - Some('}') - } - EscapeUnicodeState::Done => None, - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - let n = self.len(); - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - fn last(self) -> Option<char> { - match self.state { - EscapeUnicodeState::Done => None, - - EscapeUnicodeState::RightBrace | - EscapeUnicodeState::Value | - EscapeUnicodeState::LeftBrace | - EscapeUnicodeState::Type | - EscapeUnicodeState::Backslash => Some('}'), - } - } -} - -#[stable(feature = "exact_size_escape", since = "1.11.0")] -impl ExactSizeIterator for EscapeUnicode { - #[inline] - fn len(&self) -> usize { - // The match is a single memory access with no branching - self.hex_digit_idx + match self.state { - EscapeUnicodeState::Done => 0, - EscapeUnicodeState::RightBrace => 1, - EscapeUnicodeState::Value => 2, - EscapeUnicodeState::LeftBrace => 3, - EscapeUnicodeState::Type => 4, - EscapeUnicodeState::Backslash => 5, - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for EscapeUnicode {} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for EscapeUnicode { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for c in self.clone() { - f.write_char(c)?; - } - Ok(()) - } -} - -/// An iterator that yields the literal escape code of a `char`. -/// -/// This `struct` is created by the [`escape_default`] method on [`char`]. See -/// its documentation for more. -/// -/// [`escape_default`]: ../../std/primitive.char.html#method.escape_default -/// [`char`]: ../../std/primitive.char.html -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct EscapeDefault { - state: EscapeDefaultState -} - -#[derive(Clone, Debug)] -enum EscapeDefaultState { - Done, - Char(char), - Backslash(char), - Unicode(EscapeUnicode), -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for EscapeDefault { - type Item = char; - - fn next(&mut self) -> Option<char> { - match self.state { - EscapeDefaultState::Backslash(c) => { - self.state = EscapeDefaultState::Char(c); - Some('\\') - } - EscapeDefaultState::Char(c) => { - self.state = EscapeDefaultState::Done; - Some(c) - } - EscapeDefaultState::Done => None, - EscapeDefaultState::Unicode(ref mut iter) => iter.next(), - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - let n = self.len(); - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - fn nth(&mut self, n: usize) -> Option<char> { - match self.state { - EscapeDefaultState::Backslash(c) if n == 0 => { - self.state = EscapeDefaultState::Char(c); - Some('\\') - }, - EscapeDefaultState::Backslash(c) if n == 1 => { - self.state = EscapeDefaultState::Done; - Some(c) - }, - EscapeDefaultState::Backslash(_) => { - self.state = EscapeDefaultState::Done; - None - }, - EscapeDefaultState::Char(c) => { - self.state = EscapeDefaultState::Done; - - if n == 0 { - Some(c) - } else { - None - } - }, - EscapeDefaultState::Done => return None, - EscapeDefaultState::Unicode(ref mut i) => return i.nth(n), - } - } - - fn last(self) -> Option<char> { - match self.state { - EscapeDefaultState::Unicode(iter) => iter.last(), - EscapeDefaultState::Done => None, - EscapeDefaultState::Backslash(c) | EscapeDefaultState::Char(c) => Some(c), - } - } -} - -#[stable(feature = "exact_size_escape", since = "1.11.0")] -impl ExactSizeIterator for EscapeDefault { - fn len(&self) -> usize { - match self.state { - EscapeDefaultState::Done => 0, - EscapeDefaultState::Char(_) => 1, - EscapeDefaultState::Backslash(_) => 2, - EscapeDefaultState::Unicode(ref iter) => iter.len(), - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for EscapeDefault {} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for EscapeDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for c in self.clone() { - f.write_char(c)?; - } - Ok(()) - } -} - -/// An iterator that yields the literal escape code of a `char`. -/// -/// This `struct` is created by the [`escape_debug`] method on [`char`]. See its -/// documentation for more. -/// -/// [`escape_debug`]: ../../std/primitive.char.html#method.escape_debug -/// [`char`]: ../../std/primitive.char.html -#[stable(feature = "char_escape_debug", since = "1.20.0")] -#[derive(Clone, Debug)] -pub struct EscapeDebug(EscapeDefault); - -#[stable(feature = "char_escape_debug", since = "1.20.0")] -impl Iterator for EscapeDebug { - type Item = char; - fn next(&mut self) -> Option<char> { self.0.next() } - fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() } -} - -#[stable(feature = "char_escape_debug", since = "1.20.0")] -impl ExactSizeIterator for EscapeDebug { } - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for EscapeDebug {} - -#[stable(feature = "char_escape_debug", since = "1.20.0")] -impl fmt::Display for EscapeDebug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - - - -/// An iterator over an iterator of bytes of the characters the bytes represent -/// as UTF-8 -#[unstable(feature = "decode_utf8", issue = "33906")] -#[derive(Clone, Debug)] -pub struct DecodeUtf8<I: Iterator<Item = u8>>(::iter::Peekable<I>); - -/// Decodes an `Iterator` of bytes as UTF-8. -#[unstable(feature = "decode_utf8", issue = "33906")] -#[inline] -pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter> { - DecodeUtf8(i.into_iter().peekable()) -} - -/// `<DecodeUtf8 as Iterator>::next` returns this for an invalid input sequence. -#[unstable(feature = "decode_utf8", issue = "33906")] -#[derive(PartialEq, Eq, Debug)] -pub struct InvalidSequence(()); - -#[unstable(feature = "decode_utf8", issue = "33906")] -impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> { - type Item = Result<char, InvalidSequence>; - #[inline] - - fn next(&mut self) -> Option<Result<char, InvalidSequence>> { - self.0.next().map(|first_byte| { - // Emit InvalidSequence according to - // Unicode §5.22 Best Practice for U+FFFD Substitution - // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630 - - // Roughly: consume at least one byte, - // then validate one byte at a time and stop before the first unexpected byte - // (which might be the valid start of the next byte sequence). - - let mut code_point; - macro_rules! first_byte { - ($mask: expr) => { - code_point = u32::from(first_byte & $mask) - } - } - macro_rules! continuation_byte { - () => { continuation_byte!(0x80...0xBF) }; - ($range: pat) => { - match self.0.peek() { - Some(&byte @ $range) => { - code_point = (code_point << 6) | u32::from(byte & 0b0011_1111); - self.0.next(); - } - _ => return Err(InvalidSequence(())) - } - } - } - - match first_byte { - 0x00...0x7F => { - first_byte!(0b1111_1111); - } - 0xC2...0xDF => { - first_byte!(0b0001_1111); - continuation_byte!(); - } - 0xE0 => { - first_byte!(0b0000_1111); - continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong - continuation_byte!(); - } - 0xE1...0xEC | 0xEE...0xEF => { - first_byte!(0b0000_1111); - continuation_byte!(); - continuation_byte!(); - } - 0xED => { - first_byte!(0b0000_1111); - continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates - continuation_byte!(); - } - 0xF0 => { - first_byte!(0b0000_0111); - continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong - continuation_byte!(); - continuation_byte!(); - } - 0xF1...0xF3 => { - first_byte!(0b0000_0111); - continuation_byte!(); - continuation_byte!(); - continuation_byte!(); - } - 0xF4 => { - first_byte!(0b0000_0111); - continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX - continuation_byte!(); - continuation_byte!(); - } - _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX - } - unsafe { - Ok(from_u32_unchecked(code_point)) - } - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - let (lower, upper) = self.0.size_hint(); - - // A code point is at most 4 bytes long. - let min_code_points = lower / 4; - - (min_code_points, upper) - } -} - -#[unstable(feature = "decode_utf8", issue = "33906")] -impl<I: FusedIterator<Item = u8>> FusedIterator for DecodeUtf8<I> {} diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs new file mode 100644 index 00000000000..150562a4a9b --- /dev/null +++ b/src/libcore/char/convert.rs @@ -0,0 +1,304 @@ +// Copyright 2012-2014 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. + +//! Character conversions. + +use convert::TryFrom; +use fmt; +use mem::transmute; +use str::FromStr; +use super::MAX; + +/// Converts a `u32` to a `char`. +/// +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with +/// [`as`]: +/// +/// ``` +/// let c = '💯'; +/// let i = c as u32; +/// +/// assert_eq!(128175, i); +/// ``` +/// +/// However, the reverse is not true: not all valid [`u32`]s are valid +/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value +/// for a [`char`]. +/// +/// [`char`]: ../../std/primitive.char.html +/// [`u32`]: ../../std/primitive.u32.html +/// [`as`]: ../../book/first-edition/casting-between-types.html#as +/// +/// For an unsafe version of this function which ignores these checks, see +/// [`from_u32_unchecked`]. +/// +/// [`from_u32_unchecked`]: fn.from_u32_unchecked.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_u32(0x2764); +/// +/// assert_eq!(Some('❤'), c); +/// ``` +/// +/// Returning `None` when the input is not a valid [`char`]: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_u32(0x110000); +/// +/// assert_eq!(None, c); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_u32(i: u32) -> Option<char> { + char::try_from(i).ok() +} + +/// Converts a `u32` to a `char`, ignoring validity. +/// +/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with +/// [`as`]: +/// +/// ``` +/// let c = '💯'; +/// let i = c as u32; +/// +/// assert_eq!(128175, i); +/// ``` +/// +/// However, the reverse is not true: not all valid [`u32`]s are valid +/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to +/// [`char`], possibly creating an invalid one. +/// +/// [`char`]: ../../std/primitive.char.html +/// [`u32`]: ../../std/primitive.u32.html +/// [`as`]: ../../book/first-edition/casting-between-types.html#as +/// +/// # Safety +/// +/// This function is unsafe, as it may construct invalid `char` values. +/// +/// For a safe version of this function, see the [`from_u32`] function. +/// +/// [`from_u32`]: fn.from_u32.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char; +/// +/// let c = unsafe { char::from_u32_unchecked(0x2764) }; +/// +/// assert_eq!('❤', c); +/// ``` +#[inline] +#[stable(feature = "char_from_unchecked", since = "1.5.0")] +pub unsafe fn from_u32_unchecked(i: u32) -> char { + transmute(i) +} + +#[stable(feature = "char_convert", since = "1.13.0")] +impl From<char> for u32 { + #[inline] + fn from(c: char) -> Self { + c as u32 + } +} + +/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF. +/// +/// Unicode is designed such that this effectively decodes bytes +/// with the character encoding that IANA calls ISO-8859-1. +/// This encoding is compatible with ASCII. +/// +/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen), +/// which leaves some "blanks", byte values that are not assigned to any character. +/// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes. +/// +/// Note that this is *also* different from Windows-1252 a.k.a. code page 1252, +/// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks +/// to punctuation and various Latin characters. +/// +/// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/) +/// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases +/// for a superset of Windows-1252 that fills the remaining blanks with corresponding +/// C0 and C1 control codes. +#[stable(feature = "char_convert", since = "1.13.0")] +impl From<u8> for char { + #[inline] + fn from(i: u8) -> Self { + i as char + } +} + + +/// An error which can be returned when parsing a char. +#[stable(feature = "char_from_str", since = "1.20.0")] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ParseCharError { + kind: CharErrorKind, +} + +impl ParseCharError { + #[unstable(feature = "char_error_internals", + reason = "this method should not be available publicly", + issue = "0")] + #[doc(hidden)] + pub fn __description(&self) -> &str { + match self.kind { + CharErrorKind::EmptyString => { + "cannot parse char from empty string" + }, + CharErrorKind::TooManyChars => "too many characters in string" + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum CharErrorKind { + EmptyString, + TooManyChars, +} + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl fmt::Display for ParseCharError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.__description().fmt(f) + } +} + + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl FromStr for char { + type Err = ParseCharError; + + #[inline] + fn from_str(s: &str) -> Result<Self, Self::Err> { + let mut chars = s.chars(); + match (chars.next(), chars.next()) { + (None, _) => { + Err(ParseCharError { kind: CharErrorKind::EmptyString }) + }, + (Some(c), None) => Ok(c), + _ => { + Err(ParseCharError { kind: CharErrorKind::TooManyChars }) + } + } + } +} + + +#[stable(feature = "try_from", since = "1.26.0")] +impl TryFrom<u32> for char { + type Error = CharTryFromError; + + #[inline] + fn try_from(i: u32) -> Result<Self, Self::Error> { + if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) { + Err(CharTryFromError(())) + } else { + Ok(unsafe { from_u32_unchecked(i) }) + } + } +} + +/// The error type returned when a conversion from u32 to char fails. +#[stable(feature = "try_from", since = "1.26.0")] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct CharTryFromError(()); + +#[stable(feature = "try_from", since = "1.26.0")] +impl fmt::Display for CharTryFromError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "converted integer out of range for `char`".fmt(f) + } +} + +/// Converts a digit in the given radix to a `char`. +/// +/// A 'radix' here is sometimes also called a 'base'. A radix of two +/// indicates a binary number, a radix of ten, decimal, and a radix of +/// sixteen, hexadecimal, to give some common values. Arbitrary +/// radices are supported. +/// +/// `from_digit()` will return `None` if the input is not a digit in +/// the given radix. +/// +/// # Panics +/// +/// Panics if given a radix larger than 36. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_digit(4, 10); +/// +/// assert_eq!(Some('4'), c); +/// +/// // Decimal 11 is a single digit in base 16 +/// let c = char::from_digit(11, 16); +/// +/// assert_eq!(Some('b'), c); +/// ``` +/// +/// Returning `None` when the input is not a digit: +/// +/// ``` +/// use std::char; +/// +/// let c = char::from_digit(20, 10); +/// +/// assert_eq!(None, c); +/// ``` +/// +/// Passing a large radix, causing a panic: +/// +/// ``` +/// use std::thread; +/// use std::char; +/// +/// let result = thread::spawn(|| { +/// // this panics +/// let c = char::from_digit(1, 37); +/// }).join(); +/// +/// assert!(result.is_err()); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_digit(num: u32, radix: u32) -> Option<char> { + if radix > 36 { + panic!("from_digit: radix is too high (maximum 36)"); + } + if num < radix { + let num = num as u8; + if num < 10 { + Some((b'0' + num) as char) + } else { + Some((b'a' + num - 10) as char) + } + } else { + None + } +} + diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs new file mode 100644 index 00000000000..48b531104f8 --- /dev/null +++ b/src/libcore/char/decode.rs @@ -0,0 +1,259 @@ +// Copyright 2012-2014 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. + +//! UTF-8 and UTF-16 decoding iterators + +use fmt; +use iter::FusedIterator; +use super::from_u32_unchecked; + +/// An iterator over an iterator of bytes of the characters the bytes represent +/// as UTF-8 +#[unstable(feature = "decode_utf8", issue = "33906")] +#[derive(Clone, Debug)] +pub struct DecodeUtf8<I: Iterator<Item = u8>>(::iter::Peekable<I>); + +/// Decodes an `Iterator` of bytes as UTF-8. +#[unstable(feature = "decode_utf8", issue = "33906")] +#[inline] +pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter> { + DecodeUtf8(i.into_iter().peekable()) +} + +/// `<DecodeUtf8 as Iterator>::next` returns this for an invalid input sequence. +#[unstable(feature = "decode_utf8", issue = "33906")] +#[derive(PartialEq, Eq, Debug)] +pub struct InvalidSequence(()); + +#[unstable(feature = "decode_utf8", issue = "33906")] +impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> { + type Item = Result<char, InvalidSequence>; + #[inline] + + fn next(&mut self) -> Option<Result<char, InvalidSequence>> { + self.0.next().map(|first_byte| { + // Emit InvalidSequence according to + // Unicode §5.22 Best Practice for U+FFFD Substitution + // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630 + + // Roughly: consume at least one byte, + // then validate one byte at a time and stop before the first unexpected byte + // (which might be the valid start of the next byte sequence). + + let mut code_point; + macro_rules! first_byte { + ($mask: expr) => { + code_point = u32::from(first_byte & $mask) + } + } + macro_rules! continuation_byte { + () => { continuation_byte!(0x80...0xBF) }; + ($range: pat) => { + match self.0.peek() { + Some(&byte @ $range) => { + code_point = (code_point << 6) | u32::from(byte & 0b0011_1111); + self.0.next(); + } + _ => return Err(InvalidSequence(())) + } + } + } + + match first_byte { + 0x00...0x7F => { + first_byte!(0b1111_1111); + } + 0xC2...0xDF => { + first_byte!(0b0001_1111); + continuation_byte!(); + } + 0xE0 => { + first_byte!(0b0000_1111); + continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong + continuation_byte!(); + } + 0xE1...0xEC | 0xEE...0xEF => { + first_byte!(0b0000_1111); + continuation_byte!(); + continuation_byte!(); + } + 0xED => { + first_byte!(0b0000_1111); + continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates + continuation_byte!(); + } + 0xF0 => { + first_byte!(0b0000_0111); + continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong + continuation_byte!(); + continuation_byte!(); + } + 0xF1...0xF3 => { + first_byte!(0b0000_0111); + continuation_byte!(); + continuation_byte!(); + continuation_byte!(); + } + 0xF4 => { + first_byte!(0b0000_0111); + continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX + continuation_byte!(); + continuation_byte!(); + } + _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX + } + unsafe { + Ok(from_u32_unchecked(code_point)) + } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let (lower, upper) = self.0.size_hint(); + + // A code point is at most 4 bytes long. + let min_code_points = lower / 4; + + (min_code_points, upper) + } +} + +#[unstable(feature = "decode_utf8", issue = "33906")] +impl<I: FusedIterator<Item = u8>> FusedIterator for DecodeUtf8<I> {} + +/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[derive(Clone, Debug)] +pub struct DecodeUtf16<I> + where I: Iterator<Item = u16> +{ + iter: I, + buf: Option<u16>, +} + +/// An error that can be returned when decoding UTF-16 code points. +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct DecodeUtf16Error { + code: u16, +} + +/// Create an iterator over the UTF-16 encoded code points in `iter`, +/// returning unpaired surrogates as `Err`s. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::char::decode_utf16; +/// +/// fn main() { +/// // 𝄞mus<invalid>ic<invalid> +/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, +/// 0x0073, 0xDD1E, 0x0069, 0x0063, +/// 0xD834]; +/// +/// assert_eq!(decode_utf16(v.iter().cloned()) +/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) +/// .collect::<Vec<_>>(), +/// vec![Ok('𝄞'), +/// Ok('m'), Ok('u'), Ok('s'), +/// Err(0xDD1E), +/// Ok('i'), Ok('c'), +/// Err(0xD834)]); +/// } +/// ``` +/// +/// A lossy decoder can be obtained by replacing `Err` results with the replacement character: +/// +/// ``` +/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; +/// +/// fn main() { +/// // 𝄞mus<invalid>ic<invalid> +/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, +/// 0x0073, 0xDD1E, 0x0069, 0x0063, +/// 0xD834]; +/// +/// assert_eq!(decode_utf16(v.iter().cloned()) +/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) +/// .collect::<String>(), +/// "𝄞mus�ic�"); +/// } +/// ``` +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[inline] +pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> { + DecodeUtf16 { + iter: iter.into_iter(), + buf: None, + } +} + +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> { + type Item = Result<char, DecodeUtf16Error>; + + fn next(&mut self) -> Option<Result<char, DecodeUtf16Error>> { + let u = match self.buf.take() { + Some(buf) => buf, + None => self.iter.next()? + }; + + if u < 0xD800 || 0xDFFF < u { + // not a surrogate + Some(Ok(unsafe { from_u32_unchecked(u as u32) })) + } else if u >= 0xDC00 { + // a trailing surrogate + Some(Err(DecodeUtf16Error { code: u })) + } else { + let u2 = match self.iter.next() { + Some(u2) => u2, + // eof + None => return Some(Err(DecodeUtf16Error { code: u })), + }; + if u2 < 0xDC00 || u2 > 0xDFFF { + // not a trailing surrogate so we're not a valid + // surrogate pair, so rewind to redecode u2 next time. + self.buf = Some(u2); + return Some(Err(DecodeUtf16Error { code: u })); + } + + // all ok, so lets decode it. + let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000; + Some(Ok(unsafe { from_u32_unchecked(c) })) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let (low, high) = self.iter.size_hint(); + // we could be entirely valid surrogates (2 elements per + // char), or entirely non-surrogates (1 element per char) + (low / 2, high) + } +} + +impl DecodeUtf16Error { + /// Returns the unpaired surrogate which caused this error. + #[stable(feature = "decode_utf16", since = "1.9.0")] + pub fn unpaired_surrogate(&self) -> u16 { + self.code + } +} + +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl fmt::Display for DecodeUtf16Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "unpaired surrogate found: {:x}", self.code) + } +} diff --git a/src/libstd_unicode/char.rs b/src/libcore/char/methods.rs index 33e47ade8cb..374adafef64 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libcore/char/methods.rs @@ -8,169 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A character type. -//! -//! The `char` type represents a single character. More specifically, since -//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode -//! scalar value]', which is similar to, but not the same as, a '[Unicode code -//! point]'. -//! -//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value -//! [Unicode code point]: http://www.unicode.org/glossary/#code_point -//! -//! This module exists for technical reasons, the primary documentation for -//! `char` is directly on [the `char` primitive type](../../std/primitive.char.html) -//! itself. -//! -//! This module is the home of the iterator implementations for the iterators -//! implemented on `char`, as well as some useful constants and conversion -//! functions that convert various types to `char`. +//! impl char {} -#![stable(feature = "rust1", since = "1.0.0")] - -use core::char::CharExt as C; -use core::iter::FusedIterator; -use core::fmt::{self, Write}; -use tables::{conversions, derived_property, general_category, property}; - -// stable re-exports -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::char::{EscapeDebug, EscapeDefault, EscapeUnicode}; -#[stable(feature = "char_from_str", since = "1.20.0")] -pub use core::char::ParseCharError; - -// unstable re-exports -#[stable(feature = "try_from", since = "1.26.0")] -pub use core::char::CharTryFromError; -#[unstable(feature = "decode_utf8", issue = "33906")] -pub use core::char::{DecodeUtf8, decode_utf8}; -#[unstable(feature = "unicode", issue = "27783")] -pub use tables::{UNICODE_VERSION}; -#[unstable(feature = "unicode", issue = "27783")] -pub use version::UnicodeVersion; - -/// Returns an iterator that yields the lowercase equivalent of a `char`. -/// -/// This `struct` is created by the [`to_lowercase`] method on [`char`]. See -/// its documentation for more. -/// -/// [`to_lowercase`]: ../../std/primitive.char.html#method.to_lowercase -/// [`char`]: ../../std/primitive.char.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug, Clone)] -pub struct ToLowercase(CaseMappingIter); - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ToLowercase { - type Item = char; - fn next(&mut self) -> Option<char> { - self.0.next() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for ToLowercase {} - -/// Returns an iterator that yields the uppercase equivalent of a `char`. -/// -/// This `struct` is created by the [`to_uppercase`] method on [`char`]. See -/// its documentation for more. -/// -/// [`to_uppercase`]: ../../std/primitive.char.html#method.to_uppercase -/// [`char`]: ../../std/primitive.char.html -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Debug, Clone)] -pub struct ToUppercase(CaseMappingIter); - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for ToUppercase { - type Item = char; - fn next(&mut self) -> Option<char> { - self.0.next() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for ToUppercase {} - -#[derive(Debug, Clone)] -enum CaseMappingIter { - Three(char, char, char), - Two(char, char), - One(char), - Zero, -} - -impl CaseMappingIter { - fn new(chars: [char; 3]) -> CaseMappingIter { - if chars[2] == '\0' { - if chars[1] == '\0' { - CaseMappingIter::One(chars[0]) // Including if chars[0] == '\0' - } else { - CaseMappingIter::Two(chars[0], chars[1]) - } - } else { - CaseMappingIter::Three(chars[0], chars[1], chars[2]) - } - } -} - -impl Iterator for CaseMappingIter { - type Item = char; - fn next(&mut self) -> Option<char> { - match *self { - CaseMappingIter::Three(a, b, c) => { - *self = CaseMappingIter::Two(b, c); - Some(a) - } - CaseMappingIter::Two(b, c) => { - *self = CaseMappingIter::One(c); - Some(b) - } - CaseMappingIter::One(c) => { - *self = CaseMappingIter::Zero; - Some(c) - } - CaseMappingIter::Zero => None, - } - } -} - -impl fmt::Display for CaseMappingIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CaseMappingIter::Three(a, b, c) => { - f.write_char(a)?; - f.write_char(b)?; - f.write_char(c) - } - CaseMappingIter::Two(b, c) => { - f.write_char(b)?; - f.write_char(c) - } - CaseMappingIter::One(c) => { - f.write_char(c) - } - CaseMappingIter::Zero => Ok(()), - } - } -} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for ToLowercase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -#[stable(feature = "char_struct_display", since = "1.16.0")] -impl fmt::Display for ToUppercase { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} +use slice; +use str::from_utf8_unchecked_mut; +use super::*; +use unicode::printable::is_printable; +use unicode::tables::{conversions, derived_property, general_category, property}; #[lang = "char"] impl char { @@ -223,7 +67,7 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn is_digit(self, radix: u32) -> bool { - C::is_digit(self, radix) + self.to_digit(radix).is_some() } /// Converts a `char` to a digit in the given radix. @@ -277,7 +121,17 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_digit(self, radix: u32) -> Option<u32> { - C::to_digit(self, radix) + if radix > 36 { + panic!("to_digit: radix is too high (maximum 36)"); + } + let val = match self { + '0' ... '9' => self as u32 - '0' as u32, + 'a' ... 'z' => self as u32 - 'a' as u32 + 10, + 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, + _ => return None, + }; + if val < radix { Some(val) } + else { None } } /// Returns an iterator that yields the hexadecimal Unicode escape of a @@ -317,7 +171,20 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn escape_unicode(self) -> EscapeUnicode { - C::escape_unicode(self) + let c = self as u32; + + // or-ing 1 ensures that for c==0 the code computes that one + // digit should be printed and (which is the same) avoids the + // (31 - 32) underflow + let msb = 31 - (c | 1).leading_zeros(); + + // the index of the most significant hex digit + let ms_hex_digit = msb / 4; + EscapeUnicode { + c: self, + state: EscapeUnicodeState::Backslash, + hex_digit_idx: ms_hex_digit as usize, + } } /// Returns an iterator that yields the literal escape code of a character @@ -357,7 +224,15 @@ impl char { #[stable(feature = "char_escape_debug", since = "1.20.0")] #[inline] pub fn escape_debug(self) -> EscapeDebug { - C::escape_debug(self) + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + c if is_printable(c) => EscapeDefaultState::Char(c), + c => EscapeDefaultState::Unicode(c.escape_unicode()), + }; + EscapeDebug(EscapeDefault { state: init_state }) } /// Returns an iterator that yields the literal escape code of a character @@ -412,7 +287,15 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn escape_default(self) -> EscapeDefault { - C::escape_default(self) + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()) + }; + EscapeDefault { state: init_state } } /// Returns the number of bytes this `char` would need if encoded in UTF-8. @@ -463,7 +346,16 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn len_utf8(self) -> usize { - C::len_utf8(self) + let code = self as u32; + if code < MAX_ONE_B { + 1 + } else if code < MAX_TWO_B { + 2 + } else if code < MAX_THREE_B { + 3 + } else { + 4 + } } /// Returns the number of 16-bit code units this `char` would need if @@ -488,7 +380,8 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn len_utf16(self) -> usize { - C::len_utf16(self) + let ch = self as u32; + if (ch & 0xFFFF) == ch { 1 } else { 2 } } /// Encodes this character as UTF-8 into the provided byte buffer, @@ -530,7 +423,35 @@ impl char { #[stable(feature = "unicode_encode_char", since = "1.15.0")] #[inline] pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { - C::encode_utf8(self, dst) + let code = self as u32; + unsafe { + let len = + if code < MAX_ONE_B && !dst.is_empty() { + *dst.get_unchecked_mut(0) = code as u8; + 1 + } else if code < MAX_TWO_B && dst.len() >= 2 { + *dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; + *dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT; + 2 + } else if code < MAX_THREE_B && dst.len() >= 3 { + *dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; + *dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT; + 3 + } else if dst.len() >= 4 { + *dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; + *dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; + *dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT; + 4 + } else { + panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf8(), + code, + dst.len()) + }; + from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) + } } /// Encodes this character as UTF-16 into the provided `u16` buffer, @@ -570,7 +491,25 @@ impl char { #[stable(feature = "unicode_encode_char", since = "1.15.0")] #[inline] pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { - C::encode_utf16(self, dst) + let mut code = self as u32; + unsafe { + if (code & 0xFFFF) == code && !dst.is_empty() { + // The BMP falls through (assuming non-surrogate, as it should) + *dst.get_unchecked_mut(0) = code as u16; + slice::from_raw_parts_mut(dst.as_mut_ptr(), 1) + } else if dst.len() >= 2 { + // Supplementary planes break into surrogates. + code -= 0x1_0000; + *dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16); + *dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF); + slice::from_raw_parts_mut(dst.as_mut_ptr(), 2) + } else { + panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}", + from_u32_unchecked(code).len_utf16(), + code, + dst.len()) + } + } } /// Returns true if this `char` is an alphabetic code point, and false if not. @@ -1452,140 +1391,3 @@ impl char { self.is_ascii() && (*self as u8).is_ascii_control() } } - -/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. -#[stable(feature = "decode_utf16", since = "1.9.0")] -#[derive(Clone, Debug)] -pub struct DecodeUtf16<I> - where I: Iterator<Item = u16> -{ - iter: I, - buf: Option<u16>, -} - -/// An error that can be returned when decoding UTF-16 code points. -#[stable(feature = "decode_utf16", since = "1.9.0")] -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct DecodeUtf16Error { - code: u16, -} - -/// Create an iterator over the UTF-16 encoded code points in `iter`, -/// returning unpaired surrogates as `Err`s. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char::decode_utf16; -/// -/// fn main() { -/// // 𝄞mus<invalid>ic<invalid> -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; -/// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) -/// .collect::<Vec<_>>(), -/// vec![Ok('𝄞'), -/// Ok('m'), Ok('u'), Ok('s'), -/// Err(0xDD1E), -/// Ok('i'), Ok('c'), -/// Err(0xD834)]); -/// } -/// ``` -/// -/// A lossy decoder can be obtained by replacing `Err` results with the replacement character: -/// -/// ``` -/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; -/// -/// fn main() { -/// // 𝄞mus<invalid>ic<invalid> -/// let v = [0xD834, 0xDD1E, 0x006d, 0x0075, -/// 0x0073, 0xDD1E, 0x0069, 0x0063, -/// 0xD834]; -/// -/// assert_eq!(decode_utf16(v.iter().cloned()) -/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) -/// .collect::<String>(), -/// "𝄞mus�ic�"); -/// } -/// ``` -#[stable(feature = "decode_utf16", since = "1.9.0")] -#[inline] -pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> { - DecodeUtf16 { - iter: iter.into_iter(), - buf: None, - } -} - -#[stable(feature = "decode_utf16", since = "1.9.0")] -impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> { - type Item = Result<char, DecodeUtf16Error>; - - fn next(&mut self) -> Option<Result<char, DecodeUtf16Error>> { - let u = match self.buf.take() { - Some(buf) => buf, - None => self.iter.next()? - }; - - if u < 0xD800 || 0xDFFF < u { - // not a surrogate - Some(Ok(unsafe { from_u32_unchecked(u as u32) })) - } else if u >= 0xDC00 { - // a trailing surrogate - Some(Err(DecodeUtf16Error { code: u })) - } else { - let u2 = match self.iter.next() { - Some(u2) => u2, - // eof - None => return Some(Err(DecodeUtf16Error { code: u })), - }; - if u2 < 0xDC00 || u2 > 0xDFFF { - // not a trailing surrogate so we're not a valid - // surrogate pair, so rewind to redecode u2 next time. - self.buf = Some(u2); - return Some(Err(DecodeUtf16Error { code: u })); - } - - // all ok, so lets decode it. - let c = (((u - 0xD800) as u32) << 10 | (u2 - 0xDC00) as u32) + 0x1_0000; - Some(Ok(unsafe { from_u32_unchecked(c) })) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - let (low, high) = self.iter.size_hint(); - // we could be entirely valid surrogates (2 elements per - // char), or entirely non-surrogates (1 element per char) - (low / 2, high) - } -} - -impl DecodeUtf16Error { - /// Returns the unpaired surrogate which caused this error. - #[stable(feature = "decode_utf16", since = "1.9.0")] - pub fn unpaired_surrogate(&self) -> u16 { - self.code - } -} - -#[stable(feature = "decode_utf16", since = "1.9.0")] -impl fmt::Display for DecodeUtf16Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "unpaired surrogate found: {:x}", self.code) - } -} - -/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a -/// decoding error. -/// -/// It can occur, for example, when giving ill-formed UTF-8 bytes to -/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy). -#[stable(feature = "decode_utf16", since = "1.9.0")] -pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs new file mode 100644 index 00000000000..9edc0c88756 --- /dev/null +++ b/src/libcore/char/mod.rs @@ -0,0 +1,506 @@ +// Copyright 2012-2014 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. + +//! A character type. +//! +//! The `char` type represents a single character. More specifically, since +//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode +//! scalar value]', which is similar to, but not the same as, a '[Unicode code +//! point]'. +//! +//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value +//! [Unicode code point]: http://www.unicode.org/glossary/#code_point +//! +//! This module exists for technical reasons, the primary documentation for +//! `char` is directly on [the `char` primitive type](../../std/primitive.char.html) +//! itself. +//! +//! This module is the home of the iterator implementations for the iterators +//! implemented on `char`, as well as some useful constants and conversion +//! functions that convert various types to `char`. + +#![allow(non_snake_case)] +#![stable(feature = "core_char", since = "1.2.0")] + +mod convert; +mod decode; +mod methods; + +// stable re-exports +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::convert::{from_u32, from_digit}; +#[stable(feature = "char_from_unchecked", since = "1.5.0")] +pub use self::convert::from_u32_unchecked; +#[stable(feature = "char_from_str", since = "1.20.0")] +pub use self::convert::ParseCharError; +#[stable(feature = "try_from", since = "1.26.0")] +pub use self::convert::CharTryFromError; +#[stable(feature = "decode_utf16", since = "1.9.0")] +pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; + +// unstable re-exports +#[unstable(feature = "unicode_version", issue = "49726")] +pub use unicode::tables::UNICODE_VERSION; +#[unstable(feature = "unicode_version", issue = "49726")] +pub use unicode::version::UnicodeVersion; +#[unstable(feature = "decode_utf8", issue = "33906")] +pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence}; + +use fmt::{self, Write}; +use iter::FusedIterator; + +// UTF-8 ranges and tags for encoding characters +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_THREE_B: u8 = 0b1110_0000; +const TAG_FOUR_B: u8 = 0b1111_0000; +const MAX_ONE_B: u32 = 0x80; +const MAX_TWO_B: u32 = 0x800; +const MAX_THREE_B: u32 = 0x10000; + +/* + Lu Uppercase_Letter an uppercase letter + Ll Lowercase_Letter a lowercase letter + Lt Titlecase_Letter a digraphic character, with first part uppercase + Lm Modifier_Letter a modifier letter + Lo Other_Letter other letters, including syllables and ideographs + Mn Nonspacing_Mark a nonspacing combining mark (zero advance width) + Mc Spacing_Mark a spacing combining mark (positive advance width) + Me Enclosing_Mark an enclosing combining mark + Nd Decimal_Number a decimal digit + Nl Letter_Number a letterlike numeric character + No Other_Number a numeric character of other type + Pc Connector_Punctuation a connecting punctuation mark, like a tie + Pd Dash_Punctuation a dash or hyphen punctuation mark + Ps Open_Punctuation an opening punctuation mark (of a pair) + Pe Close_Punctuation a closing punctuation mark (of a pair) + Pi Initial_Punctuation an initial quotation mark + Pf Final_Punctuation a final quotation mark + Po Other_Punctuation a punctuation mark of other type + Sm Math_Symbol a symbol of primarily mathematical use + Sc Currency_Symbol a currency sign + Sk Modifier_Symbol a non-letterlike modifier symbol + So Other_Symbol a symbol of other type + Zs Space_Separator a space character (of various non-zero widths) + Zl Line_Separator U+2028 LINE SEPARATOR only + Zp Paragraph_Separator U+2029 PARAGRAPH SEPARATOR only + Cc Control a C0 or C1 control code + Cf Format a format control character + Cs Surrogate a surrogate code point + Co Private_Use a private-use character + Cn Unassigned a reserved unassigned code point or a noncharacter +*/ + +/// The highest valid code point a `char` can have. +/// +/// A [`char`] is a [Unicode Scalar Value], which means that it is a [Code +/// Point], but only ones within a certain range. `MAX` is the highest valid +/// code point that's a valid [Unicode Scalar Value]. +/// +/// [`char`]: ../../std/primitive.char.html +/// [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value +/// [Code Point]: http://www.unicode.org/glossary/#code_point +#[stable(feature = "rust1", since = "1.0.0")] +pub const MAX: char = '\u{10ffff}'; + +/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a +/// decoding error. +/// +/// It can occur, for example, when giving ill-formed UTF-8 bytes to +/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy). +#[stable(feature = "decode_utf16", since = "1.9.0")] +pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}'; + +/// Returns an iterator that yields the hexadecimal Unicode escape of a +/// character, as `char`s. +/// +/// This `struct` is created by the [`escape_unicode`] method on [`char`]. See +/// its documentation for more. +/// +/// [`escape_unicode`]: ../../std/primitive.char.html#method.escape_unicode +/// [`char`]: ../../std/primitive.char.html +#[derive(Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct EscapeUnicode { + c: char, + state: EscapeUnicodeState, + + // The index of the next hex digit to be printed (0 if none), + // i.e. the number of remaining hex digits to be printed; + // increasing from the least significant digit: 0x543210 + hex_digit_idx: usize, +} + +// The enum values are ordered so that their representation is the +// same as the remaining length (besides the hexadecimal digits). This +// likely makes `len()` a single load from memory) and inline-worth. +#[derive(Clone, Debug)] +enum EscapeUnicodeState { + Done, + RightBrace, + Value, + LeftBrace, + Type, + Backslash, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for EscapeUnicode { + type Item = char; + + fn next(&mut self) -> Option<char> { + match self.state { + EscapeUnicodeState::Backslash => { + self.state = EscapeUnicodeState::Type; + Some('\\') + } + EscapeUnicodeState::Type => { + self.state = EscapeUnicodeState::LeftBrace; + Some('u') + } + EscapeUnicodeState::LeftBrace => { + self.state = EscapeUnicodeState::Value; + Some('{') + } + EscapeUnicodeState::Value => { + let hex_digit = ((self.c as u32) >> (self.hex_digit_idx * 4)) & 0xf; + let c = from_digit(hex_digit, 16).unwrap(); + if self.hex_digit_idx == 0 { + self.state = EscapeUnicodeState::RightBrace; + } else { + self.hex_digit_idx -= 1; + } + Some(c) + } + EscapeUnicodeState::RightBrace => { + self.state = EscapeUnicodeState::Done; + Some('}') + } + EscapeUnicodeState::Done => None, + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let n = self.len(); + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + fn last(self) -> Option<char> { + match self.state { + EscapeUnicodeState::Done => None, + + EscapeUnicodeState::RightBrace | + EscapeUnicodeState::Value | + EscapeUnicodeState::LeftBrace | + EscapeUnicodeState::Type | + EscapeUnicodeState::Backslash => Some('}'), + } + } +} + +#[stable(feature = "exact_size_escape", since = "1.11.0")] +impl ExactSizeIterator for EscapeUnicode { + #[inline] + fn len(&self) -> usize { + // The match is a single memory access with no branching + self.hex_digit_idx + match self.state { + EscapeUnicodeState::Done => 0, + EscapeUnicodeState::RightBrace => 1, + EscapeUnicodeState::Value => 2, + EscapeUnicodeState::LeftBrace => 3, + EscapeUnicodeState::Type => 4, + EscapeUnicodeState::Backslash => 5, + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for EscapeUnicode {} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for EscapeUnicode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.clone() { + f.write_char(c)?; + } + Ok(()) + } +} + +/// An iterator that yields the literal escape code of a `char`. +/// +/// This `struct` is created by the [`escape_default`] method on [`char`]. See +/// its documentation for more. +/// +/// [`escape_default`]: ../../std/primitive.char.html#method.escape_default +/// [`char`]: ../../std/primitive.char.html +#[derive(Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct EscapeDefault { + state: EscapeDefaultState +} + +#[derive(Clone, Debug)] +enum EscapeDefaultState { + Done, + Char(char), + Backslash(char), + Unicode(EscapeUnicode), +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for EscapeDefault { + type Item = char; + + fn next(&mut self) -> Option<char> { + match self.state { + EscapeDefaultState::Backslash(c) => { + self.state = EscapeDefaultState::Char(c); + Some('\\') + } + EscapeDefaultState::Char(c) => { + self.state = EscapeDefaultState::Done; + Some(c) + } + EscapeDefaultState::Done => None, + EscapeDefaultState::Unicode(ref mut iter) => iter.next(), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let n = self.len(); + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + fn nth(&mut self, n: usize) -> Option<char> { + match self.state { + EscapeDefaultState::Backslash(c) if n == 0 => { + self.state = EscapeDefaultState::Char(c); + Some('\\') + }, + EscapeDefaultState::Backslash(c) if n == 1 => { + self.state = EscapeDefaultState::Done; + Some(c) + }, + EscapeDefaultState::Backslash(_) => { + self.state = EscapeDefaultState::Done; + None + }, + EscapeDefaultState::Char(c) => { + self.state = EscapeDefaultState::Done; + + if n == 0 { + Some(c) + } else { + None + } + }, + EscapeDefaultState::Done => return None, + EscapeDefaultState::Unicode(ref mut i) => return i.nth(n), + } + } + + fn last(self) -> Option<char> { + match self.state { + EscapeDefaultState::Unicode(iter) => iter.last(), + EscapeDefaultState::Done => None, + EscapeDefaultState::Backslash(c) | EscapeDefaultState::Char(c) => Some(c), + } + } +} + +#[stable(feature = "exact_size_escape", since = "1.11.0")] +impl ExactSizeIterator for EscapeDefault { + fn len(&self) -> usize { + match self.state { + EscapeDefaultState::Done => 0, + EscapeDefaultState::Char(_) => 1, + EscapeDefaultState::Backslash(_) => 2, + EscapeDefaultState::Unicode(ref iter) => iter.len(), + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for EscapeDefault {} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for EscapeDefault { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.clone() { + f.write_char(c)?; + } + Ok(()) + } +} + +/// An iterator that yields the literal escape code of a `char`. +/// +/// This `struct` is created by the [`escape_debug`] method on [`char`]. See its +/// documentation for more. +/// +/// [`escape_debug`]: ../../std/primitive.char.html#method.escape_debug +/// [`char`]: ../../std/primitive.char.html +#[stable(feature = "char_escape_debug", since = "1.20.0")] +#[derive(Clone, Debug)] +pub struct EscapeDebug(EscapeDefault); + +#[stable(feature = "char_escape_debug", since = "1.20.0")] +impl Iterator for EscapeDebug { + type Item = char; + fn next(&mut self) -> Option<char> { self.0.next() } + fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() } +} + +#[stable(feature = "char_escape_debug", since = "1.20.0")] +impl ExactSizeIterator for EscapeDebug { } + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for EscapeDebug {} + +#[stable(feature = "char_escape_debug", since = "1.20.0")] +impl fmt::Display for EscapeDebug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +/// Returns an iterator that yields the lowercase equivalent of a `char`. +/// +/// This `struct` is created by the [`to_lowercase`] method on [`char`]. See +/// its documentation for more. +/// +/// [`to_lowercase`]: ../../std/primitive.char.html#method.to_lowercase +/// [`char`]: ../../std/primitive.char.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug, Clone)] +pub struct ToLowercase(CaseMappingIter); + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for ToLowercase { + type Item = char; + fn next(&mut self) -> Option<char> { + self.0.next() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ToLowercase {} + +/// Returns an iterator that yields the uppercase equivalent of a `char`. +/// +/// This `struct` is created by the [`to_uppercase`] method on [`char`]. See +/// its documentation for more. +/// +/// [`to_uppercase`]: ../../std/primitive.char.html#method.to_uppercase +/// [`char`]: ../../std/primitive.char.html +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Debug, Clone)] +pub struct ToUppercase(CaseMappingIter); + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for ToUppercase { + type Item = char; + fn next(&mut self) -> Option<char> { + self.0.next() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ToUppercase {} + +#[derive(Debug, Clone)] +enum CaseMappingIter { + Three(char, char, char), + Two(char, char), + One(char), + Zero, +} + +impl CaseMappingIter { + fn new(chars: [char; 3]) -> CaseMappingIter { + if chars[2] == '\0' { + if chars[1] == '\0' { + CaseMappingIter::One(chars[0]) // Including if chars[0] == '\0' + } else { + CaseMappingIter::Two(chars[0], chars[1]) + } + } else { + CaseMappingIter::Three(chars[0], chars[1], chars[2]) + } + } +} + +impl Iterator for CaseMappingIter { + type Item = char; + fn next(&mut self) -> Option<char> { + match *self { + CaseMappingIter::Three(a, b, c) => { + *self = CaseMappingIter::Two(b, c); + Some(a) + } + CaseMappingIter::Two(b, c) => { + *self = CaseMappingIter::One(c); + Some(b) + } + CaseMappingIter::One(c) => { + *self = CaseMappingIter::Zero; + Some(c) + } + CaseMappingIter::Zero => None, + } + } +} + +impl fmt::Display for CaseMappingIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + CaseMappingIter::Three(a, b, c) => { + f.write_char(a)?; + f.write_char(b)?; + f.write_char(c) + } + CaseMappingIter::Two(b, c) => { + f.write_char(b)?; + f.write_char(c) + } + CaseMappingIter::One(c) => { + f.write_char(c) + } + CaseMappingIter::Zero => Ok(()), + } + } +} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for ToLowercase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +#[stable(feature = "char_struct_display", since = "1.16.0")] +impl fmt::Display for ToUppercase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index cf9abb26d3e..5ebd9e4334c 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -63,7 +63,6 @@ #![no_core] #![deny(missing_docs)] #![deny(missing_debug_implementations)] -#![deny(warnings)] #![feature(allow_internal_unstable)] #![feature(asm)] @@ -76,6 +75,7 @@ #![feature(custom_attribute)] #![feature(doc_cfg)] #![feature(doc_spotlight)] +#![feature(extern_types)] #![feature(fn_must_use)] #![feature(fundamental)] #![feature(intrinsics)] @@ -181,12 +181,20 @@ pub mod hash; pub mod fmt; pub mod time; +pub mod unicode; + /* Heap memory allocator trait */ #[allow(missing_docs)] -pub mod heap; +pub mod alloc; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +/// Use the `alloc` module instead. +pub mod heap { + pub use alloc::*; +} // note: does not need to be public -mod char_private; mod iter_private; mod tuple; mod unit; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index dcda404721c..35d70609c19 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -644,6 +644,32 @@ $EndFeature, " } doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, +returning `None` if `rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +assert_eq!((", stringify!($SelfT), +"::min_value() + 1).checked_div_euc(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::min_value().checked_div_euc(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div_euc(0), None); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_div_euc(self, rhs: Self) -> Option<Self> { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(self.div_euc(rhs)) + } + } + } + + doc_comment! { concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0` or the division results in overflow. @@ -671,6 +697,33 @@ $EndFeature, " } doc_comment! { + concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None` if +`rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_mod_euc(-1), None); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_mod_euc(self, rhs: Self) -> Option<Self> { + if rhs == 0 || (self == Self::min_value() && rhs == -1) { + None + } else { + Some(self.mod_euc(rhs)) + } + } + } + + doc_comment! { concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. # Examples @@ -1004,6 +1057,34 @@ $EndFeature, " } doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`, +wrapping around at the boundary of the type. + +Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value +for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the +type. In this case, this method returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10); +assert_eq!((-128i8).wrapping_div_euc(-1), -128); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_div_euc(self, rhs: Self) -> Self { + self.overflowing_div_euc(rhs).0 + } + } + + doc_comment! { concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the boundary of the type. @@ -1032,6 +1113,33 @@ $EndFeature, " } doc_comment! { + concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`, wrapping around at the +boundary of the type. + +Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value +for the type). In this case, this method returns 0. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0); +assert_eq!((-128i8).wrapping_mod_euc(-1), 0); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_mod_euc(self, rhs: Self) -> Self { + self.overflowing_mod_euc(rhs).0 + } + } + + doc_comment! { concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary of the type. @@ -1297,6 +1405,39 @@ $EndFeature, " } doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then `self` is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euc(-1), (", stringify!($SelfT), +"::MIN, true)); +```"), + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (self, true) + } else { + (self.div_euc(rhs), false) + } + } + } + + doc_comment! { concat!("Calculates the remainder when `self` is divided by `rhs`. Returns a tuple of the remainder after dividing along with a boolean indicating whether an @@ -1328,6 +1469,40 @@ $EndFeature, " } } + + doc_comment! { + concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +use std::", stringify!($SelfT), "; + +assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_mod_euc(-1), (0, true)); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) { + if self == Self::min_value() && rhs == -1 { + (0, true) + } else { + (self.mod_euc(rhs), false) + } + } + } + + doc_comment! { concat!("Negates self, overflowing if this is equal to the minimum value. @@ -1523,6 +1698,80 @@ $EndFeature, " } doc_comment! { + concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. + +This computes the integer `n` such that `self = n * rhs + self.mod_euc(rhs)`. +In other words, the result is `self / rhs` rounded to the integer `n` +such that `self >= n * rhs`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.div_euc(b), 1); // 7 >= 4 * 1 +assert_eq!(a.div_euc(-b), -1); // 7 >= -4 * -1 +assert_eq!((-a).div_euc(b), -2); // -7 >= 4 * -2 +assert_eq!((-a).div_euc(-b), 2); // -7 >= -4 * 2 +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn div_euc(self, rhs: Self) -> Self { + let q = self / rhs; + if self % rhs < 0 { + return if rhs > 0 { q - 1 } else { q + 1 } + } + q + } + } + + + doc_comment! { + concat!("Calculates the remainder `self mod rhs` by Euclidean division. + +In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.mod_euc(b), 3); +assert_eq!((-a).mod_euc(b), 1); +assert_eq!(a.mod_euc(-b), 3); +assert_eq!((-a).mod_euc(-b), 1); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn mod_euc(self, rhs: Self) -> Self { + let r = self % rhs; + if r < 0 { + r + rhs.abs() + } else { + r + } + } + } + + doc_comment! { concat!("Computes the absolute value of `self`. # Overflow behavior @@ -2110,6 +2359,31 @@ assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " } doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euc(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div_euc(0), None); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_div_euc(self, rhs: Self) -> Option<Self> { + if rhs == 0 { + None + } else { + Some(self.div_euc(rhs)) + } + } + } + + + doc_comment! { concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if `rhs == 0`. @@ -2133,6 +2407,30 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " } doc_comment! { + concat!("Checked Euclidean modulo. Computes `self.mod_euc(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_mod_euc(0), None); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn checked_mod_euc(self, rhs: Self) -> Option<Self> { + if rhs == 0 { + None + } else { + Some(self.mod_euc(rhs)) + } + } + } + + doc_comment! { concat!("Checked negation. Computes `-self`, returning `None` unless `self == 0`. @@ -2412,6 +2710,28 @@ Basic usage: } doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euc(rhs)`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euc(10), 10); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_div_euc(self, rhs: Self) -> Self { + self / rhs + } + } + + doc_comment! { concat!("Wrapping (modular) remainder. Computes `self % rhs`. Wrapped remainder calculation on unsigned types is just the regular remainder calculation. @@ -2433,6 +2753,29 @@ Basic usage: } } + doc_comment! { + concat!("Wrapping Euclidean modulo. Computes `self.mod_euc(rhs)`. +Wrapped modulo calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +assert_eq!(100", stringify!($SelfT), ".wrapping_mod_euc(10), 0); +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + pub fn wrapping_mod_euc(self, rhs: Self) -> Self { + self % rhs + } + } + /// Wrapping (modular) negation. Computes `-self`, /// wrapping around at the boundary of the type. /// @@ -2667,6 +3010,33 @@ Basic usage } doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euc(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +#![feature(euclidean_division)] +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euc(2), (2, false)); +```"), + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn overflowing_div_euc(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } + } + + doc_comment! { concat!("Calculates the remainder when `self` is divided by `rhs`. Returns a tuple of the remainder after dividing along with a boolean @@ -2693,6 +3063,33 @@ Basic usage } doc_comment! { + concat!("Calculates the remainder `self.mod_euc(rhs)` by Euclidean division. + +Returns a tuple of the modulo after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +#![feature(euclidean_division)] +assert_eq!(5", stringify!($SelfT), ".overflowing_mod_euc(2), (1, false)); +```"), + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn overflowing_mod_euc(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } + } + + doc_comment! { concat!("Negates self in an overflowing fashion. Returns `!self + 1` using wrapping operations to return the value @@ -2849,6 +3246,49 @@ Basic usage: } } + doc_comment! { + concat!("Performs Euclidean division. + +For unsigned types, this is just the same as `self / rhs`. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +assert_eq!(7", stringify!($SelfT), ".div_euc(4), 1); // or any other integer type +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn div_euc(self, rhs: Self) -> Self { + self / rhs + } + } + + + doc_comment! { + concat!("Calculates the remainder `self mod rhs` by Euclidean division. + +For unsigned types, this is just the same as `self % rhs`. + +# Examples + +Basic usage: + +``` +#![feature(euclidean_division)] +assert_eq!(7", stringify!($SelfT), ".mod_euc(4), 3); // or any other integer type +```"), + #[unstable(feature = "euclidean_division", issue = "49048")] + #[inline] + #[rustc_inherit_overflow_checks] + pub fn mod_euc(self, rhs: Self) -> Self { + self % rhs + } + } + doc_comment! { concat!("Returns `true` if and only if `self == 2^k` for some `k`. diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 61ef6798b2e..0dfdabee031 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -628,8 +628,6 @@ impl<T> Option<T> { /// # Examples /// /// ```rust - /// #![feature(option_filter)] - /// /// fn is_even(n: &i32) -> bool { /// n % 2 == 0 /// } @@ -639,7 +637,7 @@ impl<T> Option<T> { /// assert_eq!(Some(4).filter(is_even), Some(4)); /// ``` #[inline] - #[unstable(feature = "option_filter", issue = "45860")] + #[stable(feature = "option_filter", since = "1.27.0")] pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self { if let Some(x) = self { if predicate(&x) { diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index d43496c387c..cc3ad71117a 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -62,6 +62,3 @@ pub use slice::SliceExt; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use str::StrExt; -#[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] -pub use char::CharExt; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5a54de06b5e..4a7d7c410eb 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -677,6 +677,7 @@ impl<T: ?Sized> *const T { /// /// ``` /// #![feature(offset_to)] + /// #![allow(deprecated)] /// /// fn main() { /// let a = [0; 5]; @@ -689,14 +690,15 @@ impl<T: ?Sized> *const T { /// } /// ``` #[unstable(feature = "offset_to", issue = "41079")] + #[rustc_deprecated(since = "1.27.0", reason = "Replaced by `wrapping_offset_from`, with the \ + opposite argument order. If you're writing unsafe code, consider `offset_from`.")] #[inline] pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized { let size = mem::size_of::<T>(); if size == 0 { None } else { - let diff = (other as isize).wrapping_sub(self as isize); - Some(diff / size as isize) + Some(other.wrapping_offset_from(self)) } } @@ -1442,6 +1444,7 @@ impl<T: ?Sized> *mut T { /// /// ``` /// #![feature(offset_to)] + /// #![allow(deprecated)] /// /// fn main() { /// let mut a = [0; 5]; @@ -1454,14 +1457,15 @@ impl<T: ?Sized> *mut T { /// } /// ``` #[unstable(feature = "offset_to", issue = "41079")] + #[rustc_deprecated(since = "1.27.0", reason = "Replaced by `wrapping_offset_from`, with the \ + opposite argument order. If you're writing unsafe code, consider `offset_from`.")] #[inline] pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized { let size = mem::size_of::<T>(); if size == 0 { None } else { - let diff = (other as isize).wrapping_sub(self as isize); - Some(diff / size as isize) + Some(other.wrapping_offset_from(self)) } } @@ -2746,6 +2750,14 @@ impl<T: ?Sized> NonNull<T> { NonNull::new_unchecked(self.as_ptr() as *mut U) } } + + /// Cast to an `Opaque` pointer + #[unstable(feature = "allocator_api", issue = "32838")] + pub fn as_opaque(self) -> NonNull<::alloc::Opaque> { + unsafe { + NonNull::new_unchecked(self.as_ptr() as _) + } + } } #[stable(feature = "nonnull", since = "1.25.0")] diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0f1b7cb8fcc..0a22028da81 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1185,7 +1185,7 @@ macro_rules! iterator { #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - let exact = ptrdistance(self.ptr, self.end); + let exact = unsafe { ptrdistance(self.ptr, self.end) }; (exact, Some(exact)) } @@ -1593,10 +1593,11 @@ unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} // Return the number of elements of `T` from `start` to `end`. // Return the arithmetic difference if `T` is zero size. #[inline(always)] -fn ptrdistance<T>(start: *const T, end: *const T) -> usize { - match start.offset_to(end) { - Some(x) => x as usize, - None => (end as usize).wrapping_sub(start as usize), +unsafe fn ptrdistance<T>(start: *const T, end: *const T) -> usize { + if mem::size_of::<T>() == 0 { + (end as usize).wrapping_sub(start as usize) + } else { + end.offset_from(start) as usize } } diff --git a/src/libstd_unicode/lossy.rs b/src/libcore/str/lossy.rs index cc8e93308a5..30b7267da7c 100644 --- a/src/libstd_unicode/lossy.rs +++ b/src/libcore/str/lossy.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::str as core_str; -use core::fmt; -use core::fmt::Write; use char; -use core::mem; - +use str as core_str; +use fmt; +use fmt::Write; +use mem; /// Lossy UTF-8 string. #[unstable(feature = "str_internals", issue = "0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 1185b7acaae..f1fe23092de 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -19,13 +19,17 @@ use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char; use fmt; -use iter::{Map, Cloned, FusedIterator, TrustedLen}; +use iter::{Map, Cloned, FusedIterator, TrustedLen, Filter}; use iter_private::TrustedRandomAccess; use slice::{self, SliceIndex}; use mem; pub mod pattern; +#[unstable(feature = "str_internals", issue = "0")] +#[allow(missing_docs)] +pub mod lossy; + /// A trait to abstract the idea of creating a new instance of a type from a /// string. /// @@ -2212,6 +2216,18 @@ pub trait StrExt { fn is_empty(&self) -> bool; #[stable(feature = "core", since = "1.6.0")] fn parse<T: FromStr>(&self) -> Result<T, T::Err>; + #[stable(feature = "split_whitespace", since = "1.1.0")] + fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; + #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] + fn is_whitespace(&self) -> bool; + #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] + fn is_alphanumeric(&self) -> bool; + #[stable(feature = "rust1", since = "1.0.0")] + fn trim(&self) -> &str; + #[stable(feature = "rust1", since = "1.0.0")] + fn trim_left(&self) -> &str; + #[stable(feature = "rust1", since = "1.0.0")] + fn trim_right(&self) -> &str; } // truncate `&str` to length at most equal to `max` @@ -2532,6 +2548,36 @@ impl StrExt for str { #[inline] fn parse<T: FromStr>(&self) -> Result<T, T::Err> { FromStr::from_str(self) } + + #[inline] + fn split_whitespace(&self) -> SplitWhitespace { + SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } + } + + #[inline] + fn is_whitespace(&self) -> bool { + self.chars().all(|c| c.is_whitespace()) + } + + #[inline] + fn is_alphanumeric(&self) -> bool { + self.chars().all(|c| c.is_alphanumeric()) + } + + #[inline] + fn trim(&self) -> &str { + self.trim_matches(|c: char| c.is_whitespace()) + } + + #[inline] + fn trim_left(&self) -> &str { + self.trim_left_matches(|c: char| c.is_whitespace()) + } + + #[inline] + fn trim_right(&self) -> &str { + self.trim_right_matches(|c: char| c.is_whitespace()) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2547,3 +2593,75 @@ impl<'a> Default for &'a str { /// Creates an empty str fn default() -> &'a str { "" } } + +/// An iterator over the non-whitespace substrings of a string, +/// separated by any amount of whitespace. +/// +/// This struct is created by the [`split_whitespace`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace +/// [`str`]: ../../std/primitive.str.html +#[stable(feature = "split_whitespace", since = "1.1.0")] +#[derive(Clone, Debug)] +pub struct SplitWhitespace<'a> { + inner: Filter<Split<'a, IsWhitespace>, IsNotEmpty>, +} + +#[derive(Clone)] +struct IsWhitespace; + +impl FnOnce<(char, )> for IsWhitespace { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool { + self.call_mut(arg) + } +} + +impl FnMut<(char, )> for IsWhitespace { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool { + arg.0.is_whitespace() + } +} + +#[derive(Clone)] +struct IsNotEmpty; + +impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { + self.call_mut(arg) + } +} + +impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { + !arg.0.is_empty() + } +} + + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> Iterator for SplitWhitespace<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } +} + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { + fn next_back(&mut self) -> Option<&'a str> { + self.inner.next_back() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a> FusedIterator for SplitWhitespace<'a> {} diff --git a/src/libcore/tests/atomic.rs b/src/libcore/tests/atomic.rs index f634fabe503..a3667b3f3fe 100644 --- a/src/libcore/tests/atomic.rs +++ b/src/libcore/tests/atomic.rs @@ -104,8 +104,10 @@ static S_UINT: AtomicUsize = AtomicUsize::new(0); #[test] fn static_init() { - assert!(!S_FALSE.load(SeqCst)); - assert!(S_TRUE.load(SeqCst)); - assert!(S_INT.load(SeqCst) == 0); - assert!(S_UINT.load(SeqCst) == 0); + // Note that we're not really testing the mutability here but it's important + // on Android at the moment (#49775) + assert!(!S_FALSE.swap(true, SeqCst)); + assert!(S_TRUE.swap(false, SeqCst)); + assert!(S_INT.fetch_add(1, SeqCst) == 0); + assert!(S_UINT.fetch_add(1, SeqCst) == 0); } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 971759dcdd0..149269263dc 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(ascii_ctype)] #![feature(box_syntax)] #![feature(core_float)] @@ -35,6 +33,7 @@ #![feature(sort_internals)] #![feature(specialization)] #![feature(step_trait)] +#![feature(str_internals)] #![feature(test)] #![feature(trusted_len)] #![feature(try_trait)] @@ -70,4 +69,5 @@ mod ptr; mod result; mod slice; mod str; +mod str_lossy; mod tuple; diff --git a/src/libstd_unicode/tests/lossy.rs b/src/libcore/tests/str_lossy.rs index e05d0668556..69e28256da9 100644 --- a/src/libstd_unicode/tests/lossy.rs +++ b/src/libcore/tests/str_lossy.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std_unicode::lossy::*; +use core::str::lossy::*; #[test] fn chunks() { diff --git a/src/libstd_unicode/bool_trie.rs b/src/libcore/unicode/bool_trie.rs index 3e45b08f399..3e45b08f399 100644 --- a/src/libstd_unicode/bool_trie.rs +++ b/src/libcore/unicode/bool_trie.rs diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs new file mode 100644 index 00000000000..b6b033adc04 --- /dev/null +++ b/src/libcore/unicode/mod.rs @@ -0,0 +1,27 @@ +// Copyright 2012-2014 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. + +#![unstable(feature = "unicode_internals", issue = "0")] +#![allow(missing_docs)] + +mod bool_trie; +pub(crate) mod printable; +pub(crate) mod tables; +pub(crate) mod version; + +// For use in liballoc, not re-exported in libstd. +pub mod derived_property { + pub use unicode::tables::derived_property::{Case_Ignorable, Cased}; +} + +// For use in libsyntax +pub mod property { + pub use unicode::tables::property::Pattern_White_Space; +} diff --git a/src/etc/char_private.py b/src/libcore/unicode/printable.py index cfe5b01e934..9410dafbbc3 100644 --- a/src/etc/char_private.py +++ b/src/libcore/unicode/printable.py @@ -187,7 +187,7 @@ def main(): // option. This file may not be copied, modified, or distributed // except according to those terms. -// NOTE: The following code was generated by "src/etc/char_private.py", +// NOTE: The following code was generated by "src/libcore/unicode/printable.py", // do not edit directly! fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], diff --git a/src/libcore/char_private.rs b/src/libcore/unicode/printable.rs index e6803745ab5..4426c32eebc 100644 --- a/src/libcore/char_private.rs +++ b/src/libcore/unicode/printable.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// NOTE: The following code was generated by "src/etc/char_private.py", +// NOTE: The following code was generated by "src/libcore/unicode/printable.py", // do not edit directly! fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], diff --git a/src/libstd_unicode/tables.rs b/src/libcore/unicode/tables.rs index b53953b62a7..3fbbc011bc4 100644 --- a/src/libstd_unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -12,11 +12,12 @@ #![allow(missing_docs, non_upper_case_globals, non_snake_case)] -use version::UnicodeVersion; -use bool_trie::{BoolTrie, SmallBoolTrie}; +use unicode::version::UnicodeVersion; +use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of -/// `CharExt` and `UnicodeStrPrelude` traits are based on. +/// `char` and `str` methods are based on. +#[unstable(feature = "unicode_version", issue = "49726")] pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { major: 10, minor: 0, @@ -1138,9 +1139,6 @@ pub mod property { } pub mod conversions { - use core::option::Option; - use core::option::Option::{Some, None}; - pub fn to_lower(c: char) -> [char; 3] { match bsearch_case_table(c, to_lowercase_table) { None => [c, '\0', '\0'], diff --git a/src/libstd_unicode/unicode.py b/src/libcore/unicode/unicode.py index a8629493086..75ec01944bf 100755 --- a/src/libstd_unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -39,8 +39,8 @@ preamble = '''// Copyright 2012-2016 The Rust Project Developers. See the COPYRI #![allow(missing_docs, non_upper_case_globals, non_snake_case)] -use version::UnicodeVersion; -use bool_trie::{BoolTrie, SmallBoolTrie}; +use unicode::version::UnicodeVersion; +use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; ''' # Mapping taken from Table 12 from: @@ -408,9 +408,6 @@ def emit_property_module(f, mod, tbl, emit): def emit_conversions_module(f, to_upper, to_lower, to_title): f.write("pub mod conversions {") f.write(""" - use core::option::Option; - use core::option::Option::{Some, None}; - pub fn to_lower(c: char) -> [char; 3] { match bsearch_case_table(c, to_lowercase_table) { None => [c, '\\0', '\\0'], @@ -473,7 +470,8 @@ if __name__ == "__main__": unicode_version = re.search(pattern, readme.read()).groups() rf.write(""" /// The version of [Unicode](http://www.unicode.org/) that the Unicode parts of -/// `CharExt` and `UnicodeStrPrelude` traits are based on. +/// `char` and `str` methods are based on. +#[unstable(feature = "unicode_version", issue = "49726")] pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { major: %s, minor: %s, diff --git a/src/libstd_unicode/version.rs b/src/libcore/unicode/version.rs index d82a749d917..59ebf5f5012 100644 --- a/src/libstd_unicode/version.rs +++ b/src/libcore/unicode/version.rs @@ -12,6 +12,7 @@ /// /// See also: <http://www.unicode.org/versions/> #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[unstable(feature = "unicode_version", issue = "49726")] pub struct UnicodeVersion { /// Major version. pub major: u32, diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 0f45f965104..a551b1b770a 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -19,7 +19,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] -#![deny(warnings)] pub use self::Piece::*; pub use self::Position::*; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index d8c366d2413..158d0101515 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -287,7 +287,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![feature(str_escape)] diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 5f768ef4399..43c5bbbc618 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -19,7 +19,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] -#![deny(warnings)] #![panic_runtime] #![allow(unused_features)] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index a5c227cb401..9321d6917d1 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -28,7 +28,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] -#![deny(warnings)] #![feature(alloc)] #![feature(core_intrinsics)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 6aa5572721d..e171216523a 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -24,7 +24,6 @@ //! See [the book](../book/first-edition/procedural-macros.html) for more. #![stable(feature = "proc_macro_lib", since = "1.15.0")] -#![deny(warnings)] #![deny(missing_docs)] #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", @@ -141,9 +140,16 @@ impl From<TokenTree> for TokenStream { #[unstable(feature = "proc_macro", issue = "38356")] impl iter::FromIterator<TokenTree> for TokenStream { fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self { + trees.into_iter().map(TokenStream::from).collect() + } +} + +#[unstable(feature = "proc_macro", issue = "38356")] +impl iter::FromIterator<TokenStream> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self { let mut builder = tokenstream::TokenStreamBuilder::new(); - for tree in trees { - builder.push(tree.to_internal()); + for stream in streams { + builder.push(stream.0); } TokenStream(builder.build()) } diff --git a/src/librustc/benches/lib.rs b/src/librustc/benches/lib.rs index 278e0f9a26e..5496df1342f 100644 --- a/src/librustc/benches/lib.rs +++ b/src/librustc/benches/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(test)] extern crate test; diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 1247db55f58..118125a19dd 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -389,7 +389,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprType(ref e, _) | hir::ExprUnary(_, ref e) | hir::ExprField(ref e, _) | - hir::ExprTupField(ref e, _) | hir::ExprYield(ref e) | hir::ExprRepeat(ref e, _) => { self.straightline(expr, pred, Some(&**e).into_iter()) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 7c5318a96f5..1b907073238 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -500,6 +500,7 @@ define_dep_nodes!( <'tcx> [] GenericsOfItem(DefId), [] PredicatesOfItem(DefId), [] InferredOutlivesOf(DefId), + [] InferredOutlivesCrate(CrateNum), [] SuperPredicatesOfItem(DefId), [] TraitDefOfItem(DefId), [] AdtDefOfItem(DefId), @@ -632,6 +633,7 @@ define_dep_nodes!( <'tcx> [input] MaybeUnusedTraitImport(DefId), [input] MaybeUnusedExternCrates, [eval_always] StabilityIndex, + [eval_always] AllTraits, [input] AllCrateNums, [] ExportedSymbols(CrateNum), [eval_always] CollectAndPartitionTranslationItems, diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9f51eb8c35a..be9f8b8dac5 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -658,6 +658,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { PatKind::Struct(ref qpath, ref fields, _) => { visitor.visit_qpath(qpath, pattern.id, pattern.span); for field in fields { + visitor.visit_id(field.node.id); visitor.visit_name(field.span, field.node.name); visitor.visit_pat(&field.node.pat) } @@ -959,6 +960,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprStruct(ref qpath, ref fields, ref optional_base) => { visitor.visit_qpath(qpath, expression.id, expression.span); for field in fields { + visitor.visit_id(field.id); visitor.visit_name(field.name.span, field.name.node); visitor.visit_expr(&field.expr) } @@ -1025,9 +1027,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(subexpression); visitor.visit_name(name.span, name.node); } - ExprTupField(ref subexpression, _) => { - visitor.visit_expr(subexpression); - } ExprIndex(ref main_expression, ref index_expression) => { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b13c289394a..fee076acb20 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2100,6 +2100,7 @@ impl<'a> LoweringContext<'a> { fn lower_field(&mut self, f: &Field) -> hir::Field { hir::Field { + id: self.next_id().node_id, name: respan(f.ident.span, self.lower_ident(f.ident)), expr: P(self.lower_expr(&f.expr)), span: f.span, @@ -2863,6 +2864,7 @@ impl<'a> LoweringContext<'a> { .map(|f| Spanned { span: f.span, node: hir::FieldPat { + id: self.next_id().node_id, name: self.lower_ident(f.node.ident), pat: self.lower_pat(&f.node.pat), is_shorthand: f.node.is_shorthand, @@ -3010,7 +3012,28 @@ impl<'a> LoweringContext<'a> { ) }), ExprKind::Catch(ref body) => { - self.with_catch_scope(body.id, |this| hir::ExprBlock(this.lower_block(body, true))) + self.with_catch_scope(body.id, |this| { + let unstable_span = + this.allow_internal_unstable(CompilerDesugaringKind::Catch, body.span); + let mut block = this.lower_block(body, true).into_inner(); + let tail = block.expr.take().map_or_else( + || { + let LoweredNodeId { node_id, hir_id } = this.next_id(); + let span = this.sess.codemap().end_point(unstable_span); + hir::Expr { + id: node_id, + span, + node: hir::ExprTup(hir_vec![]), + attrs: ThinVec::new(), + hir_id, + } + }, + |x: P<hir::Expr>| x.into_inner(), + ); + block.expr = Some(this.wrap_in_try_constructor( + "from_ok", tail, unstable_span)); + hir::ExprBlock(P(block)) + }) } ExprKind::Match(ref expr, ref arms) => hir::ExprMatch( P(self.lower_expr(expr)), @@ -3074,7 +3097,6 @@ impl<'a> LoweringContext<'a> { P(self.lower_expr(el)), respan(ident.span, self.lower_ident(ident)), ), - ExprKind::TupField(ref el, ident) => hir::ExprTupField(P(self.lower_expr(el)), ident), ExprKind::Index(ref el, ref er) => { hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) } @@ -3539,12 +3561,8 @@ impl<'a> LoweringContext<'a> { self.expr_call(e.span, from, hir_vec![err_expr]) }; - let from_err_expr = { - let path = &["ops", "Try", "from_error"]; - let from_err = P(self.expr_std_path(unstable_span, path, ThinVec::new())); - P(self.expr_call(e.span, from_err, hir_vec![from_expr])) - }; - + let from_err_expr = + self.wrap_in_try_constructor("from_error", from_expr, unstable_span); let thin_attrs = ThinVec::from(attrs); let catch_scope = self.catch_scopes.last().map(|x| *x); let ret_expr = if let Some(catch_node) = catch_scope { @@ -3725,6 +3743,7 @@ impl<'a> LoweringContext<'a> { fn field(&mut self, name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field { hir::Field { + id: self.next_id().node_id, name: Spanned { node: name, span }, span, expr, @@ -4079,6 +4098,18 @@ impl<'a> LoweringContext<'a> { ) } } + + fn wrap_in_try_constructor( + &mut self, + method: &'static str, + e: hir::Expr, + unstable_span: Span, + ) -> P<hir::Expr> { + let path = &["ops", "Try", method]; + let from_err = P(self.expr_std_path(unstable_span, path, + ThinVec::new())); + P(self.expr_call(e.span, from_err, hir_vec![e])) + } } fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> { diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index e8bcbfbb77a..1e348e3a31c 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -33,10 +33,11 @@ use hir::svh::Svh; use util::nodemap::{DefIdMap, FxHashMap}; use arena::TypedArena; -use std::cell::RefCell; use std::io; use ty::TyCtxt; +use rustc_data_structures::sync::Lock; + pub mod blocks; mod collector; mod def_collector; @@ -264,7 +265,7 @@ pub struct Map<'hir> { definitions: &'hir Definitions, /// Bodies inlined from other crates are cached here. - inlined_bodies: RefCell<DefIdMap<&'hir Body>>, + inlined_bodies: Lock<DefIdMap<&'hir Body>>, /// The reverse mapping of `node_to_hir_id`. hir_to_node_id: FxHashMap<HirId, NodeId>, @@ -927,8 +928,13 @@ impl<'hir> Map<'hir> { } pub fn intern_inlined_body(&self, def_id: DefId, body: Body) -> &'hir Body { + let mut inlined_bodies = self.inlined_bodies.borrow_mut(); + if let Some(&b) = inlined_bodies.get(&def_id) { + debug_assert_eq!(&body, b); + return b; + } let body = self.forest.inlined_bodies.alloc(body); - self.inlined_bodies.borrow_mut().insert(def_id, body); + inlined_bodies.insert(def_id, body); body } @@ -1189,7 +1195,7 @@ pub fn map_crate<'hir>(sess: &::session::Session, map, hir_to_node_id, definitions, - inlined_bodies: RefCell::new(DefIdMap()), + inlined_bodies: Lock::new(DefIdMap()), }; hir_id_validator::check_crate(&map); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index be8cceb6118..e6080fad91d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -827,6 +827,7 @@ impl Pat { /// except is_shorthand is true #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct FieldPat { + pub id: NodeId, /// The identifier for the field pub name: Name, /// The pattern the field is destructured to @@ -1172,6 +1173,7 @@ pub struct Arm { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Field { + pub id: NodeId, pub name: Spanned<Name>, pub expr: P<Expr>, pub span: Span, @@ -1276,7 +1278,6 @@ impl Expr { ExprAssign(..) => ExprPrecedence::Assign, ExprAssignOp(..) => ExprPrecedence::AssignOp, ExprField(..) => ExprPrecedence::Field, - ExprTupField(..) => ExprPrecedence::TupField, ExprIndex(..) => ExprPrecedence::Index, ExprPath(..) => ExprPrecedence::Path, ExprAddrOf(..) => ExprPrecedence::AddrOf, @@ -1363,12 +1364,8 @@ pub enum Expr_ { /// /// For example, `a += 1`. ExprAssignOp(BinOp, P<Expr>, P<Expr>), - /// Access of a named struct field (`obj.foo`) + /// Access of a named (`obj.foo`) or unnamed (`obj.0`) struct or tuple field ExprField(P<Expr>, Spanned<Name>), - /// Access of an unnamed field of a struct or tuple-struct - /// - /// For example, `foo.0`. - ExprTupField(P<Expr>, Spanned<usize>), /// An indexing operation (`foo[2]`) ExprIndex(P<Expr>, P<Expr>), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index ff501f30c89..d3f2458ef87 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1201,8 +1201,7 @@ impl<'a> State<'a> { fn print_expr_call(&mut self, func: &hir::Expr, args: &[hir::Expr]) -> io::Result<()> { let prec = match func.node { - hir::ExprField(..) | - hir::ExprTupField(..) => parser::PREC_FORCE_PAREN, + hir::ExprField(..) => parser::PREC_FORCE_PAREN, _ => parser::PREC_POSTFIX, }; @@ -1405,11 +1404,6 @@ impl<'a> State<'a> { self.s.word(".")?; self.print_name(name.node)?; } - hir::ExprTupField(ref expr, id) => { - self.print_expr_maybe_paren(&expr, parser::PREC_POSTFIX)?; - self.s.word(".")?; - self.print_usize(id.node)?; - } hir::ExprIndex(ref expr, ref index) => { self.print_expr_maybe_paren(&expr, parser::PREC_POSTFIX)?; self.s.word("[")?; @@ -2376,7 +2370,6 @@ fn contains_exterior_struct_lit(value: &hir::Expr) -> bool { hir::ExprCast(ref x, _) | hir::ExprType(ref x, _) | hir::ExprField(ref x, _) | - hir::ExprTupField(ref x, _) | hir::ExprIndex(ref x, _) => { // &X { y: 1 }, X { y: 1 }.y contains_exterior_struct_lit(&x) diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 38b284fd646..4a001802eac 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -420,11 +420,23 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Pat { } impl_stable_hash_for_spanned!(hir::FieldPat); -impl_stable_hash_for!(struct hir::FieldPat { - name, - pat, - is_shorthand -}); + +impl<'a> HashStable<StableHashingContext<'a>> for hir::FieldPat { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { + let hir::FieldPat { + id: _, + name, + ref pat, + is_shorthand, + } = *self; + + name.hash_stable(hcx, hasher); + pat.hash_stable(hcx, hasher); + is_shorthand.hash_stable(hcx, hasher); + } +} impl_stable_hash_for!(enum hir::BindingAnnotation { Unannotated, @@ -507,12 +519,24 @@ impl_stable_hash_for!(struct hir::Arm { body }); -impl_stable_hash_for!(struct hir::Field { - name, - expr, - span, - is_shorthand -}); +impl<'a> HashStable<StableHashingContext<'a>> for hir::Field { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { + let hir::Field { + id: _, + name, + ref expr, + span, + is_shorthand, + } = *self; + + name.hash_stable(hcx, hasher); + expr.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + is_shorthand.hash_stable(hcx, hasher); + } +} impl_stable_hash_for_spanned!(ast::Name); @@ -569,7 +593,6 @@ impl_stable_hash_for!(enum hir::Expr_ { ExprAssign(lhs, rhs), ExprAssignOp(op, lhs, rhs), ExprField(owner, field_name), - ExprTupField(owner, idx), ExprIndex(lhs, rhs), ExprPath(path), ExprAddrOf(mutability, sub), diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 3bb4c86e7c2..4ac678aaa05 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -372,7 +372,8 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { DotFill, - QuestionMark + QuestionMark, + Catch }); impl_stable_hash_for!(enum ::syntax_pos::FileName { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index af4d3429bb1..41cfac2674b 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1100,6 +1100,20 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::CrateVariancesMap { } } +impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::CratePredicatesMap<'gcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { + let ty::CratePredicatesMap { + ref predicates, + // This is just an irrelevant helper value. + empty_predicate: _, + } = *self; + + predicates.hash_stable(hcx, hasher); + } +} + impl_stable_hash_for!(struct ty::AssociatedItem { def_id, name, diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index eb5df697216..725ea9734ab 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -533,10 +533,14 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> match r { // ignore bound regions that appear in the type (e.g., this // would ignore `'r` in a type like `for<'r> fn(&'r u32)`. - ty::ReLateBound(..) => return r, + ty::ReLateBound(..) | // ignore `'static`, as that can appear anywhere - ty::ReStatic => return r, + ty::ReStatic | + + // ignore `ReScope`, as that can appear anywhere + // See `src/test/run-pass/issue-49556.rs` for example. + ty::ReScope(..) => return r, _ => { } } diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs index 4357c9a5a77..8ea6eb005a1 100644 --- a/src/librustc/infer/canonical.rs +++ b/src/librustc/infer/canonical.rs @@ -36,13 +36,13 @@ use rustc_data_structures::indexed_vec::Idx; use serialize::UseSpecializedDecodable; use std::fmt::Debug; use std::ops::Index; +use std::sync::atomic::Ordering; use syntax::codemap::Span; use traits::{Obligation, ObligationCause, PredicateObligation}; use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags}; use ty::subst::{Kind, UnpackedKind}; use ty::fold::{TypeFoldable, TypeFolder}; use util::captures::Captures; -use util::common::CellUsizeExt; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::fx::FxHashMap; @@ -473,7 +473,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { where V: Canonicalize<'gcx, 'tcx>, { - self.tcx.sess.perf_stats.queries_canonicalized.increment(); + self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed); Canonicalizer::canonicalize( value, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 96c23098821..8d314e25197 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -181,7 +181,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.msg_span_from_early_bound_and_free_regions(region) }, ty::ReStatic => ("the static lifetime".to_owned(), None), - _ => bug!(), + _ => bug!("{:?}", region), } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 91df6cabf3a..5e96f4eb576 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::ast; +use syntax::symbol::InternedString; use syntax_pos::Span; use ty::{self, Ty}; @@ -53,7 +53,7 @@ pub enum TypeVariableOrigin { MiscVariable(Span), NormalizeProjectionType(Span), TypeInference(Span), - TypeParameterDefinition(Span, ast::Name), + TypeParameterDefinition(Span, InternedString), /// one of the upvars or closure kind parameters in a `ClosureSubsts` /// (before it has been determined) diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 7da664e6d02..a2cefe488c6 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -39,7 +39,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -61,6 +60,7 @@ #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] +#![feature(slice_sort_by_cached_key)] #![feature(specialization)] #![feature(unboxed_closures)] #![feature(trace_macros)] diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 89a9f303478..0d4fd99995f 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -31,7 +31,7 @@ pub use self::Level::*; pub use self::LintSource::*; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{self, Lrc}; use errors::{DiagnosticBuilder, DiagnosticId}; use hir::def_id::{CrateNum, LOCAL_CRATE}; @@ -287,8 +287,9 @@ pub trait EarlyLintPass: LintPass { } /// A lint pass boxed up as a trait object. -pub type EarlyLintPassObject = Box<dyn EarlyLintPass + 'static>; -pub type LateLintPassObject = Box<dyn for<'a, 'tcx> LateLintPass<'a, 'tcx> + 'static>; +pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + sync::Sync + 'static>; +pub type LateLintPassObject = Box<dyn for<'a, 'tcx> LateLintPass<'a, 'tcx> + sync::Send + + sync::Sync + 'static>; /// Identifies a lint known to the compiler. #[derive(Clone, Copy, Debug)] diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index add9b621596..41334a37dbe 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -401,7 +401,7 @@ pub fn used_crates(tcx: TyCtxt, prefer: LinkagePreference) .collect::<Vec<_>>(); let mut ordering = tcx.postorder_cnums(LOCAL_CRATE); Lrc::make_mut(&mut ordering).reverse(); - libs.sort_by_key(|&(a, _)| { + libs.sort_by_cached_key(|&(a, _)| { ordering.iter().position(|x| *x == a) }); libs diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index abd52624c30..9ec3d2e2460 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -13,7 +13,7 @@ // from live codes are live, and everything else is dead. use hir::map as hir_map; -use hir::{self, Item_, PatKind}; +use hir::{self, PatKind}; use hir::intravisit::{self, Visitor, NestedVisitorMap}; use hir::itemlikevisit::ItemLikeVisitor; @@ -99,22 +99,14 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.check_def_id(self.tables.type_dependent_defs()[id].def_id()); } - fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { + fn handle_field_access(&mut self, lhs: &hir::Expr, node_id: ast::NodeId) { match self.tables.expr_ty_adjusted(lhs).sty { ty::TyAdt(def, _) => { - self.insert_def_id(def.non_enum_variant().field_named(name).did); - } - _ => span_bug!(lhs.span, "named field access on non-ADT"), - } - } - - fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) { - match self.tables.expr_ty_adjusted(lhs).sty { - ty::TyAdt(def, _) => { - self.insert_def_id(def.non_enum_variant().fields[idx].did); + let index = self.tcx.field_index(node_id, self.tables); + self.insert_def_id(def.non_enum_variant().fields[index].did); } ty::TyTuple(..) => {} - _ => span_bug!(lhs.span, "numeric field access on non-ADT"), + _ => span_bug!(lhs.span, "named field access on non-ADT"), } } @@ -128,7 +120,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { if let PatKind::Wild = pat.node.pat.node { continue; } - self.insert_def_id(variant.field_named(pat.node.name).did); + let index = self.tcx.field_index(pat.node.id, self.tables); + self.insert_def_id(variant.fields[index].did); } } @@ -191,18 +184,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.inherited_pub_visibility = had_inherited_pub_visibility; } - fn mark_as_used_if_union(&mut self, did: DefId, fields: &hir::HirVec<hir::Field>) { - if let Some(node_id) = self.tcx.hir.as_local_node_id(did) { - if let Some(hir_map::NodeItem(item)) = self.tcx.hir.find(node_id) { - if let Item_::ItemUnion(ref variant, _) = item.node { - if variant.fields().len() > 1 { - for field in variant.fields() { - if fields.iter().find(|x| x.name.node == field.name).is_some() { - self.live_symbols.insert(field.id); - } - } - } - } + fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &hir::HirVec<hir::Field>) { + if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did.is_local() { + for field in fields { + let index = self.tcx.field_index(field.id, self.tables); + self.insert_def_id(adt.non_enum_variant().fields[index].did); } } } @@ -242,17 +228,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { hir::ExprMethodCall(..) => { self.lookup_and_handle_method(expr.hir_id); } - hir::ExprField(ref lhs, ref name) => { - self.handle_field_access(&lhs, name.node); - } - hir::ExprTupField(ref lhs, idx) => { - self.handle_tup_field_access(&lhs, idx.node); + hir::ExprField(ref lhs, ..) => { + self.handle_field_access(&lhs, expr.id); } hir::ExprStruct(_, ref fields, _) => { - if let ty::TypeVariants::TyAdt(ref def, _) = self.tables.expr_ty(expr).sty { - if def.is_union() { - self.mark_as_used_if_union(def.did, fields); - } + if let ty::TypeVariants::TyAdt(ref adt, _) = self.tables.expr_ty(expr).sty { + self.mark_as_used_if_union(adt, fields); } } _ => () @@ -408,7 +389,7 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Seed entry point - if let Some((id, _)) = *tcx.sess.entry_fn.borrow() { + if let Some((id, _, _)) = *tcx.sess.entry_fn.borrow() { worklist.push(id); } diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index e7055827c49..e7fc8d633c8 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -94,13 +94,14 @@ pub enum Linkage { pub fn calculate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let sess = &tcx.sess; - let mut fmts = sess.dependency_formats.borrow_mut(); + let mut fmts = FxHashMap(); for &ty in sess.crate_types.borrow().iter() { let linkage = calculate_type(tcx, ty); verify_ok(tcx, &linkage); fmts.insert(ty, linkage); } sess.abort_if_errors(); + sess.dependency_formats.set(fmts); } fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -222,7 +223,7 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // // Things like allocators and panic runtimes may not have been activated // quite yet, so do so here. - activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret, + activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, &|cnum| tcx.is_panic_runtime(cnum)); activate_injected_allocator(sess, &mut ret); @@ -301,7 +302,7 @@ fn attempt_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<DependencyLis // Our allocator/panic runtime may not have been linked above if it wasn't // explicitly linked, which is the case for any injected dependency. Handle // that here and activate them. - activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret, + activate_injected_dep(*sess.injected_panic_runtime.get(), &mut ret, &|cnum| tcx.is_panic_runtime(cnum)); activate_injected_allocator(sess, &mut ret); diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index 37d79f408f3..ebc79646662 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -63,12 +63,13 @@ pub fn find_entry_point(session: &Session, }); if !any_exe { // No need to find a main function + session.entry_fn.set(None); return } // If the user wants no main function at all, then stop here. if attr::contains_name(&hir_map.krate().attrs, "no_main") { - session.entry_type.set(Some(config::EntryNone)); + session.entry_fn.set(None); return } @@ -153,17 +154,15 @@ fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) { } fn configure_main(this: &mut EntryContext, crate_name: &str) { - if this.start_fn.is_some() { - *this.session.entry_fn.borrow_mut() = this.start_fn; - this.session.entry_type.set(Some(config::EntryStart)); - } else if this.attr_main_fn.is_some() { - *this.session.entry_fn.borrow_mut() = this.attr_main_fn; - this.session.entry_type.set(Some(config::EntryMain)); - } else if this.main_fn.is_some() { - *this.session.entry_fn.borrow_mut() = this.main_fn; - this.session.entry_type.set(Some(config::EntryMain)); + if let Some((node_id, span)) = this.start_fn { + this.session.entry_fn.set(Some((node_id, span, config::EntryStart))); + } else if let Some((node_id, span)) = this.attr_main_fn { + this.session.entry_fn.set(Some((node_id, span, config::EntryMain))); + } else if let Some((node_id, span)) = this.main_fn { + this.session.entry_fn.set(Some((node_id, span, config::EntryMain))); } else { // No main function + this.session.entry_fn.set(None); let mut err = struct_err!(this.session, E0601, "`main` function not found in crate `{}`", crate_name); if !this.non_main_fns.is_empty() { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 28524678e99..2cc5a4a8fe6 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -404,10 +404,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.select_from_expr(&base); } - hir::ExprTupField(ref base, _) => { // base.<n> - self.select_from_expr(&base); - } - hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] self.select_from_expr(&lhs); self.consume_expr(&rhs); @@ -663,11 +659,15 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { match with_cmt.ty.sty { ty::TyAdt(adt, substs) if adt.is_struct() => { // Consume those fields of the with expression that are needed. - for with_field in &adt.non_enum_variant().fields { - if !contains_field_named(with_field, fields) { + for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() { + let is_mentioned = fields.iter().any(|f| { + self.tcx().field_index(f.id, self.mc.tables) == f_index + }); + if !is_mentioned { let cmt_field = self.mc.cat_field( &*with_expr, with_cmt.clone(), + f_index, with_field.name, with_field.ty(self.tcx(), substs) ); @@ -691,14 +691,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // walk the with expression so that complex expressions // are properly handled. self.walk_expr(with_expr); - - fn contains_field_named(field: &ty::FieldDef, - fields: &[hir::Field]) - -> bool - { - fields.iter().any( - |f| f.name.node == field.name) - } } // Invoke the appropriate delegate calls for anything that gets diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 966353b53a9..11dc2a81885 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -476,7 +476,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { } // otherwise, live nodes are not required: - hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) | + hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprArray(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprAddrOf(..) | hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(..) | @@ -912,10 +912,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&e, succ) } - hir::ExprTupField(ref e, _) => { - self.propagate_through_expr(&e, succ) - } - hir::ExprClosure(.., blk_id, _, _) => { debug!("{} is an ExprClosure", self.ir.tcx.hir.node_to_pretty_string(expr.id)); @@ -1226,7 +1222,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match expr.node { hir::ExprPath(_) => succ, hir::ExprField(ref e, _) => self.propagate_through_expr(&e, succ), - hir::ExprTupField(ref e, _) => self.propagate_through_expr(&e, succ), _ => self.propagate_through_expr(expr, succ) } } @@ -1419,7 +1414,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { // no correctness conditions related to liveness hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprIf(..) | hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) | - hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) | + hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) | hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) | diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5875e5e4097..6f41f07dce8 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -62,7 +62,6 @@ pub use self::PointerKind::*; pub use self::InteriorKind::*; -pub use self::FieldName::*; pub use self::MutabilityCategory::*; pub use self::AliasableReason::*; pub use self::Note::*; @@ -81,10 +80,11 @@ use ty::fold::TypeFoldable; use hir::{MutImmutable, MutMutable, PatKind}; use hir::pat_util::EnumerateAndAdjustIterator; use hir; -use syntax::ast; +use syntax::ast::{self, Name}; use syntax_pos::Span; use std::fmt; +use std::hash::{Hash, Hasher}; use rustc_data_structures::sync::Lrc; use std::rc::Rc; use util::nodemap::ItemLocalSet; @@ -129,14 +129,25 @@ pub enum PointerKind<'tcx> { // base without a pointer dereference", e.g. a field #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum InteriorKind { - InteriorField(FieldName), + InteriorField(FieldIndex), InteriorElement(InteriorOffsetKind), } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum FieldName { - NamedField(ast::Name), - PositionalField(usize) +// Contains index of a field that is actually used for loan path comparisons and +// string representation of the field that should be used only for diagnostics. +#[derive(Clone, Copy, Eq)] +pub struct FieldIndex(pub usize, pub Name); + +impl PartialEq for FieldIndex { + fn eq(&self, rhs: &Self) -> bool { + self.0 == rhs.0 + } +} + +impl Hash for FieldIndex { + fn hash<H: Hasher>(&self, h: &mut H) { + self.0.hash(h) + } } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] @@ -198,7 +209,7 @@ pub enum ImmutabilityBlame<'tcx> { } impl<'tcx> cmt_<'tcx> { - fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)> + fn resolve_field(&self, field_index: usize) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)> { let adt_def = match self.ty.sty { ty::TyAdt(def, _) => def, @@ -215,11 +226,7 @@ impl<'tcx> cmt_<'tcx> { &adt_def.variants[0] } }; - let field_def = match field_name { - NamedField(name) => variant_def.field_named(name), - PositionalField(idx) => &variant_def.fields[idx] - }; - Some((adt_def, field_def)) + Some((adt_def, &variant_def.fields[field_index])) } pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> { @@ -230,8 +237,8 @@ impl<'tcx> cmt_<'tcx> { match base_cmt.cat { Categorization::Local(node_id) => Some(ImmutabilityBlame::LocalDeref(node_id)), - Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { - base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| { + Categorization::Interior(ref base_cmt, InteriorField(field_index)) => { + base_cmt.resolve_field(field_index.0).map(|(adt_def, field_def)| { ImmutabilityBlame::AdtFieldDeref(adt_def, field_def) }) } @@ -646,12 +653,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { expr.id, expr, base_cmt); - Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty)) - } - - hir::ExprTupField(ref base, idx) => { - let base_cmt = self.cat_expr(&base)?; - Ok(self.cat_tup_field(expr, base_cmt, idx.node, expr_ty)) + let f_index = self.tcx.field_index(expr.id, self.tables); + Ok(self.cat_field(expr, base_cmt, f_index, f_name.node, expr_ty)) } hir::ExprIndex(ref base, _) => { @@ -979,14 +982,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn cat_field<N:ast_node>(&self, node: &N, base_cmt: cmt<'tcx>, - f_name: ast::Name, + f_index: usize, + f_name: Name, f_ty: Ty<'tcx>) -> cmt<'tcx> { let ret = Rc::new(cmt_ { id: node.id(), span: node.span(), mutbl: base_cmt.mutbl.inherit(), - cat: Categorization::Interior(base_cmt, InteriorField(NamedField(f_name))), + cat: Categorization::Interior(base_cmt, InteriorField(FieldIndex(f_index, f_name))), ty: f_ty, note: NoteNone }); @@ -994,24 +998,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - pub fn cat_tup_field<N:ast_node>(&self, - node: &N, - base_cmt: cmt<'tcx>, - f_idx: usize, - f_ty: Ty<'tcx>) - -> cmt<'tcx> { - let ret = Rc::new(cmt_ { - id: node.id(), - span: node.span(), - mutbl: base_cmt.mutbl.inherit(), - cat: Categorization::Interior(base_cmt, InteriorField(PositionalField(f_idx))), - ty: f_ty, - note: NoteNone - }); - debug!("cat_tup_field ret {:?}", ret); - ret - } - fn cat_overloaded_place(&self, expr: &hir::Expr, base: &hir::Expr, @@ -1292,8 +1278,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) - let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); + let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior); self.cat_pattern_(subcmt, &subpat, op)?; } } @@ -1315,7 +1301,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { for fp in field_pats { let field_ty = self.pat_ty(&fp.node.pat)?; // see (*2) - let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.name, field_ty); + let f_index = self.tcx.field_index(fp.node.id, self.tables); + let cmt_field = self.cat_field(pat, cmt.clone(), f_index, fp.node.name, field_ty); self.cat_pattern_(cmt_field, &fp.node.pat, op)?; } } @@ -1332,8 +1319,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { let subpat_ty = self.pat_ty(&subpat)?; // see (*2) - let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, - InteriorField(PositionalField(i))); + let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); + let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior); self.cat_pattern_(subcmt, &subpat, op)?; } } @@ -1516,12 +1503,9 @@ impl<'tcx> cmt_<'tcx> { } } } - Categorization::Interior(_, InteriorField(NamedField(_))) => { + Categorization::Interior(_, InteriorField(..)) => { "field".to_string() } - Categorization::Interior(_, InteriorField(PositionalField(_))) => { - "anonymous field".to_string() - } Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index)) => { "indexed content".to_string() } @@ -1554,8 +1538,7 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str { impl fmt::Debug for InteriorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - InteriorField(NamedField(fld)) => write!(f, "{}", fld), - InteriorField(PositionalField(i)) => write!(f, "#{}", i), + InteriorField(FieldIndex(_, info)) => write!(f, "{}", info), InteriorElement(..) => write!(f, "[]"), } } diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index 6c87f750376..077a20315a2 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -18,17 +18,17 @@ use session::Session; use syntax::ast; -use std::cell::Cell; +use rustc_data_structures::sync::Once; pub fn update_limits(sess: &Session, krate: &ast::Crate) { update_limit(sess, krate, &sess.recursion_limit, "recursion_limit", - "recursion limit"); + "recursion limit", 64); update_limit(sess, krate, &sess.type_length_limit, "type_length_limit", - "type length limit"); + "type length limit", 1048576); } -fn update_limit(sess: &Session, krate: &ast::Crate, limit: &Cell<usize>, - name: &str, description: &str) { +fn update_limit(sess: &Session, krate: &ast::Crate, limit: &Once<usize>, + name: &str, description: &str, default: usize) { for attr in &krate.attrs { if !attr.check_name(name) { continue; @@ -45,4 +45,5 @@ fn update_limit(sess: &Session, krate: &ast::Crate, limit: &Cell<usize>, "malformed {} attribute, expected #![{}=\"N\"]", description, name); } + limit.set(default); } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 7e1b7c08c3d..42483c83f4b 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1307,7 +1307,6 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, hir::ExprAddrOf(_, ref subexpr) | hir::ExprUnary(hir::UnDeref, ref subexpr) | hir::ExprField(ref subexpr, _) | - hir::ExprTupField(ref subexpr, _) | hir::ExprIndex(ref subexpr, _) => { expr = &subexpr; } diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 9b75c19a875..1ed5a22257c 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell::{Ref, RefCell}; use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::sync::{RwLock, ReadGuard}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use ich::StableHashingContext; @@ -19,7 +19,7 @@ use rustc_serialize as serialize; #[derive(Clone, Debug)] pub struct Cache { - predecessors: RefCell<Option<IndexVec<BasicBlock, Vec<BasicBlock>>>> + predecessors: RwLock<Option<IndexVec<BasicBlock, Vec<BasicBlock>>>> } @@ -46,7 +46,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for Cache { impl Cache { pub fn new() -> Self { Cache { - predecessors: RefCell::new(None) + predecessors: RwLock::new(None) } } @@ -55,12 +55,12 @@ impl Cache { *self.predecessors.borrow_mut() = None; } - pub fn predecessors(&self, mir: &Mir) -> Ref<IndexVec<BasicBlock, Vec<BasicBlock>>> { + pub fn predecessors(&self, mir: &Mir) -> ReadGuard<IndexVec<BasicBlock, Vec<BasicBlock>>> { if self.predecessors.borrow().is_none() { *self.predecessors.borrow_mut() = Some(calculate_predecessors(mir)); } - Ref::map(self.predecessors.borrow(), |p| p.as_ref().unwrap()) + ReadGuard::map(self.predecessors.borrow(), |p| p.as_ref().unwrap()) } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9ed4e6a8e00..33f52ab09c8 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -34,7 +34,7 @@ use util::ppaux; use std::slice; use hir::{self, InlineAsm}; use std::borrow::{Cow}; -use std::cell::Ref; +use rustc_data_structures::sync::ReadGuard; use std::fmt::{self, Debug, Formatter, Write}; use std::{iter, mem, u32}; use std::ops::{Index, IndexMut}; @@ -187,13 +187,13 @@ impl<'tcx> Mir<'tcx> { } #[inline] - pub fn predecessors(&self) -> Ref<IndexVec<BasicBlock, Vec<BasicBlock>>> { + pub fn predecessors(&self) -> ReadGuard<IndexVec<BasicBlock, Vec<BasicBlock>>> { self.cache.predecessors(self) } #[inline] - pub fn predecessors_for(&self, bb: BasicBlock) -> Ref<Vec<BasicBlock>> { - Ref::map(self.predecessors(), |p| &p[bb]) + pub fn predecessors_for(&self, bb: BasicBlock) -> ReadGuard<Vec<BasicBlock>> { + ReadGuard::map(self.predecessors(), |p| &p[bb]) } #[inline] diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs index 64f405e0f24..df4060e71e5 100644 --- a/src/librustc/session/code_stats.rs +++ b/src/librustc/session/code_stats.rs @@ -62,6 +62,7 @@ pub struct TypeSizeInfo { pub type_description: String, pub align: u64, pub overall_size: u64, + pub packed: bool, pub opt_discr_size: Option<u64>, pub variants: Vec<VariantInfo>, } @@ -79,6 +80,7 @@ impl CodeStats { type_desc: S, align: Align, overall_size: Size, + packed: bool, opt_discr_size: Option<Size>, variants: Vec<VariantInfo>) { let info = TypeSizeInfo { @@ -86,6 +88,7 @@ impl CodeStats { type_description: type_desc.to_string(), align: align.abi(), overall_size: overall_size.bytes(), + packed: packed, opt_discr_size: opt_discr_size.map(|s| s.bytes()), variants, }; @@ -153,24 +156,26 @@ impl CodeStats { for field in fields.iter() { let FieldInfo { ref name, offset, size, align } = *field; - // Include field alignment in output only if it caused padding injection - if min_offset != offset { - if offset > min_offset { - let pad = offset - min_offset; - println!("print-type-size {}padding: {} bytes", - indent, pad); - println!("print-type-size {}field `.{}`: {} bytes, \ - alignment: {} bytes", - indent, name, size, align); - } else { - println!("print-type-size {}field `.{}`: {} bytes, \ - offset: {} bytes, \ - alignment: {} bytes", - indent, name, size, offset, align); - } - } else { + if offset > min_offset { + let pad = offset - min_offset; + println!("print-type-size {}padding: {} bytes", + indent, pad); + } + + if offset < min_offset { + // if this happens something is very wrong + println!("print-type-size {}field `.{}`: {} bytes, \ + offset: {} bytes, \ + alignment: {} bytes", + indent, name, size, offset, align); + } else if info.packed || offset == min_offset { println!("print-type-size {}field `.{}`: {} bytes", indent, name, size); + } else { + // Include field alignment in output only if it caused padding injection + println!("print-type-size {}field `.{}`: {} bytes, \ + alignment: {} bytes", + indent, name, size, align); } min_offset = offset + size; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a07370e1e42..8b6a8fea4ca 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -614,13 +614,11 @@ impl Options { // The type of entry function, so // users can have their own entry -// functions that don't start a -// scheduler +// functions #[derive(Copy, Clone, PartialEq)] pub enum EntryFnType { EntryMain, EntryStart, - EntryNone, } #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)] @@ -1861,6 +1859,13 @@ pub fn build_session_options_and_crate_config( ); } + if debugging_opts.query_threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() { + early_error( + error_format, + "Optimization fuel is incompatible with multiple query threads", + ); + } + if codegen_units == Some(0) { early_error( error_format, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 77cf50a8341..8f2043fdfc6 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -22,11 +22,11 @@ use middle::dependency_format; use session::search_paths::PathKind; use session::config::{DebugInfoLevel, OutputType}; use ty::tls; -use util::nodemap::{FxHashMap, FxHashSet}; +use util::nodemap::{FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; use util::common::ProfileQueriesMsg; -use rustc_data_structures::sync::{Lrc, Lock}; +use rustc_data_structures::sync::{Lrc, Lock, LockCell, OneThread, Once}; use syntax::ast::NodeId; use errors::{self, DiagnosticBuilder, DiagnosticId}; @@ -46,15 +46,16 @@ use rustc_back::target::{Target, TargetTriple}; use rustc_data_structures::flock; use jobserver::Client; +use std; use std::cell::{self, Cell, RefCell}; use std::collections::HashMap; use std::env; use std::fmt; use std::io::Write; use std::path::{Path, PathBuf}; -use std::sync::{Once, ONCE_INIT}; use std::time::Duration; use std::sync::mpsc; +use std::sync::atomic::{AtomicUsize, Ordering}; mod code_stats; pub mod config; @@ -69,10 +70,9 @@ pub struct Session { pub opts: config::Options, pub parse_sess: ParseSess, /// For a library crate, this is always none - pub entry_fn: RefCell<Option<(NodeId, Span)>>, - pub entry_type: Cell<Option<config::EntryFnType>>, - pub plugin_registrar_fn: Cell<Option<ast::NodeId>>, - pub derive_registrar_fn: Cell<Option<ast::NodeId>>, + pub entry_fn: Once<Option<(NodeId, Span, config::EntryFnType)>>, + pub plugin_registrar_fn: Once<Option<ast::NodeId>>, + pub derive_registrar_fn: Once<Option<ast::NodeId>>, pub default_sysroot: Option<PathBuf>, /// The name of the root source file of the crate, in the local file system. /// `None` means that there is no source file. @@ -80,50 +80,54 @@ pub struct Session { /// The directory the compiler has been executed in plus a flag indicating /// if the value stored here has been affected by path remapping. pub working_dir: (PathBuf, bool), - pub lint_store: RefCell<lint::LintStore>, - pub buffered_lints: RefCell<Option<lint::LintBuffer>>, + + // FIXME: lint_store and buffered_lints are not thread-safe, + // but are only used in a single thread + pub lint_store: OneThread<RefCell<lint::LintStore>>, + pub buffered_lints: OneThread<RefCell<Option<lint::LintBuffer>>>, + /// Set of (DiagnosticId, Option<Span>, message) tuples tracking /// (sub)diagnostics that have been set once, but should not be set again, /// in order to avoid redundantly verbose output (Issue #24690, #44953). pub one_time_diagnostics: RefCell<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>, - pub plugin_llvm_passes: RefCell<Vec<String>>, - pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>, - pub crate_types: RefCell<Vec<config::CrateType>>, - pub dependency_formats: RefCell<dependency_format::Dependencies>, + pub plugin_llvm_passes: OneThread<RefCell<Vec<String>>>, + pub plugin_attributes: OneThread<RefCell<Vec<(String, AttributeType)>>>, + pub crate_types: Once<Vec<config::CrateType>>, + pub dependency_formats: Once<dependency_format::Dependencies>, /// The crate_disambiguator is constructed out of all the `-C metadata` /// arguments passed to the compiler. Its value together with the crate-name /// forms a unique global identifier for the crate. It is used to allow /// multiple crates with the same name to coexist. See the /// trans::back::symbol_names module for more information. - pub crate_disambiguator: RefCell<Option<CrateDisambiguator>>, + pub crate_disambiguator: Once<CrateDisambiguator>, - features: RefCell<Option<feature_gate::Features>>, + features: Once<feature_gate::Features>, /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. - pub recursion_limit: Cell<usize>, + pub recursion_limit: Once<usize>, /// The maximum length of types during monomorphization. - pub type_length_limit: Cell<usize>, + pub type_length_limit: Once<usize>, /// The maximum number of stackframes allowed in const eval - pub const_eval_stack_frame_limit: Cell<usize>, + pub const_eval_stack_frame_limit: usize, /// The maximum number miri steps per constant - pub const_eval_step_limit: Cell<usize>, + pub const_eval_step_limit: usize, /// The metadata::creader module may inject an allocator/panic_runtime /// dependency if it didn't already find one, and this tracks what was /// injected. - pub injected_allocator: Cell<Option<CrateNum>>, - pub allocator_kind: Cell<Option<AllocatorKind>>, - pub injected_panic_runtime: Cell<Option<CrateNum>>, + pub injected_allocator: Once<Option<CrateNum>>, + pub allocator_kind: Once<Option<AllocatorKind>>, + pub injected_panic_runtime: Once<Option<CrateNum>>, /// Map from imported macro spans (which consist of /// the localized span for the macro body) to the /// macro name and definition span in the source crate. - pub imported_macro_spans: RefCell<HashMap<Span, (String, Span)>>, + pub imported_macro_spans: OneThread<RefCell<HashMap<Span, (String, Span)>>>, - incr_comp_session: RefCell<IncrCompSession>, + incr_comp_session: OneThread<RefCell<IncrCompSession>>, /// A cache of attributes ignored by StableHashingContext pub ignored_attr_names: FxHashSet<Symbol>, @@ -135,53 +139,42 @@ pub struct Session { pub perf_stats: PerfStats, /// Data about code being compiled, gathered during compilation. - pub code_stats: RefCell<CodeStats>, + pub code_stats: Lock<CodeStats>, - next_node_id: Cell<ast::NodeId>, + next_node_id: OneThread<Cell<ast::NodeId>>, /// If -zfuel=crate=n is specified, Some(crate). optimization_fuel_crate: Option<String>, /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0. - optimization_fuel_limit: Cell<u64>, + optimization_fuel_limit: LockCell<u64>, /// We're rejecting all further optimizations. - out_of_fuel: Cell<bool>, + out_of_fuel: LockCell<bool>, // The next two are public because the driver needs to read them. /// If -zprint-fuel=crate, Some(crate). pub print_fuel_crate: Option<String>, /// Always set to zero and incremented so that we can print fuel expended by a crate. - pub print_fuel: Cell<u64>, + pub print_fuel: LockCell<u64>, /// Loaded up early on in the initialization of this `Session` to avoid /// false positives about a job server in our environment. pub jobserver_from_env: Option<Client>, /// Metadata about the allocators for the current crate being compiled - pub has_global_allocator: Cell<bool>, + pub has_global_allocator: Once<bool>, } pub struct PerfStats { - /// The accumulated time needed for computing the SVH of the crate - pub svh_time: Cell<Duration>, - /// The accumulated time spent on computing incr. comp. hashes - pub incr_comp_hashes_time: Cell<Duration>, - /// The number of incr. comp. hash computations performed - pub incr_comp_hashes_count: Cell<u64>, - /// The number of bytes hashed when computing ICH values - pub incr_comp_bytes_hashed: Cell<u64>, /// The accumulated time spent on computing symbol hashes - pub symbol_hash_time: Cell<Duration>, + pub symbol_hash_time: Lock<Duration>, /// The accumulated time spent decoding def path tables from metadata - pub decode_def_path_tables_time: Cell<Duration>, + pub decode_def_path_tables_time: Lock<Duration>, /// Total number of values canonicalized queries constructed. - pub queries_canonicalized: Cell<usize>, - /// Number of times we canonicalized a value and found that the - /// result had already been canonicalized. - pub canonicalized_values_allocated: Cell<usize>, + pub queries_canonicalized: AtomicUsize, /// Number of times this query is invoked. - pub normalize_ty_after_erasing_regions: Cell<usize>, + pub normalize_ty_after_erasing_regions: AtomicUsize, /// Number of times this query is invoked. - pub normalize_projection_ty: Cell<usize>, + pub normalize_projection_ty: AtomicUsize, } /// Enum to support dispatch of one-time diagnostics (in Session.diag_once) @@ -209,10 +202,7 @@ impl From<&'static lint::Lint> for DiagnosticMessageId { impl Session { pub fn local_crate_disambiguator(&self) -> CrateDisambiguator { - match *self.crate_disambiguator.borrow() { - Some(value) => value, - None => bug!("accessing disambiguator before initialization"), - } + *self.crate_disambiguator.get() } pub fn struct_span_warn<'a, S: Into<MultiSpan>>( @@ -539,18 +529,12 @@ impl Session { /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents /// dependency tracking. Use tcx.features() instead. #[inline] - pub fn features_untracked(&self) -> cell::Ref<feature_gate::Features> { - let features = self.features.borrow(); - - if features.is_none() { - bug!("Access to Session::features before it is initialized"); - } - - cell::Ref::map(features, |r| r.as_ref().unwrap()) + pub fn features_untracked(&self) -> &feature_gate::Features { + self.features.get() } pub fn init_features(&self, features: feature_gate::Features) { - *(self.features.borrow_mut()) = Some(features); + self.features.set(features); } /// Calculates the flavor of LTO to use for this compilation. @@ -835,51 +819,25 @@ impl Session { pub fn print_perf_stats(&self) { println!( - "Total time spent computing SVHs: {}", - duration_to_secs_str(self.perf_stats.svh_time.get()) - ); - println!( - "Total time spent computing incr. comp. hashes: {}", - duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get()) - ); - println!( - "Total number of incr. comp. hashes computed: {}", - self.perf_stats.incr_comp_hashes_count.get() - ); - println!( - "Total number of bytes hashed for incr. comp.: {}", - self.perf_stats.incr_comp_bytes_hashed.get() - ); - if self.perf_stats.incr_comp_hashes_count.get() != 0 { - println!( - "Average bytes hashed per incr. comp. HIR node: {}", - self.perf_stats.incr_comp_bytes_hashed.get() - / self.perf_stats.incr_comp_hashes_count.get() - ); - } else { - println!("Average bytes hashed per incr. comp. HIR node: N/A"); - } - println!( "Total time spent computing symbol hashes: {}", - duration_to_secs_str(self.perf_stats.symbol_hash_time.get()) + duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock()) ); println!( "Total time spent decoding DefPath tables: {}", - duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()) + duration_to_secs_str(*self.perf_stats.decode_def_path_tables_time.lock()) ); println!("Total queries canonicalized: {}", - self.perf_stats.queries_canonicalized.get()); - println!("Total canonical values interned: {}", - self.perf_stats.canonicalized_values_allocated.get()); + self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)); println!("normalize_ty_after_erasing_regions: {}", - self.perf_stats.normalize_ty_after_erasing_regions.get()); + self.perf_stats.normalize_ty_after_erasing_regions.load(Ordering::Relaxed)); println!("normalize_projection_ty: {}", - self.perf_stats.normalize_projection_ty.get()); + self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed)); } /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool { + assert!(self.query_threads() == 1); let mut ret = true; match self.optimization_fuel_crate { Some(ref c) if c == crate_name => { @@ -1109,9 +1067,9 @@ pub fn build_session_( let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); let optimization_fuel_limit = - Cell::new(sopts.debugging_opts.fuel.as_ref().map(|i| i.1).unwrap_or(0)); + LockCell::new(sopts.debugging_opts.fuel.as_ref().map(|i| i.1).unwrap_or(0)); let print_fuel_crate = sopts.debugging_opts.print_fuel.clone(); - let print_fuel = Cell::new(0); + let print_fuel = LockCell::new(0); let working_dir = match env::current_dir() { Ok(dir) => dir, @@ -1127,52 +1085,46 @@ pub fn build_session_( opts: sopts, parse_sess: p_s, // For a library crate, this is always none - entry_fn: RefCell::new(None), - entry_type: Cell::new(None), - plugin_registrar_fn: Cell::new(None), - derive_registrar_fn: Cell::new(None), + entry_fn: Once::new(), + plugin_registrar_fn: Once::new(), + derive_registrar_fn: Once::new(), default_sysroot, local_crate_source_file, working_dir, - lint_store: RefCell::new(lint::LintStore::new()), - buffered_lints: RefCell::new(Some(lint::LintBuffer::new())), + lint_store: OneThread::new(RefCell::new(lint::LintStore::new())), + buffered_lints: OneThread::new(RefCell::new(Some(lint::LintBuffer::new()))), one_time_diagnostics: RefCell::new(FxHashSet()), - plugin_llvm_passes: RefCell::new(Vec::new()), - plugin_attributes: RefCell::new(Vec::new()), - crate_types: RefCell::new(Vec::new()), - dependency_formats: RefCell::new(FxHashMap()), - crate_disambiguator: RefCell::new(None), - features: RefCell::new(None), - recursion_limit: Cell::new(64), - type_length_limit: Cell::new(1048576), - const_eval_stack_frame_limit: Cell::new(100), - const_eval_step_limit: Cell::new(1_000_000), - next_node_id: Cell::new(NodeId::new(1)), - injected_allocator: Cell::new(None), - allocator_kind: Cell::new(None), - injected_panic_runtime: Cell::new(None), - imported_macro_spans: RefCell::new(HashMap::new()), - incr_comp_session: RefCell::new(IncrCompSession::NotInitialized), + plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())), + plugin_attributes: OneThread::new(RefCell::new(Vec::new())), + crate_types: Once::new(), + dependency_formats: Once::new(), + crate_disambiguator: Once::new(), + features: Once::new(), + recursion_limit: Once::new(), + type_length_limit: Once::new(), + const_eval_stack_frame_limit: 100, + const_eval_step_limit: 1_000_000, + next_node_id: OneThread::new(Cell::new(NodeId::new(1))), + injected_allocator: Once::new(), + allocator_kind: Once::new(), + injected_panic_runtime: Once::new(), + imported_macro_spans: OneThread::new(RefCell::new(HashMap::new())), + incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), ignored_attr_names: ich::compute_ignored_attr_names(), profile_channel: Lock::new(None), perf_stats: PerfStats { - svh_time: Cell::new(Duration::from_secs(0)), - incr_comp_hashes_time: Cell::new(Duration::from_secs(0)), - incr_comp_hashes_count: Cell::new(0), - incr_comp_bytes_hashed: Cell::new(0), - symbol_hash_time: Cell::new(Duration::from_secs(0)), - decode_def_path_tables_time: Cell::new(Duration::from_secs(0)), - queries_canonicalized: Cell::new(0), - canonicalized_values_allocated: Cell::new(0), - normalize_ty_after_erasing_regions: Cell::new(0), - normalize_projection_ty: Cell::new(0), + symbol_hash_time: Lock::new(Duration::from_secs(0)), + decode_def_path_tables_time: Lock::new(Duration::from_secs(0)), + queries_canonicalized: AtomicUsize::new(0), + normalize_ty_after_erasing_regions: AtomicUsize::new(0), + normalize_projection_ty: AtomicUsize::new(0), }, - code_stats: RefCell::new(CodeStats::new()), + code_stats: Lock::new(CodeStats::new()), optimization_fuel_crate, optimization_fuel_limit, print_fuel_crate, print_fuel, - out_of_fuel: Cell::new(false), + out_of_fuel: LockCell::new(false), // Note that this is unsafe because it may misinterpret file descriptors // on Unix as jobserver file descriptors. We hopefully execute this near // the beginning of the process though to ensure we don't get false @@ -1184,13 +1136,13 @@ pub fn build_session_( // per-process. jobserver_from_env: unsafe { static mut GLOBAL_JOBSERVER: *mut Option<Client> = 0 as *mut _; - static INIT: Once = ONCE_INIT; + static INIT: std::sync::Once = std::sync::ONCE_INIT; INIT.call_once(|| { GLOBAL_JOBSERVER = Box::into_raw(Box::new(Client::from_env())); }); (*GLOBAL_JOBSERVER).clone() }, - has_global_allocator: Cell::new(false), + has_global_allocator: Once::new(), }; sess diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d2bde14732b..2af4c3f9fd4 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -378,7 +378,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } for param in generics.types.iter() { - let name = param.name.as_str().to_string(); + let name = param.name.to_string(); let ty = trait_ref.substs.type_for_def(param); let ty_str = ty.to_string(); flags.push((name.clone(), diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index b30fb2ce016..32fd93cf20a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -23,13 +23,12 @@ use infer::outlives::env::OutlivesEnvironment; use middle::region; use middle::const_val::ConstEvalErr; use ty::subst::Substs; -use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, ToPredicate}; +use ty::{self, AdtKind, Slice, Ty, TyCtxt, TypeFoldable, ToPredicate}; use ty::error::{ExpectedFound, TypeError}; use infer::{InferCtxt}; use rustc_data_structures::sync::Lrc; use std::rc::Rc; -use std::convert::From; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; @@ -280,37 +279,39 @@ pub enum QuantifierKind { Existential, } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Goal<'tcx> { - // FIXME: use interned refs instead of `Box` - Implies(Vec<Clause<'tcx>>, Box<Goal<'tcx>>), - And(Box<Goal<'tcx>>, Box<Goal<'tcx>>), - Not(Box<Goal<'tcx>>), + Implies(&'tcx Slice<Clause<'tcx>>, &'tcx Goal<'tcx>), + And(&'tcx Goal<'tcx>, &'tcx Goal<'tcx>), + Not(&'tcx Goal<'tcx>), DomainGoal(DomainGoal<'tcx>), - Quantified(QuantifierKind, Box<ty::Binder<Goal<'tcx>>>) -} - -impl<'tcx> From<DomainGoal<'tcx>> for Goal<'tcx> { - fn from(domain_goal: DomainGoal<'tcx>) -> Self { - Goal::DomainGoal(domain_goal) - } + Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>) } -impl<'tcx> From<PolyDomainGoal<'tcx>> for Goal<'tcx> { - fn from(domain_goal: PolyDomainGoal<'tcx>) -> Self { +impl<'tcx> Goal<'tcx> { + pub fn from_poly_domain_goal<'a>( + domain_goal: PolyDomainGoal<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ) -> Goal<'tcx> { match domain_goal.no_late_bound_regions() { Some(p) => p.into(), None => Goal::Quantified( QuantifierKind::Universal, - Box::new(domain_goal.map_bound(|p| p.into())) + domain_goal.map_bound(|p| tcx.mk_goal(Goal::from(p))) ), } } } +impl<'tcx> From<DomainGoal<'tcx>> for Goal<'tcx> { + fn from(domain_goal: DomainGoal<'tcx>) -> Self { + Goal::DomainGoal(domain_goal) + } +} + /// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary /// Harrop Formulas". -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Clause<'tcx> { Implies(ProgramClause<'tcx>), ForAll(ty::Binder<ProgramClause<'tcx>>), @@ -322,13 +323,13 @@ pub enum Clause<'tcx> { /// it with the reverse implication operator `:-` to emphasize the way /// that programs are actually solved (via backchaining, which starts /// with the goal to solve and proceeds from there). -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct ProgramClause<'tcx> { /// This goal will be considered true... pub goal: DomainGoal<'tcx>, /// ...if we can prove these hypotheses (there may be no hypotheses at all): - pub hypotheses: Vec<Goal<'tcx>>, + pub hypotheses: &'tcx Slice<Goal<'tcx>>, } pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index a1018cb946a..405dafdff2b 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -289,7 +289,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { let trait_str = tcx.item_path_str(trait_ref.def_id); let generics = tcx.generics_of(trait_ref.def_id); let generic_map = generics.types.iter().map(|param| { - (param.name.as_str().to_string(), + (param.name.to_string(), trait_ref.substs.type_for_def(param).to_string()) }).collect::<FxHashMap<String, String>>(); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 2a62d0b5ee3..9f21ea14d0f 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -345,7 +345,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, Reveal::UserFacing => ty, Reveal::All => { - let recursion_limit = self.tcx().sess.recursion_limit.get(); + let recursion_limit = *self.tcx().sess.recursion_limit.get(); if self.depth >= recursion_limit { let obligation = Obligation::with_depth( self.cause.clone(), @@ -566,7 +566,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( found cache entry: in-progress"); // But for now, let's classify this as an overflow: - let recursion_limit = selcx.tcx().sess.recursion_limit.get(); + let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); let obligation = Obligation::with_depth(cause.clone(), recursion_limit, param_env, @@ -848,7 +848,7 @@ fn project_type<'cx, 'gcx, 'tcx>( debug!("project(obligation={:?})", obligation); - let recursion_limit = selcx.tcx().sess.recursion_limit.get(); + let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); if obligation.recursion_depth >= recursion_limit { debug!("project: overflow!"); selcx.infcx().report_overflow_error(&obligation, true); diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 63f50cff4c2..5e0a4ca3305 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -109,7 +109,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx Reveal::UserFacing => ty, Reveal::All => { - let recursion_limit = self.tcx().sess.recursion_limit.get(); + let recursion_limit = *self.tcx().sess.recursion_limit.get(); if self.anon_depth >= recursion_limit { let obligation = Obligation::with_depth( self.cause.clone(), diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 58c591bf935..51493f26194 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -997,7 +997,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { // Watch out for overflow. This intentionally bypasses (and does // not update) the cache. - let recursion_limit = self.infcx.tcx.sess.recursion_limit.get(); + let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); if stack.obligation.recursion_depth >= recursion_limit { self.infcx().report_overflow_error(&stack.obligation, true); } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 865a9a34aaa..523cd42940e 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_data_structures::accumulate_vec::AccumulateVec; use traits; use traits::project::Normalized; use ty::{self, Lift, TyCtxt}; @@ -557,6 +558,28 @@ EnumTypeFoldableImpl! { } } +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<traits::Goal<'tcx>> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|t| t.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>(); + folder.tcx().intern_goals(&v) + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} + +impl<'tcx> TypeFoldable<'tcx> for &'tcx traits::Goal<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + let v = (**self).fold_with(folder); + folder.tcx().mk_goal(v) + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + (**self).visit_with(visitor) + } +} + BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for traits::ProgramClause<'tcx> { goal, @@ -570,3 +593,14 @@ EnumTypeFoldableImpl! { (traits::Clause::ForAll)(clause), } } + +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<traits::Clause<'tcx>> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + let v = self.iter().map(|t| t.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>(); + folder.tcx().intern_clauses(&v) + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + self.iter().any(|t| t.visit_with(visitor)) + } +} diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index c118b7a4692..3ba79d91964 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -20,7 +20,6 @@ use syntax::ast; pub enum IntTy { U(ast::UintTy), I, - Ivar, CEnum, Bool, Char @@ -64,7 +63,7 @@ impl<'tcx> CastTy<'tcx> { ty::TyBool => Some(CastTy::Int(IntTy::Bool)), ty::TyChar => Some(CastTy::Int(IntTy::Char)), ty::TyInt(_) => Some(CastTy::Int(IntTy::I)), - ty::TyInfer(ty::InferTy::IntVar(_)) => Some(CastTy::Int(IntTy::Ivar)), + ty::TyInfer(ty::InferTy::IntVar(_)) => Some(CastTy::Int(IntTy::I)), ty::TyInfer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float), ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))), ty::TyFloat(_) => Some(CastTy::Float), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 69b33efdb35..88a2619c7e3 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -38,6 +38,7 @@ use ty::subst::{Kind, Substs}; use ty::ReprOptions; use ty::Instance; use traits; +use traits::{Clause, Goal}; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const}; @@ -50,7 +51,7 @@ use ty::maps; use ty::steal::Steal; use ty::BindingMode; use ty::CanonicalTy; -use util::nodemap::{NodeMap, DefIdSet, ItemLocalMap}; +use util::nodemap::{DefIdSet, ItemLocalMap}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, @@ -58,7 +59,7 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableVec}; use arena::{TypedArena, DroplessArena}; use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{Lrc, Lock}; use std::any::Any; use std::borrow::Borrow; use std::cell::{Cell, RefCell}; @@ -71,11 +72,11 @@ use std::iter; use std::sync::mpsc; use std::sync::Arc; use syntax::abi; -use syntax::ast::{self, Name, NodeId}; +use syntax::ast::{self, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; use syntax::feature_gate; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::{Symbol, keywords, InternedString}; use syntax_pos::Span; use hir; @@ -125,34 +126,40 @@ impl<'tcx> GlobalArenas<'tcx> { } } +type InternedSet<'tcx, T> = Lock<FxHashSet<Interned<'tcx, T>>>; + pub struct CtxtInterners<'tcx> { /// The arena that types, regions, etc are allocated from arena: &'tcx DroplessArena, /// Specifically use a speedy hash algorithm for these hash sets, /// they're accessed quite often. - type_: RefCell<FxHashSet<Interned<'tcx, TyS<'tcx>>>>, - type_list: RefCell<FxHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>, - substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>, - canonical_var_infos: RefCell<FxHashSet<Interned<'tcx, Slice<CanonicalVarInfo>>>>, - region: RefCell<FxHashSet<Interned<'tcx, RegionKind>>>, - existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>, - predicates: RefCell<FxHashSet<Interned<'tcx, Slice<Predicate<'tcx>>>>>, - const_: RefCell<FxHashSet<Interned<'tcx, Const<'tcx>>>>, + type_: InternedSet<'tcx, TyS<'tcx>>, + type_list: InternedSet<'tcx, Slice<Ty<'tcx>>>, + substs: InternedSet<'tcx, Substs<'tcx>>, + canonical_var_infos: InternedSet<'tcx, Slice<CanonicalVarInfo>>, + region: InternedSet<'tcx, RegionKind>, + existential_predicates: InternedSet<'tcx, Slice<ExistentialPredicate<'tcx>>>, + predicates: InternedSet<'tcx, Slice<Predicate<'tcx>>>, + const_: InternedSet<'tcx, Const<'tcx>>, + clauses: InternedSet<'tcx, Slice<Clause<'tcx>>>, + goals: InternedSet<'tcx, Slice<Goal<'tcx>>>, } impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { fn new(arena: &'tcx DroplessArena) -> CtxtInterners<'tcx> { CtxtInterners { arena, - type_: RefCell::new(FxHashSet()), - type_list: RefCell::new(FxHashSet()), - substs: RefCell::new(FxHashSet()), - region: RefCell::new(FxHashSet()), - existential_predicates: RefCell::new(FxHashSet()), - canonical_var_infos: RefCell::new(FxHashSet()), - predicates: RefCell::new(FxHashSet()), - const_: RefCell::new(FxHashSet()), + type_: Default::default(), + type_list: Default::default(), + substs: Default::default(), + region: Default::default(), + existential_predicates: Default::default(), + canonical_var_infos: Default::default(), + predicates: Default::default(), + const_: Default::default(), + clauses: Default::default(), + goals: Default::default(), } } @@ -346,6 +353,12 @@ pub struct TypeckTables<'tcx> { /// method calls, including those of overloaded operators. type_dependent_defs: ItemLocalMap<Def>, + /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`) + /// or patterns (`S { field }`). The index is often useful by itself, but to learn more + /// about the field you also need definition of the variant to which the field + /// belongs, but it may not exist if it's a tuple field (`tuple.0`). + field_indices: ItemLocalMap<usize>, + /// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in /// MIR. user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>, @@ -426,6 +439,7 @@ impl<'tcx> TypeckTables<'tcx> { TypeckTables { local_id_root, type_dependent_defs: ItemLocalMap(), + field_indices: ItemLocalMap(), user_provided_tys: ItemLocalMap(), node_types: ItemLocalMap(), node_substs: ItemLocalMap(), @@ -468,6 +482,20 @@ impl<'tcx> TypeckTables<'tcx> { } } + pub fn field_indices(&self) -> LocalTableInContext<usize> { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.field_indices + } + } + + pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<usize> { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.field_indices + } + } + pub fn user_provided_tys(&self) -> LocalTableInContext<CanonicalTy<'tcx>> { LocalTableInContext { local_id_root: self.local_id_root, @@ -706,6 +734,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> { let ty::TypeckTables { local_id_root, ref type_dependent_defs, + ref field_indices, ref user_provided_tys, ref node_types, ref node_substs, @@ -726,6 +755,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { type_dependent_defs.hash_stable(hcx, hasher); + field_indices.hash_stable(hcx, hasher); user_provided_tys.hash_stable(hcx, hasher); node_types.hash_stable(hcx, hasher); node_substs.hash_stable(hcx, hasher); @@ -888,21 +918,11 @@ pub struct GlobalCtxt<'tcx> { /// Used to prevent layout from recursing too deeply. pub layout_depth: Cell<usize>, - /// Map from function to the `#[derive]` mode that it's defining. Only used - /// by `proc-macro` crates. - pub derive_macros: RefCell<NodeMap<Symbol>>, - - stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>, + stability_interner: Lock<FxHashSet<&'tcx attr::Stability>>, pub interpret_interner: InterpretInterner<'tcx>, - layout_interner: RefCell<FxHashSet<&'tcx LayoutDetails>>, - - /// A vector of every trait accessible in the whole crate - /// (i.e. including those from subcrates). This is used only for - /// error reporting, and so is lazily initialized and generally - /// shouldn't taint the common path (hence the RefCell). - pub all_traits: RefCell<Option<Vec<DefId>>>, + layout_interner: Lock<FxHashSet<&'tcx LayoutDetails>>, /// A general purpose channel to throw data out the back towards LLVM worker /// threads. @@ -910,7 +930,7 @@ pub struct GlobalCtxt<'tcx> { /// This is intended to only get used during the trans phase of the compiler /// when satisfying the query for a particular codegen unit. Internally in /// the query it'll send data along this channel to get processed later. - pub tx_to_llvm_workers: mpsc::Sender<Box<dyn Any + Send>>, + pub tx_to_llvm_workers: Lock<mpsc::Sender<Box<dyn Any + Send>>>, output_filenames: Arc<OutputFilenames>, } @@ -918,7 +938,7 @@ pub struct GlobalCtxt<'tcx> { /// Everything needed to efficiently work with interned allocations #[derive(Debug, Default)] pub struct InterpretInterner<'tcx> { - inner: RefCell<InterpretInternerInner<'tcx>>, + inner: Lock<InterpretInternerInner<'tcx>>, } #[derive(Debug, Default)] @@ -1278,13 +1298,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { evaluation_cache: traits::EvaluationCache::new(), crate_name: Symbol::intern(crate_name), data_layout, - layout_interner: RefCell::new(FxHashSet()), + layout_interner: Lock::new(FxHashSet()), layout_depth: Cell::new(0), - derive_macros: RefCell::new(NodeMap()), - stability_interner: RefCell::new(FxHashSet()), + stability_interner: Lock::new(FxHashSet()), interpret_interner: Default::default(), - all_traits: RefCell::new(None), - tx_to_llvm_workers: tx, + tx_to_llvm_workers: Lock::new(tx), output_filenames: Arc::new(output_filenames.clone()), }; @@ -2088,6 +2106,20 @@ impl<'tcx: 'lcx, 'lcx> Borrow<Const<'lcx>> for Interned<'tcx, Const<'tcx>> { } } +impl<'tcx: 'lcx, 'lcx> Borrow<[Clause<'lcx>]> +for Interned<'tcx, Slice<Clause<'tcx>>> { + fn borrow<'a>(&'a self) -> &'a [Clause<'lcx>] { + &self.0[..] + } +} + +impl<'tcx: 'lcx, 'lcx> Borrow<[Goal<'lcx>]> +for Interned<'tcx, Slice<Goal<'tcx>>> { + fn borrow<'a>(&'a self) -> &'a [Goal<'lcx>] { + &self.0[..] + } +} + macro_rules! intern_method { ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty, $alloc_method:ident, @@ -2185,7 +2217,9 @@ slice_interners!( existential_predicates: _intern_existential_predicates(ExistentialPredicate), predicates: _intern_predicates(Predicate), type_list: _intern_type_list(Ty), - substs: _intern_substs(Kind) + substs: _intern_substs(Kind), + clauses: _intern_clauses(Clause), + goals: _intern_goals(Goal) ); // This isn't a perfect fit: CanonicalVarInfo slices are always @@ -2430,12 +2464,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_param(self, index: u32, - name: Name) -> Ty<'tcx> { + name: InternedString) -> Ty<'tcx> { self.mk_ty(TyParam(ParamTy { idx: index, name: name })) } pub fn mk_self_type(self) -> Ty<'tcx> { - self.mk_param(0, keywords::SelfType.name()) + self.mk_param(0, keywords::SelfType.name().as_str()) } pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> { @@ -2490,6 +2524,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> &'tcx Slice<Clause<'tcx>> { + if ts.len() == 0 { + Slice::empty() + } else { + self._intern_clauses(ts) + } + } + + pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> &'tcx Slice<Goal<'tcx>> { + if ts.len() == 0 { + Slice::empty() + } else { + self._intern_goals(ts) + } + } + pub fn mk_fn_sig<I>(self, inputs: I, output: I::Item, @@ -2536,6 +2586,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from)) } + pub fn mk_clauses<I: InternAs<[Clause<'tcx>], + &'tcx Slice<Clause<'tcx>>>>(self, iter: I) -> I::Output { + iter.intern_with(|xs| self.intern_clauses(xs)) + } + + pub fn mk_goals<I: InternAs<[Goal<'tcx>], + &'tcx Slice<Goal<'tcx>>>>(self, iter: I) -> I::Output { + iter.intern_with(|xs| self.intern_goals(xs)) + } + + pub fn mk_goal(self, goal: Goal<'tcx>) -> &'tcx Goal { + &self.mk_goals(iter::once(goal))[0] + } + pub fn lint_node<S: Into<MultiSpan>>(self, lint: &'static Lint, id: NodeId, diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5f9c305d92f..35ada4a7227 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -12,7 +12,7 @@ pub use self::Integer::*; pub use self::Primitive::*; use session::{self, DataTypeKind, Session}; -use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags}; +use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; use syntax::ast::{self, FloatTy, IntTy, UintTy}; use syntax::attr; @@ -344,8 +344,8 @@ impl AddAssign for Size { /// a maximum capacity of 2<sup>31</sup> - 1 or 2147483647. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Align { - abi: u8, - pref: u8, + abi_pow2: u8, + pref_pow2: u8, } impl Align { @@ -377,17 +377,17 @@ impl Align { }; Ok(Align { - abi: log2(abi)?, - pref: log2(pref)?, + abi_pow2: log2(abi)?, + pref_pow2: log2(pref)?, }) } pub fn abi(self) -> u64 { - 1 << self.abi + 1 << self.abi_pow2 } pub fn pref(self) -> u64 { - 1 << self.pref + 1 << self.pref_pow2 } pub fn abi_bits(self) -> u64 { @@ -400,15 +400,15 @@ impl Align { pub fn min(self, other: Align) -> Align { Align { - abi: cmp::min(self.abi, other.abi), - pref: cmp::min(self.pref, other.pref), + abi_pow2: cmp::min(self.abi_pow2, other.abi_pow2), + pref_pow2: cmp::min(self.pref_pow2, other.pref_pow2), } } pub fn max(self, other: Align) -> Align { Align { - abi: cmp::max(self.abi, other.abi), - pref: cmp::max(self.pref, other.pref), + abi_pow2: cmp::max(self.abi_pow2, other.abi_pow2), + pref_pow2: cmp::max(self.pref_pow2, other.pref_pow2), } } } @@ -898,7 +898,7 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); - let rec_limit = tcx.sess.recursion_limit.get(); + let rec_limit = *tcx.sess.recursion_limit.get(); let depth = tcx.layout_depth.get(); if depth > rec_limit { tcx.sess.fatal( @@ -974,6 +974,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { bug!("struct cannot be packed and aligned"); } + let pack = { + let pack = repr.pack as u64; + Align::from_bytes(pack, pack).unwrap() + }; + let mut align = if packed { dl.i8_align } else { @@ -984,8 +989,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let mut offsets = vec![Size::from_bytes(0); fields.len()]; let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect(); - // Anything with repr(C) or repr(packed) doesn't optimize. - let mut optimize = (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty(); + let mut optimize = !repr.inhibit_struct_field_reordering_opt(); if let StructKind::Prefixed(_, align) = kind { optimize &= align.abi() == 1; } @@ -997,6 +1001,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { fields.len() }; let optimizing = &mut inverse_memory_index[..end]; + let field_align = |f: &TyLayout| { + if packed { f.align.min(pack).abi() } else { f.align.abi() } + }; match kind { StructKind::AlwaysSized | StructKind::MaybeUnsized => { @@ -1004,11 +1011,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Place ZSTs first to avoid "interesting offsets", // especially with only one or two non-ZST fields. let f = &fields[x as usize]; - (!f.is_zst(), cmp::Reverse(f.align.abi())) - }) + (!f.is_zst(), cmp::Reverse(field_align(f))) + }); } StructKind::Prefixed(..) => { - optimizing.sort_by_key(|&x| fields[x as usize].align.abi()); + optimizing.sort_by_key(|&x| field_align(&fields[x as usize])); } } } @@ -1022,7 +1029,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let mut offset = Size::from_bytes(0); if let StructKind::Prefixed(prefix_size, prefix_align) = kind { - if !packed { + if packed { + let prefix_align = prefix_align.min(pack); + align = align.max(prefix_align); + } else { align = align.max(prefix_align); } offset = prefix_size.abi_align(prefix_align); @@ -1044,7 +1054,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } // Invariant: offset < dl.obj_size_bound() <= 1<<61 - if !packed { + if packed { + let field_pack = field.align.min(pack); + offset = offset.abi_align(field_pack); + align = align.max(field_pack); + } + else { offset = offset.abi_align(field.align); align = align.max(field.align); } @@ -1377,7 +1392,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { bug!("Union cannot be packed and aligned"); } - let mut align = if def.repr.packed() { + let pack = { + let pack = def.repr.pack as u64; + Align::from_bytes(pack, pack).unwrap() + }; + + let mut align = if packed { dl.i8_align } else { dl.aggregate_align @@ -1393,7 +1413,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { for field in &variants[0] { assert!(!field.is_unsized()); - if !packed { + if packed { + let field_pack = field.align.min(pack); + align = align.max(field_pack); + } else { align = align.max(field.align); } size = cmp::max(size, field.size); @@ -1471,10 +1494,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Find one non-ZST variant. 'variants: for (v, fields) in variants.iter().enumerate() { + if fields.iter().any(|f| f.abi == Abi::Uninhabited) { + continue 'variants; + } for f in fields { - if f.abi == Abi::Uninhabited { - continue 'variants; - } if !f.is_zst() { if dataful_variant.is_none() { dataful_variant = Some(v); @@ -1740,12 +1763,13 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) { // (delay format until we actually need it) - let record = |kind, opt_discr_size, variants| { + let record = |kind, packed, opt_discr_size, variants| { let type_desc = format!("{:?}", layout.ty); self.tcx.sess.code_stats.borrow_mut().record_type_size(kind, type_desc, layout.align, layout.size, + packed, opt_discr_size, variants); }; @@ -1758,7 +1782,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { ty::TyClosure(..) => { debug!("print-type-size t: `{:?}` record closure", layout.ty); - record(DataTypeKind::Closure, None, vec![]); + record(DataTypeKind::Closure, false, None, vec![]); return; } @@ -1769,6 +1793,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { }; let adt_kind = adt_def.adt_kind(); + let adt_packed = adt_def.repr.packed(); let build_variant_info = |n: Option<ast::Name>, flds: &[ast::Name], @@ -1821,6 +1846,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect(); record(adt_kind.into(), + adt_packed, None, vec![build_variant_info(Some(variant_def.name), &fields, @@ -1828,7 +1854,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } else { // (This case arises for *empty* enums; so give it // zero variants.) - record(adt_kind.into(), None, vec![]); + record(adt_kind.into(), adt_packed, None, vec![]); } } @@ -1845,7 +1871,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { layout.for_variant(self, i)) }) .collect(); - record(adt_kind.into(), match layout.variants { + record(adt_kind.into(), adt_packed, match layout.variants { Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)), _ => None }, variant_infos); @@ -2518,8 +2544,8 @@ impl_stable_hash_for!(enum ::ty::layout::Primitive { }); impl_stable_hash_for!(struct ::ty::layout::Align { - abi, - pref + abi_pow2, + pref_pow2 }); impl_stable_hash_for!(struct ::ty::layout::Size { diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 16866636cd9..664c84f5986 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -155,6 +155,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::crate_variances<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::inferred_outlives_crate<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("computing the inferred outlives predicates for items in this crate") + } +} + impl<'tcx> QueryDescription<'tcx> for queries::mir_shims<'tcx> { fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String { format!("generating MIR shim for `{}`", @@ -586,6 +592,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::stability_index<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::all_traits<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("fetching all foreign and local traits") + } +} + impl<'tcx> QueryDescription<'tcx> for queries::all_crate_nums<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { format!("fetching all foreign CrateNum instances") diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 5a23a3b952a..d317f5a494b 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -39,7 +39,7 @@ use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::specialization_graph; use traits::Clause; -use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; +use ty::{self, CrateInherentImpls, ParamEnvAnd, Slice, Ty, TyCtxt}; use ty::steal::Steal; use ty::subst::Substs; use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; @@ -102,6 +102,7 @@ define_maps! { <'tcx> /// associated generics and predicates. [] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics, [] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + [] fn explicit_predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, /// Maps from the def-id of a trait to the list of /// super-predicates. This is a subset of the full list of @@ -139,7 +140,11 @@ define_maps! { <'tcx> [] fn variances_of: ItemVariances(DefId) -> Lrc<Vec<ty::Variance>>, /// Maps from def-id of a type to its (inferred) outlives. - [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Vec<ty::Predicate<'tcx>>, + [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>, + + /// Maps from def-id of a type to its (inferred) outlives. + [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum) + -> Lrc<ty::CratePredicatesMap<'tcx>>, /// Maps from an impl/trait def-id to a list of the def-ids of its items [] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Lrc<Vec<DefId>>, @@ -386,6 +391,11 @@ define_maps! { <'tcx> [] fn stability_index: stability_index_node(CrateNum) -> Lrc<stability::Index<'tcx>>, [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc<Vec<CrateNum>>, + /// A vector of every trait accessible in the whole crate + /// (i.e. including those from subcrates). This is used only for + /// error reporting. + [] fn all_traits: all_traits_node(CrateNum) -> Lrc<Vec<DefId>>, + [] fn exported_symbols: ExportedSymbols(CrateNum) -> Arc<Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)>>, [] fn collect_and_partition_translation_items: @@ -435,7 +445,7 @@ define_maps! { <'tcx> [] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>, - [] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc<Vec<Clause<'tcx>>>, + [] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc<&'tcx Slice<Clause<'tcx>>>, [] fn wasm_custom_sections: WasmCustomSections(CrateNum) -> Lrc<Vec<DefId>>, [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum) @@ -575,6 +585,10 @@ fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::AllCrateNums } +fn all_traits_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::AllTraits +} + fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::CollectAndPartitionTranslationItems } diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 232b300e754..efe7a56d800 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -671,7 +671,16 @@ macro_rules! define_maps { map: LockGuard<'_, QueryMap<$tcx, Self>>, dep_node: DepNode) -> Result<($V, DepNodeIndex), CycleError<$tcx>> { - debug_assert!(!tcx.dep_graph.dep_node_exists(&dep_node)); + // If the following assertion triggers, it can have two reasons: + // 1. Something is wrong with DepNode creation, either here or + // in DepGraph::try_mark_green() + // 2. Two distinct query keys get mapped to the same DepNode + // (see for example #48923) + assert!(!tcx.dep_graph.dep_node_exists(&dep_node), + "Forcing query with already existing DepNode.\n\ + - query-key: {:?}\n\ + - dep-node: {:?}", + key, dep_node); profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); let res = Self::start_job(tcx, @@ -998,6 +1007,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::GenericsOfItem => { force!(generics_of, def_id!()); } DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); } DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); } + DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); } DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); } DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); } DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); } @@ -1115,6 +1125,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, } DepKind::MaybeUnusedExternCrates => { force!(maybe_unused_extern_crates, LOCAL_CRATE); } DepKind::StabilityIndex => { force!(stability_index, LOCAL_CRATE); } + DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); } DepKind::AllCrateNums => { force!(all_crate_nums, LOCAL_CRATE); } DepKind::ExportedSymbols => { force!(exported_symbols, krate!()); } DepKind::CollectAndPartitionTranslationItems => { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b920553ec36..6618f9bc2f5 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -50,7 +50,7 @@ use std::vec::IntoIter; use std::mem; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; -use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::ext::hygiene::Mark; use syntax::symbol::{Symbol, InternedString}; use syntax_pos::{DUMMY_SP, Span}; @@ -712,7 +712,7 @@ pub struct FloatVarValue(pub ast::FloatTy); #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct TypeParameterDef { - pub name: Name, + pub name: InternedString, pub def_id: DefId, pub index: u32, pub has_default: bool, @@ -956,6 +956,22 @@ pub enum Predicate<'tcx> { ConstEvaluatable(DefId, &'tcx Substs<'tcx>), } +/// The crate outlives map is computed during typeck and contains the +/// outlives of every item in the local crate. You should not use it +/// directly, because to do so will make your pass dependent on the +/// HIR of every item in the local crate. Instead, use +/// `tcx.inferred_outlives_of()` to get the outlives for a *particular* +/// item. +pub struct CratePredicatesMap<'tcx> { + /// For each struct with outlive bounds, maps to a vector of the + /// predicate of its outlive bounds. If an item has no outlives + /// bounds, it will have no entry. + pub predicates: FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>, + + /// An empty vector, useful for cloning. + pub empty_predicate: Lrc<Vec<ty::Predicate<'tcx>>>, +} + impl<'tcx> AsRef<Predicate<'tcx>> for Predicate<'tcx> { fn as_ref(&self) -> &Predicate<'tcx> { self @@ -1623,15 +1639,13 @@ bitflags! { #[derive(RustcEncodable, RustcDecodable, Default)] pub struct ReprFlags: u8 { const IS_C = 1 << 0; - const IS_PACKED = 1 << 1; - const IS_SIMD = 1 << 2; - const IS_TRANSPARENT = 1 << 3; + const IS_SIMD = 1 << 1; + const IS_TRANSPARENT = 1 << 2; // Internal only for now. If true, don't reorder fields. - const IS_LINEAR = 1 << 4; + const IS_LINEAR = 1 << 3; // Any of these flags being set prevent field reordering optimisation. const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | - ReprFlags::IS_PACKED.bits | ReprFlags::IS_SIMD.bits | ReprFlags::IS_LINEAR.bits; } @@ -1648,11 +1662,13 @@ impl_stable_hash_for!(struct ReprFlags { pub struct ReprOptions { pub int: Option<attr::IntType>, pub align: u32, + pub pack: u32, pub flags: ReprFlags, } impl_stable_hash_for!(struct ReprOptions { align, + pack, int, flags }); @@ -1662,11 +1678,19 @@ impl ReprOptions { let mut flags = ReprFlags::empty(); let mut size = None; let mut max_align = 0; + let mut min_pack = 0; for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) { flags.insert(match r { attr::ReprC => ReprFlags::IS_C, - attr::ReprPacked => ReprFlags::IS_PACKED, + attr::ReprPacked(pack) => { + min_pack = if min_pack > 0 { + cmp::min(pack, min_pack) + } else { + pack + }; + ReprFlags::empty() + }, attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, attr::ReprSimd => ReprFlags::IS_SIMD, attr::ReprInt(i) => { @@ -1685,7 +1709,7 @@ impl ReprOptions { if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) { flags.insert(ReprFlags::IS_LINEAR); } - ReprOptions { int: size, align: max_align, flags: flags } + ReprOptions { int: size, align: max_align, pack: min_pack, flags: flags } } #[inline] @@ -1693,7 +1717,7 @@ impl ReprOptions { #[inline] pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) } #[inline] - pub fn packed(&self) -> bool { self.flags.contains(ReprFlags::IS_PACKED) } + pub fn packed(&self) -> bool { self.pack > 0 } #[inline] pub fn transparent(&self) -> bool { self.flags.contains(ReprFlags::IS_TRANSPARENT) } #[inline] @@ -1709,6 +1733,12 @@ impl ReprOptions { pub fn inhibit_enum_layout_opt(&self) -> bool { self.c() || self.int.is_some() } + + /// Returns true if this `#[repr()]` should inhibit struct field reordering + /// optimizations, such as with repr(C) or repr(packed(1)). + pub fn inhibit_struct_field_reordering_opt(&self) -> bool { + !(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1) + } } impl<'a, 'gcx, 'tcx> AdtDef { @@ -2077,32 +2107,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } -impl<'a, 'gcx, 'tcx> VariantDef { - #[inline] - pub fn find_field_named(&self, name: ast::Name) -> Option<&FieldDef> { - self.index_of_field_named(name).map(|index| &self.fields[index]) - } - - pub fn index_of_field_named(&self, name: ast::Name) -> Option<usize> { - if let Some(index) = self.fields.iter().position(|f| f.name == name) { - return Some(index); - } - let mut ident = name.to_ident(); - while ident.span.ctxt() != SyntaxContext::empty() { - ident.span.remove_mark(); - if let Some(field) = self.fields.iter().position(|f| f.name.to_ident() == ident) { - return Some(field); - } - } - None - } - - #[inline] - pub fn field_named(&self, name: ast::Name) -> &FieldDef { - self.find_field_named(name).unwrap() - } -} - impl<'a, 'gcx, 'tcx> FieldDef { pub fn ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { tcx.type_of(self.did).subst(tcx, subst) @@ -2369,6 +2373,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn field_index(self, node_id: NodeId, tables: &TypeckTables) -> usize { + let hir_id = self.hir.node_to_hir_id(node_id); + tables.field_indices().get(hir_id).cloned().expect("no index for a field") + } + + pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> { + variant.fields.iter().position(|field| { + self.adjust_ident(ident.modern(), variant.did, DUMMY_NODE_ID).0 == field.name.to_ident() + }) + } + pub fn associated_items( self, def_id: DefId, diff --git a/src/librustc/ty/steal.rs b/src/librustc/ty/steal.rs index 0b081888881..842c0d65734 100644 --- a/src/librustc/ty/steal.rs +++ b/src/librustc/ty/steal.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell::{Ref, RefCell}; +use rustc_data_structures::sync::{RwLock, ReadGuard}; use std::mem; /// The `Steal` struct is intended to used as the value for a query. @@ -32,25 +32,25 @@ use std::mem; /// /// FIXME(#41710) -- what is the best way to model linear queries? pub struct Steal<T> { - value: RefCell<Option<T>> + value: RwLock<Option<T>> } impl<T> Steal<T> { pub fn new(value: T) -> Self { Steal { - value: RefCell::new(Some(value)) + value: RwLock::new(Some(value)) } } - pub fn borrow(&self) -> Ref<T> { - Ref::map(self.value.borrow(), |opt| match *opt { + pub fn borrow(&self) -> ReadGuard<T> { + ReadGuard::map(self.value.borrow(), |opt| match *opt { None => bug!("attempted to read from stolen value"), Some(ref v) => v }) } pub fn steal(&self) -> T { - let value_ref = &mut *self.value.borrow_mut(); + let value_ref = &mut *self.value.try_write().expect("stealing value which is locked"); let value = mem::replace(value_ref, None); value.expect("attempt to read from stolen value") } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index ed04d41ba14..7a9174cbfaf 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -24,7 +24,7 @@ use std::iter; use std::cmp::Ordering; use syntax::abi; use syntax::ast::{self, Name}; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, InternedString}; use serialize; @@ -864,16 +864,16 @@ impl<'tcx> PolyFnSig<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct ParamTy { pub idx: u32, - pub name: Name, + pub name: InternedString, } impl<'a, 'gcx, 'tcx> ParamTy { - pub fn new(index: u32, name: Name) -> ParamTy { + pub fn new(index: u32, name: InternedString) -> ParamTy { ParamTy { idx: index, name: name } } pub fn for_self() -> ParamTy { - ParamTy::new(0, keywords::SelfType.name()) + ParamTy::new(0, keywords::SelfType.name().as_str()) } pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { @@ -885,7 +885,7 @@ impl<'a, 'gcx, 'tcx> ParamTy { } pub fn is_self(&self) -> bool { - if self.name == keywords::SelfType.name() { + if self.name == keywords::SelfType.name().as_str() { assert_eq!(self.idx, 0); true } else { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 22f851a908b..77eff49d19f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -33,7 +33,7 @@ use rustc_data_structures::fx::FxHashMap; use std::{cmp, fmt}; use std::hash::Hash; use std::intrinsics; -use syntax::ast::{self, Name}; +use syntax::ast; use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax_pos::{Span, DUMMY_SP}; @@ -270,42 +270,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { false } - /// Returns the type of element at index `i` in tuple or tuple-like type `t`. - /// For an enum `t`, `variant` is None only if `t` is a univariant enum. - pub fn positional_element_ty(self, - ty: Ty<'tcx>, - i: usize, - variant: Option<DefId>) -> Option<Ty<'tcx>> { - match (&ty.sty, variant) { - (&TyAdt(adt, substs), Some(vid)) => { - adt.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyAdt(adt, substs), None) => { - // Don't use `non_enum_variant`, this may be a univariant enum. - adt.variants[0].fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyTuple(ref v), None) => v.get(i).cloned(), - _ => None, - } - } - - /// Returns the type of element at field `n` in struct or struct-like type `t`. - /// For an enum `t`, `variant` must be some def id. - pub fn named_element_ty(self, - ty: Ty<'tcx>, - n: Name, - variant: Option<DefId>) -> Option<Ty<'tcx>> { - match (&ty.sty, variant) { - (&TyAdt(adt, substs), Some(vid)) => { - adt.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) - } - (&TyAdt(adt, substs), None) => { - adt.non_enum_variant().find_field_named(n).map(|f| f.ty(self, substs)) - } - _ => return None - } - } - /// Returns the deeply last field of nested structures, or the same type, /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. @@ -729,7 +693,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> } TyParam(p) => { self.hash(p.idx); - self.hash(p.name.as_str()); + self.hash(p.name); } TyProjection(ref data) => { self.def_id(data.item_def_id); diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 32ec837f031..bb6aa654c29 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -10,6 +10,8 @@ #![allow(non_camel_case_types)] +use rustc_data_structures::sync::Lock; + use std::cell::{RefCell, Cell}; use std::collections::HashMap; use std::ffi::CString; @@ -236,13 +238,14 @@ pub fn to_readable_str(mut val: usize) -> String { groups.join("_") } -pub fn record_time<T, F>(accu: &Cell<Duration>, f: F) -> T where +pub fn record_time<T, F>(accu: &Lock<Duration>, f: F) -> T where F: FnOnce() -> T, { let start = Instant::now(); let rv = f(); let duration = start.elapsed(); - accu.set(duration + accu.get()); + let mut accu = accu.lock(); + *accu = *accu + duration; rv } @@ -382,13 +385,3 @@ fn test_to_readable_str() { assert_eq!("1_000_000", to_readable_str(1_000_000)); assert_eq!("1_234_567", to_readable_str(1_234_567)); } - -pub trait CellUsizeExt { - fn increment(&self); -} - -impl CellUsizeExt for Cell<usize> { - fn increment(&self) { - self.set(self.get() + 1); - } -} diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index ee38cca7828..305502e7f06 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -11,7 +11,7 @@ use rustc::middle::allocator::AllocatorKind; use rustc_errors; use syntax::abi::Abi; -use syntax::ast::{Crate, Attribute, LitKind, StrStyle, ExprKind}; +use syntax::ast::{Crate, Attribute, LitKind, StrStyle}; use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg}; use syntax::ast::{self, Ident, Item, ItemKind, TyKind, VisibilityKind, Expr}; use syntax::attr; @@ -88,7 +88,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { span, kind: AllocatorKind::Global, global: item.ident, - alloc: Ident::from_str("alloc"), + core: Ident::from_str("core"), cx: ExtCtxt::new(self.sess, ecfg, self.resolver), }; let super_path = f.cx.path(f.span, vec![ @@ -96,7 +96,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { f.global, ]); let mut items = vec![ - f.cx.item_extern_crate(f.span, f.alloc), + f.cx.item_extern_crate(f.span, f.core), f.cx.item_use_simple( f.span, respan(f.span.shrink_to_lo(), VisibilityKind::Inherited), @@ -126,7 +126,7 @@ struct AllocFnFactory<'a> { span: Span, kind: AllocatorKind, global: Ident, - alloc: Ident, + core: Ident, cx: ExtCtxt<'a>, } @@ -143,8 +143,7 @@ impl<'a> AllocFnFactory<'a> { self.arg_ty(ty, &mut abi_args, mk) }).collect(); let result = self.call_allocator(method.name, args); - let (output_ty, output_expr) = - self.ret_ty(&method.output, &mut abi_args, mk, result); + let (output_ty, output_expr) = self.ret_ty(&method.output, result); let kind = ItemKind::Fn(self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)), Unsafety::Unsafe, dummy_spanned(Constness::NotConst), @@ -159,16 +158,15 @@ impl<'a> AllocFnFactory<'a> { fn call_allocator(&self, method: &str, mut args: Vec<P<Expr>>) -> P<Expr> { let method = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("Alloc"), + self.core, + Ident::from_str("alloc"), + Ident::from_str("GlobalAlloc"), Ident::from_str(method), ]); let method = self.cx.expr_path(method); let allocator = self.cx.path_ident(self.span, self.global); let allocator = self.cx.expr_path(allocator); let allocator = self.cx.expr_addr_of(self.span, allocator); - let allocator = self.cx.expr_mut_addr_of(self.span, allocator); args.insert(0, allocator); self.cx.expr_call(self.span, method, args) @@ -205,8 +203,8 @@ impl<'a> AllocFnFactory<'a> { args.push(self.cx.arg(self.span, align, ty_usize)); let layout_new = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), + self.core, + Ident::from_str("alloc"), Ident::from_str("Layout"), Ident::from_str("from_size_align_unchecked"), ]); @@ -219,240 +217,38 @@ impl<'a> AllocFnFactory<'a> { layout } - AllocatorTy::LayoutRef => { - let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.ptr_u8())); - - // Convert our `arg: *const u8` via: - // - // &*(arg as *const Layout) - let expr = self.cx.expr_ident(self.span, ident); - let expr = self.cx.expr_cast(self.span, expr, self.layout_ptr()); - let expr = self.cx.expr_deref(self.span, expr); - self.cx.expr_addr_of(self.span, expr) - } - - AllocatorTy::AllocErr => { - // We're creating: - // - // (*(arg as *const AllocErr)).clone() + AllocatorTy::Ptr => { let ident = ident(); args.push(self.cx.arg(self.span, ident, self.ptr_u8())); - let expr = self.cx.expr_ident(self.span, ident); - let expr = self.cx.expr_cast(self.span, expr, self.alloc_err_ptr()); - let expr = self.cx.expr_deref(self.span, expr); - self.cx.expr_method_call( - self.span, - expr, - Ident::from_str("clone"), - Vec::new() - ) + let arg = self.cx.expr_ident(self.span, ident); + self.cx.expr_cast(self.span, arg, self.ptr_opaque()) } - AllocatorTy::Ptr => { + AllocatorTy::Usize => { let ident = ident(); - args.push(self.cx.arg(self.span, ident, self.ptr_u8())); + args.push(self.cx.arg(self.span, ident, self.usize())); self.cx.expr_ident(self.span, ident) } AllocatorTy::ResultPtr | - AllocatorTy::ResultExcess | - AllocatorTy::ResultUnit | AllocatorTy::Bang | - AllocatorTy::UsizePair | AllocatorTy::Unit => { panic!("can't convert AllocatorTy to an argument") } } } - fn ret_ty(&self, - ty: &AllocatorTy, - args: &mut Vec<Arg>, - ident: &mut FnMut() -> Ident, - expr: P<Expr>) -> (P<Ty>, P<Expr>) - { + fn ret_ty(&self, ty: &AllocatorTy, expr: P<Expr>) -> (P<Ty>, P<Expr>) { match *ty { - AllocatorTy::UsizePair => { - // We're creating: - // - // let arg = #expr; - // *min = arg.0; - // *max = arg.1; - - let min = ident(); - let max = ident(); - - args.push(self.cx.arg(self.span, min, self.ptr_usize())); - args.push(self.cx.arg(self.span, max, self.ptr_usize())); - - let ident = ident(); - let stmt = self.cx.stmt_let(self.span, false, ident, expr); - let min = self.cx.expr_ident(self.span, min); - let max = self.cx.expr_ident(self.span, max); - let layout = self.cx.expr_ident(self.span, ident); - let assign_min = self.cx.expr(self.span, ExprKind::Assign( - self.cx.expr_deref(self.span, min), - self.cx.expr_tup_field_access(self.span, layout.clone(), 0), - )); - let assign_min = self.cx.stmt_semi(assign_min); - let assign_max = self.cx.expr(self.span, ExprKind::Assign( - self.cx.expr_deref(self.span, max), - self.cx.expr_tup_field_access(self.span, layout.clone(), 1), - )); - let assign_max = self.cx.stmt_semi(assign_max); - - let stmts = vec![stmt, assign_min, assign_max]; - let block = self.cx.block(self.span, stmts); - let ty_unit = self.cx.ty(self.span, TyKind::Tup(Vec::new())); - (ty_unit, self.cx.expr_block(block)) - } - - AllocatorTy::ResultExcess => { - // We're creating: - // - // match #expr { - // Ok(ptr) => { - // *excess = ptr.1; - // ptr.0 - // } - // Err(e) => { - // ptr::write(err_ptr, e); - // 0 as *mut u8 - // } - // } - - let excess_ptr = ident(); - args.push(self.cx.arg(self.span, excess_ptr, self.ptr_usize())); - let excess_ptr = self.cx.expr_ident(self.span, excess_ptr); - - let err_ptr = ident(); - args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8())); - let err_ptr = self.cx.expr_ident(self.span, err_ptr); - let err_ptr = self.cx.expr_cast(self.span, - err_ptr, - self.alloc_err_ptr()); - - let name = ident(); - let ok_expr = { - let ptr = self.cx.expr_ident(self.span, name); - let write = self.cx.expr(self.span, ExprKind::Assign( - self.cx.expr_deref(self.span, excess_ptr), - self.cx.expr_tup_field_access(self.span, ptr.clone(), 1), - )); - let write = self.cx.stmt_semi(write); - let ret = self.cx.expr_tup_field_access(self.span, - ptr.clone(), - 0); - let ret = self.cx.stmt_expr(ret); - let block = self.cx.block(self.span, vec![write, ret]); - self.cx.expr_block(block) - }; - let pat = self.cx.pat_ident(self.span, name); - let ok = self.cx.path_ident(self.span, Ident::from_str("Ok")); - let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]); - let ok = self.cx.arm(self.span, vec![ok], ok_expr); - - let name = ident(); - let err_expr = { - let err = self.cx.expr_ident(self.span, name); - let write = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("__core"), - Ident::from_str("ptr"), - Ident::from_str("write"), - ]); - let write = self.cx.expr_path(write); - let write = self.cx.expr_call(self.span, write, - vec![err_ptr, err]); - let write = self.cx.stmt_semi(write); - let null = self.cx.expr_usize(self.span, 0); - let null = self.cx.expr_cast(self.span, null, self.ptr_u8()); - let null = self.cx.stmt_expr(null); - let block = self.cx.block(self.span, vec![write, null]); - self.cx.expr_block(block) - }; - let pat = self.cx.pat_ident(self.span, name); - let err = self.cx.path_ident(self.span, Ident::from_str("Err")); - let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]); - let err = self.cx.arm(self.span, vec![err], err_expr); - - let expr = self.cx.expr_match(self.span, expr, vec![ok, err]); - (self.ptr_u8(), expr) - } - AllocatorTy::ResultPtr => { // We're creating: // - // match #expr { - // Ok(ptr) => ptr, - // Err(e) => { - // ptr::write(err_ptr, e); - // 0 as *mut u8 - // } - // } - - let err_ptr = ident(); - args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8())); - let err_ptr = self.cx.expr_ident(self.span, err_ptr); - let err_ptr = self.cx.expr_cast(self.span, - err_ptr, - self.alloc_err_ptr()); - - let name = ident(); - let ok_expr = self.cx.expr_ident(self.span, name); - let pat = self.cx.pat_ident(self.span, name); - let ok = self.cx.path_ident(self.span, Ident::from_str("Ok")); - let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]); - let ok = self.cx.arm(self.span, vec![ok], ok_expr); + // #expr as *mut u8 - let name = ident(); - let err_expr = { - let err = self.cx.expr_ident(self.span, name); - let write = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("__core"), - Ident::from_str("ptr"), - Ident::from_str("write"), - ]); - let write = self.cx.expr_path(write); - let write = self.cx.expr_call(self.span, write, - vec![err_ptr, err]); - let write = self.cx.stmt_semi(write); - let null = self.cx.expr_usize(self.span, 0); - let null = self.cx.expr_cast(self.span, null, self.ptr_u8()); - let null = self.cx.stmt_expr(null); - let block = self.cx.block(self.span, vec![write, null]); - self.cx.expr_block(block) - }; - let pat = self.cx.pat_ident(self.span, name); - let err = self.cx.path_ident(self.span, Ident::from_str("Err")); - let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]); - let err = self.cx.arm(self.span, vec![err], err_expr); - - let expr = self.cx.expr_match(self.span, expr, vec![ok, err]); + let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8()); (self.ptr_u8(), expr) } - AllocatorTy::ResultUnit => { - // We're creating: - // - // #expr.is_ok() as u8 - - let cast = self.cx.expr_method_call( - self.span, - expr, - Ident::from_str("is_ok"), - Vec::new() - ); - let u8 = self.cx.path_ident(self.span, Ident::from_str("u8")); - let u8 = self.cx.ty_path(u8); - let cast = self.cx.expr_cast(self.span, cast, u8.clone()); - (u8, cast) - } - AllocatorTy::Bang => { (self.cx.ty(self.span, TyKind::Never), expr) } @@ -461,44 +257,32 @@ impl<'a> AllocFnFactory<'a> { (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr) } - AllocatorTy::AllocErr | AllocatorTy::Layout | - AllocatorTy::LayoutRef | + AllocatorTy::Usize | AllocatorTy::Ptr => { panic!("can't convert AllocatorTy to an output") } } } + fn usize(&self) -> P<Ty> { + let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); + self.cx.ty_path(usize) + } + fn ptr_u8(&self) -> P<Ty> { let u8 = self.cx.path_ident(self.span, Ident::from_str("u8")); let ty_u8 = self.cx.ty_path(u8); self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } - fn ptr_usize(&self) -> P<Ty> { - let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); - let ty_usize = self.cx.ty_path(usize); - self.cx.ty_ptr(self.span, ty_usize, Mutability::Mutable) - } - - fn layout_ptr(&self) -> P<Ty> { - let layout = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("Layout"), - ]); - let layout = self.cx.ty_path(layout); - self.cx.ty_ptr(self.span, layout, Mutability::Mutable) - } - - fn alloc_err_ptr(&self) -> P<Ty> { - let err = self.cx.path(self.span, vec![ - self.alloc, - Ident::from_str("heap"), - Ident::from_str("AllocErr"), + fn ptr_opaque(&self) -> P<Ty> { + let opaque = self.cx.path(self.span, vec![ + self.core, + Ident::from_str("alloc"), + Ident::from_str("Opaque"), ]); - let err = self.cx.ty_path(err); - self.cx.ty_ptr(self.span, err, Mutability::Mutable) + let ty_opaque = self.cx.ty_path(opaque); + self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable) } } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index e17fce5a2ec..706eab72d44 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] - #![feature(rustc_private)] extern crate rustc; @@ -27,7 +25,7 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ }, AllocatorMethod { name: "oom", - inputs: &[AllocatorTy::AllocErr], + inputs: &[], output: AllocatorTy::Bang, }, AllocatorMethod { @@ -36,13 +34,8 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ output: AllocatorTy::Unit, }, AllocatorMethod { - name: "usable_size", - inputs: &[AllocatorTy::LayoutRef], - output: AllocatorTy::UsizePair, - }, - AllocatorMethod { name: "realloc", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], + inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize], output: AllocatorTy::ResultPtr, }, AllocatorMethod { @@ -50,26 +43,6 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ inputs: &[AllocatorTy::Layout], output: AllocatorTy::ResultPtr, }, - AllocatorMethod { - name: "alloc_excess", - inputs: &[AllocatorTy::Layout], - output: AllocatorTy::ResultExcess, - }, - AllocatorMethod { - name: "realloc_excess", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], - output: AllocatorTy::ResultExcess, - }, - AllocatorMethod { - name: "grow_in_place", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], - output: AllocatorTy::ResultUnit, - }, - AllocatorMethod { - name: "shrink_in_place", - inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout], - output: AllocatorTy::ResultUnit, - }, ]; pub struct AllocatorMethod { @@ -79,14 +52,10 @@ pub struct AllocatorMethod { } pub enum AllocatorTy { - AllocErr, Bang, Layout, - LayoutRef, Ptr, - ResultExcess, ResultPtr, - ResultUnit, Unit, - UsizePair, + Usize, } diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 276f6cd09bf..0f051ea5981 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -43,7 +43,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![forbid(unsafe_code)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 9baee267709..027a9c45555 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -24,7 +24,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![feature(const_fn)] diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 5cfbe49f77f..e3adb51433b 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -107,8 +107,9 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { ty::TyAdt(adt_def, _) if adt_def.is_union() => match result { RestrictionResult::Safe => RestrictionResult::Safe, RestrictionResult::SafeIf(base_lp, mut base_vec) => { - for field in &adt_def.non_enum_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { + let field = + InteriorKind::InteriorField(mc::FieldIndex(i, field.name)); let field_ty = if field == interior { cmt.ty } else { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 93d6247eeae..6d832d4060a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -128,7 +128,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) // Note that `mir_validated` is a "stealable" result; the // thief, `optimized_mir()`, forces borrowck, so we know that // is not yet stolen. - tcx.mir_validated(owner_def_id).borrow(); + ty::maps::queries::mir_validated::ensure(tcx, owner_def_id); // option dance because you can't capture an uninitialized variable // by mut-ref. @@ -370,7 +370,7 @@ const DOWNCAST_PRINTED_OPERATOR: &'static str = " as "; // is tracked is irrelevant here.) #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum InteriorKind { - InteriorField(mc::FieldName), + InteriorField(mc::FieldIndex), InteriorElement, } @@ -1336,18 +1336,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { out.push(')'); } - LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => { + LpExtend(ref lp_base, _, LpInterior(_, InteriorField(mc::FieldIndex(_, info)))) => { self.append_autoderefd_loan_path_to_string(&lp_base, out); - match fname { - mc::NamedField(fname) => { - out.push('.'); - out.push_str(&fname.as_str()); - } - mc::PositionalField(idx) => { - out.push('.'); - out.push_str(&idx.to_string()); - } - } + out.push('.'); + out.push_str(&info.as_str()); } LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => { @@ -1422,8 +1414,7 @@ impl DataFlowOperator for LoanDataFlowOperator { impl<'tcx> fmt::Debug for InteriorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld), - InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i), + InteriorField(mc::FieldIndex(_, info)) => write!(f, "{}", info), InteriorElement => write!(f, "[]"), } } diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index a90dcd1072f..1f4050a5b36 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -21,7 +21,6 @@ use rustc::middle::dataflow::DataFlowOperator; use rustc::middle::dataflow::KillFrom; use rustc::middle::expr_use_visitor as euv; use rustc::middle::expr_use_visitor::MutateMode; -use rustc::middle::mem_categorization as mc; use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; @@ -343,8 +342,8 @@ impl<'a, 'tcx> MoveData<'tcx> { if let (&ty::TyAdt(adt_def, _), LpInterior(opt_variant_id, interior)) = (&base_lp.ty.sty, lp_elem) { if adt_def.is_union() { - for field in &adt_def.non_enum_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { + let field = InteriorKind::InteriorField(mc::FieldIndex(i, field.name)); if field != interior { let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field)); @@ -395,8 +394,8 @@ impl<'a, 'tcx> MoveData<'tcx> { if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { if adt_def.is_union() { - for field in &adt_def.non_enum_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { + let field = InteriorKind::InteriorField(mc::FieldIndex(i, field.name)); let field_ty = if field == interior { lp.ty } else { diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 6fe2ac2b0ca..52a357e1a1d 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![allow(non_camel_case_types)] diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index c4c5886d465..499c330be1d 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] extern crate rustc_apfloat; diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1e1628936d5..ba1d73dc268 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -19,7 +19,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(collections_range)] #![feature(nonzero)] diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 184ef136976..3b7d6efbdae 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -29,10 +29,15 @@ //! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync //! depending on the value of cfg!(parallel_queries). +use std::collections::HashMap; +use std::hash::{Hash, BuildHasher}; use std::cmp::Ordering; +use std::marker::PhantomData; use std::fmt::Debug; use std::fmt::Formatter; use std::fmt; +use std; +use std::ops::{Deref, DerefMut}; use owning_ref::{Erased, OwningRef}; cfg_if! { @@ -161,6 +166,8 @@ cfg_if! { use parking_lot::Mutex as InnerLock; use parking_lot::RwLock as InnerRwLock; + use std::thread; + pub type MetadataRef = OwningRef<Box<Erased + Send + Sync>, [u8]>; /// This makes locks panic if they are already held. @@ -223,6 +230,146 @@ pub fn assert_sync<T: ?Sized + Sync>() {} pub fn assert_send_val<T: ?Sized + Send>(_t: &T) {} pub fn assert_send_sync_val<T: ?Sized + Sync + Send>(_t: &T) {} +pub trait HashMapExt<K, V> { + /// Same as HashMap::insert, but it may panic if there's already an + /// entry for `key` with a value not equal to `value` + fn insert_same(&mut self, key: K, value: V); +} + +impl<K: Eq + Hash, V: Eq, S: BuildHasher> HashMapExt<K, V> for HashMap<K, V, S> { + fn insert_same(&mut self, key: K, value: V) { + self.entry(key).and_modify(|old| assert!(*old == value)).or_insert(value); + } +} + +/// A type whose inner value can be written once and then will stay read-only +// This contains a PhantomData<T> since this type conceptually owns a T outside the Mutex once +// initialized. This ensures that Once<T> is Sync only if T is. If we did not have PhantomData<T> +// we could send a &Once<Cell<bool>> to multiple threads and call `get` on it to get access +// to &Cell<bool> on those threads. +pub struct Once<T>(Lock<Option<T>>, PhantomData<T>); + +impl<T> Once<T> { + /// Creates an Once value which is uninitialized + #[inline(always)] + pub fn new() -> Self { + Once(Lock::new(None), PhantomData) + } + + /// Consumes the value and returns Some(T) if it was initialized + #[inline(always)] + pub fn into_inner(self) -> Option<T> { + self.0.into_inner() + } + + /// Tries to initialize the inner value to `value`. + /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it + /// otherwise if the inner value was already set it returns `value` back to the caller + #[inline] + pub fn try_set(&self, value: T) -> Option<T> { + let mut lock = self.0.lock(); + if lock.is_some() { + return Some(value); + } + *lock = Some(value); + None + } + + /// Tries to initialize the inner value to `value`. + /// Returns `None` if the inner value was uninitialized and `value` was consumed setting it + /// otherwise if the inner value was already set it asserts that `value` is equal to the inner + /// value and then returns `value` back to the caller + #[inline] + pub fn try_set_same(&self, value: T) -> Option<T> where T: Eq { + let mut lock = self.0.lock(); + if let Some(ref inner) = *lock { + assert!(*inner == value); + return Some(value); + } + *lock = Some(value); + None + } + + /// Tries to initialize the inner value to `value` and panics if it was already initialized + #[inline] + pub fn set(&self, value: T) { + assert!(self.try_set(value).is_none()); + } + + /// Tries to initialize the inner value by calling the closure while ensuring that no-one else + /// can access the value in the mean time by holding a lock for the duration of the closure. + /// If the value was already initialized the closure is not called and `false` is returned, + /// otherwise if the value from the closure initializes the inner value, `true` is returned + #[inline] + pub fn init_locking<F: FnOnce() -> T>(&self, f: F) -> bool { + let mut lock = self.0.lock(); + if lock.is_some() { + return false; + } + *lock = Some(f()); + true + } + + /// Tries to initialize the inner value by calling the closure without ensuring that no-one + /// else can access it. This mean when this is called from multiple threads, multiple + /// closures may concurrently be computing a value which the inner value should take. + /// Only one of these closures are used to actually initialize the value. + /// If some other closure already set the value, + /// we return the value our closure computed wrapped in a `Option`. + /// If our closure set the value, `None` is returned. + /// If the value is already initialized, the closure is not called and `None` is returned. + #[inline] + pub fn init_nonlocking<F: FnOnce() -> T>(&self, f: F) -> Option<T> { + if self.0.lock().is_some() { + None + } else { + self.try_set(f()) + } + } + + /// Tries to initialize the inner value by calling the closure without ensuring that no-one + /// else can access it. This mean when this is called from multiple threads, multiple + /// closures may concurrently be computing a value which the inner value should take. + /// Only one of these closures are used to actually initialize the value. + /// If some other closure already set the value, we assert that it our closure computed + /// a value equal to the value aready set and then + /// we return the value our closure computed wrapped in a `Option`. + /// If our closure set the value, `None` is returned. + /// If the value is already initialized, the closure is not called and `None` is returned. + #[inline] + pub fn init_nonlocking_same<F: FnOnce() -> T>(&self, f: F) -> Option<T> where T: Eq { + if self.0.lock().is_some() { + None + } else { + self.try_set_same(f()) + } + } + + /// Tries to get a reference to the inner value, returns `None` if it is not yet initialized + #[inline(always)] + pub fn try_get(&self) -> Option<&T> { + let lock = &*self.0.lock(); + if let Some(ref inner) = *lock { + // This is safe since we won't mutate the inner value + unsafe { Some(&*(inner as *const T)) } + } else { + None + } + } + + /// Gets reference to the inner value, panics if it is not yet initialized + #[inline(always)] + pub fn get(&self) -> &T { + self.try_get().expect("value was not set") + } + + /// Gets reference to the inner value, panics if it is not yet initialized + #[inline(always)] + pub fn borrow(&self) -> &T { + self.get() + } +} + impl<T: Copy + Debug> Debug for LockCell<T> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.debug_struct("LockCell") @@ -390,6 +537,18 @@ impl<T> RwLock<T> { #[cfg(not(parallel_queries))] #[inline(always)] + pub fn try_write(&self) -> Result<WriteGuard<T>, ()> { + self.0.try_borrow_mut().map_err(|_| ()) + } + + #[cfg(parallel_queries)] + #[inline(always)] + pub fn try_write(&self) -> Result<WriteGuard<T>, ()> { + self.0.try_write().ok_or(()) + } + + #[cfg(not(parallel_queries))] + #[inline(always)] pub fn write(&self) -> WriteGuard<T> { self.0.borrow_mut() } @@ -427,3 +586,54 @@ impl<T: Clone> Clone for RwLock<T> { RwLock::new(self.borrow().clone()) } } + +/// A type which only allows its inner value to be used in one thread. +/// It will panic if it is used on multiple threads. +#[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)] +pub struct OneThread<T> { + #[cfg(parallel_queries)] + thread: thread::ThreadId, + inner: T, +} + +unsafe impl<T> std::marker::Sync for OneThread<T> {} +unsafe impl<T> std::marker::Send for OneThread<T> {} + +impl<T> OneThread<T> { + #[inline(always)] + fn check(&self) { + #[cfg(parallel_queries)] + assert_eq!(thread::current().id(), self.thread); + } + + #[inline(always)] + pub fn new(inner: T) -> Self { + OneThread { + #[cfg(parallel_queries)] + thread: thread::current().id(), + inner, + } + } + + #[inline(always)] + pub fn into_inner(value: Self) -> T { + value.check(); + value.inner + } +} + +impl<T> Deref for OneThread<T> { + type Target = T; + + fn deref(&self) -> &T { + self.check(); + &self.inner + } +} + +impl<T> DerefMut for OneThread<T> { + fn deref_mut(&mut self) -> &mut T { + self.check(); + &mut self.inner + } +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c6ebc992680..4071b804def 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -652,10 +652,11 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, // these need to be set "early" so that expansion sees `quote` if enabled. sess.init_features(features); - *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs); + let crate_types = collect_crate_types(sess, &krate.attrs); + sess.crate_types.set(crate_types); let disambiguator = compute_crate_disambiguator(sess); - *sess.crate_disambiguator.borrow_mut() = Some(disambiguator); + sess.crate_disambiguator.set(disambiguator); rustc_incremental::prepare_session_directory( sess, &crate_name, @@ -783,7 +784,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let features = sess.features_untracked(); let cfg = syntax::ext::expand::ExpansionConfig { features: Some(&features), - recursion_limit: sess.recursion_limit.get(), + recursion_limit: *sess.recursion_limit.get(), trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6f88b0aecb6..3dec84d174d 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -17,12 +17,12 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![cfg_attr(unix, feature(libc))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] +#![feature(slice_sort_by_cached_key)] #![feature(set_stdio)] #![feature(rustc_stack_internals)] @@ -83,7 +83,6 @@ use rustc_trans_utils::trans_crate::TransCrate; use serialize::json::ToJson; use std::any::Any; -use std::cmp::Ordering::Equal; use std::cmp::max; use std::default::Default; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; @@ -1177,13 +1176,8 @@ Available lint options: fn sort_lints(sess: &Session, lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> { let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect(); - lints.sort_by(|x: &&Lint, y: &&Lint| { - match x.default_level(sess).cmp(&y.default_level(sess)) { - // The sort doesn't case-fold but it's doubtful we care. - Equal => x.name.cmp(y.name), - r => r, - } - }); + // The sort doesn't case-fold but it's doubtful we care. + lints.sort_by_cached_key(|x: &&Lint| (x.default_level(sess), x.name)); lints } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 9efd8844977..971855ee2d0 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -303,7 +303,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(index, Symbol::intern(&name)) + self.infcx.tcx.mk_param(index, Symbol::intern(&name).as_str()) } pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> { diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index a723e455222..8d5f9ac93f0 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(custom_attribute)] #![allow(unused_attributes)] diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 9e72ede309d..a5e07bcec24 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -13,7 +13,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(fs_read_write)] #![feature(specialization)] diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index ad3760eed80..463ec4796e8 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -368,6 +368,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { match it.node { hir::ItemStatic(..) => { + if attr::find_by_name(&it.attrs, "no_mangle").is_some() { + return; + } NonUpperCaseGlobals::check_upper_case(cx, "static variable", it.name, it.span); } hir::ItemConst(..) => { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2cc6708bc03..6f2c51b0f18 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -166,13 +166,24 @@ impl LintPass for NonShorthandFieldPatterns { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns { fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { - if let PatKind::Struct(_, ref field_pats, _) = pat.node { + if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.node { + let variant = cx.tables.pat_ty(pat).ty_adt_def() + .expect("struct pattern type is not an ADT") + .variant_of_def(cx.tables.qpath_def(qpath, pat.hir_id)); for fieldpat in field_pats { if fieldpat.node.is_shorthand { continue; } + if fieldpat.span.ctxt().outer().expn_info().is_some() { + // Don't lint if this is a macro expansion: macro authors + // shouldn't have to worry about this kind of style issue + // (Issue #49588) + continue; + } if let PatKind::Binding(_, _, name, None) = fieldpat.node.pat.node { - if name.node == fieldpat.node.name { + let binding_ident = ast::Ident::new(name.node, name.span); + if cx.tcx.find_field_index(binding_ident, &variant) == + Some(cx.tcx.field_index(fieldpat.node.id, cx.tables)) { let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, &format!("the `{}:` in this pattern is redundant", diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c915181213d..16e8600f2d8 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -22,7 +22,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![cfg_attr(test, feature(test))] #![feature(box_patterns)] diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 16bee5b987e..bf8a087ab55 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -16,7 +16,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_syntax)] #![feature(concat_idents)] diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 86f495c5fac..34d9f47bac3 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -614,6 +614,7 @@ impl<'a> CrateLoader<'a> { }); if !any_non_rlib { info!("panic runtime injection skipped, only generating rlib"); + self.sess.injected_panic_runtime.set(None); return } @@ -646,6 +647,7 @@ impl<'a> CrateLoader<'a> { // we just don't need one at all, then we're done here and there's // nothing else to do. if !needs_panic_runtime || runtime_found { + self.sess.injected_panic_runtime.set(None); return } @@ -812,9 +814,7 @@ impl<'a> CrateLoader<'a> { fn inject_allocator_crate(&mut self, krate: &ast::Crate) { let has_global_allocator = has_global_allocator(krate); - if has_global_allocator { - self.sess.has_global_allocator.set(true); - } + self.sess.has_global_allocator.set(has_global_allocator); // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically @@ -825,6 +825,8 @@ impl<'a> CrateLoader<'a> { needs_allocator = needs_allocator || data.needs_allocator(self.sess); }); if !needs_allocator { + self.sess.injected_allocator.set(None); + self.sess.allocator_kind.set(None); return } @@ -844,6 +846,8 @@ impl<'a> CrateLoader<'a> { } } if !need_lib_alloc && !need_exe_alloc { + self.sess.injected_allocator.set(None); + self.sess.allocator_kind.set(None); return } @@ -881,6 +885,7 @@ impl<'a> CrateLoader<'a> { }); if global_allocator.is_some() { self.sess.allocator_kind.set(Some(AllocatorKind::Global)); + self.sess.injected_allocator.set(None); return } @@ -924,6 +929,9 @@ impl<'a> CrateLoader<'a> { }; let allocation_crate_data = exe_allocation_crate_data.or_else(|| { + // No allocator was injected + self.sess.injected_allocator.set(None); + if attr::contains_name(&krate.attrs, "default_lib_allocator") { // Prefer self as the allocator if there's a collision return None; diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 51088563c7b..2c995d2f5cd 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -163,7 +163,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, fn_arg_names => { cdata.get_fn_arg_names(def_id.index) } impl_parent => { cdata.get_parent_impl(def_id.index) } trait_of_item => { cdata.get_trait_of_item(def_id.index) } - item_body_nested_bodies => { cdata.item_body_nested_bodies(def_id.index) } + item_body_nested_bodies => { cdata.item_body_nested_bodies(tcx, def_id.index) } const_is_rvalue_promotable_to_static => { cdata.const_is_rvalue_promotable_to_static(def_id.index) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 42e208ded49..3ea4ddc2522 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -818,11 +818,14 @@ impl<'a, 'tcx> CrateMetadata { tcx.alloc_tables(ast.tables.decode((self, tcx))) } - pub fn item_body_nested_bodies(&self, id: DefIndex) -> ExternBodyNestedBodies { + pub fn item_body_nested_bodies(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: DefIndex) + -> ExternBodyNestedBodies { if let Some(ref ast) = self.entry(id).ast { - let ast = ast.decode(self); + let mut ast = ast.decode(self); let nested_bodies: BTreeMap<_, _> = ast.nested_bodies - .decode(self) + .decode((self, tcx.sess)) .map(|body| (body.id(), body)) .collect(); ExternBodyNestedBodies { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 1b208a512e2..22b440eea60 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -459,7 +459,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro); let has_default_lib_allocator = attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator"); - let has_global_allocator = tcx.sess.has_global_allocator.get(); + let has_global_allocator = *tcx.sess.has_global_allocator.get(); let root = self.lazy(&CrateRoot { name: tcx.crate_name(LOCAL_CRATE), extra_filename: tcx.sess.opts.cg.extra_filename.clone(), @@ -1414,7 +1414,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let mut all_impls: Vec<_> = visitor.impls.into_iter().collect(); // Bring everything into deterministic order for hashing - all_impls.sort_unstable_by_key(|&(trait_def_id, _)| { + all_impls.sort_by_cached_key(|&(trait_def_id, _)| { tcx.def_path_hash(trait_def_id) }); @@ -1422,7 +1422,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { .into_iter() .map(|(trait_def_id, mut impls)| { // Bring everything into deterministic order for hashing - impls.sort_unstable_by_key(|&def_index| { + impls.sort_by_cached_key(|&def_index| { tcx.hir.definitions().def_path_hash(def_index) }); diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index e89b5a7fc1b..cbbc9d74228 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(fs_read_write)] @@ -21,6 +20,7 @@ #![feature(macro_lifetime_matcher)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] +#![feature(slice_sort_by_cached_key)] #![feature(specialization)] #![feature(rustc_private)] diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index fe7aedb4127..62acdf76546 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -42,6 +42,7 @@ use dataflow::indexes::BorrowIndex; use dataflow::move_paths::{IllegalMoveOriginKind, MoveError}; use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex}; use util::borrowck_errors::{BorrowckErrors, Origin}; +use util::collect_writes::FindAssignments; use std::iter; @@ -1550,6 +1551,36 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } + fn specialized_description(&self, place:&Place<'tcx>) -> Option<String>{ + if let Some(_name) = self.describe_place(place) { + Some(format!("data in a `&` reference")) + } else { + None + } + } + + fn get_default_err_msg(&self, place:&Place<'tcx>) -> String{ + match self.describe_place(place) { + Some(name) => format!("immutable item `{}`", name), + None => "immutable item".to_owned(), + } + } + + fn get_secondary_err_msg(&self, place:&Place<'tcx>) -> String{ + match self.specialized_description(place) { + Some(_) => format!("data in a `&` reference"), + None => self.get_default_err_msg(place) + } + } + + fn get_primary_err_msg(&self, place:&Place<'tcx>) -> String{ + if let Some(name) = self.describe_place(place) { + format!("`{}` is a `&` reference, so the data it refers to cannot be written", name) + } else { + format!("cannot assign through `&`-reference") + } + } + /// Check the permissions for the given place and read or write kind /// /// Returns true if an error is reported, false otherwise. @@ -1576,43 +1607,70 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.is_mutable(place, is_local_mutation_allowed) { error_reported = true; - - let item_msg = match self.describe_place(place) { - Some(name) => format!("immutable item `{}`", name), - None => "immutable item".to_owned(), - }; - + let item_msg = self.get_default_err_msg(place); let mut err = self.tcx .cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir); err.span_label(span, "cannot borrow as mutable"); if place != place_err { if let Some(name) = self.describe_place(place_err) { - err.note(&format!("Value not mutable causing this error: `{}`", name)); + err.note(&format!("the value which is causing this path not to be mutable \ + is...: `{}`", name)); } } err.emit(); }, Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { + if let Err(place_err) = self.is_mutable(place, is_local_mutation_allowed) { error_reported = true; + let mut err_info = None; + match *place_err { + + Place::Projection(box Projection { + ref base, elem:ProjectionElem::Deref}) => { + match *base { + Place::Local(local) => { + let locations = self.mir.find_assignments(local); + if locations.len() > 0 { + let item_msg = if error_reported { + self.get_secondary_err_msg(base) + } else { + self.get_default_err_msg(place) + }; + err_info = Some(( + self.mir.source_info(locations[0]).span, + "consider changing this to be a \ + mutable reference: `&mut`", item_msg, + self.get_primary_err_msg(base))); + } + }, + _ => {}, + } + }, + _ => {}, + } - let item_msg = match self.describe_place(place) { - Some(name) => format!("immutable item `{}`", name), - None => "immutable item".to_owned(), - }; - - let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); - err.span_label(span, "cannot mutate"); - - if place != place_err { - if let Some(name) = self.describe_place(place_err) { - err.note(&format!("Value not mutable causing this error: `{}`", name)); + if let Some((err_help_span, err_help_stmt, item_msg, sec_span)) = err_info { + let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); + err.span_suggestion(err_help_span, err_help_stmt, format!("")); + if place != place_err { + err.span_label(span, sec_span); } + err.emit() + } else { + let item_msg_ = self.get_default_err_msg(place); + let mut err = self.tcx.cannot_assign(span, &item_msg_, Origin::Mir); + err.span_label(span, "cannot mutate"); + if place != place_err { + if let Some(name) = self.describe_place(place_err) { + err.note(&format!("the value which is causing this path not to be \ + mutable is...: `{}`", name)); + } + } + err.emit(); } - - err.emit(); } } Reservation(WriteKind::Move) @@ -1631,9 +1689,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); } } - Activation(..) => {} // permission checks are done at Reservation point. - Read(ReadKind::Borrow(BorrowKind::Unique)) | Read(ReadKind::Borrow(BorrowKind::Mut { .. })) | Read(ReadKind::Borrow(BorrowKind::Shared)) @@ -2255,3 +2311,4 @@ impl ContextKind { } } } + diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index dbfb8a6d06e..942e4fb56ca 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -202,11 +202,11 @@ fn dump_mir_results<'a, 'gcx, 'tcx>( }); // Also dump the inference graph constraints as a graphviz file. - let _: io::Result<()> = do catch { + let _: io::Result<()> = do_catch! {{ let mut file = pretty::create_dump_file(infcx.tcx, "regioncx.dot", None, "nll", &0, source)?; - regioncx.dump_graphviz(&mut file) - }; + regioncx.dump_graphviz(&mut file)?; + }}; } fn dump_annotation<'a, 'gcx, 'tcx>( diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 5b373908480..c0d28280946 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -16,7 +16,7 @@ use hair::cx::to_ref::ToRef; use rustc::hir::def::{Def, CtorKind}; use rustc::middle::const_val::ConstVal; use rustc::mir::interpret::{GlobalId, Value, PrimVal}; -use rustc::ty::{self, AdtKind, VariantDef, Ty}; +use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; @@ -420,12 +420,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty::TyAdt(adt, substs) => { match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { - let field_refs = field_refs(&adt.variants[0], fields); ExprKind::Adt { adt_def: adt, variant_index: 0, substs, - fields: field_refs, + fields: field_refs(cx, fields), base: base.as_ref().map(|base| { FruInfo { base: base.to_ref(), @@ -446,12 +445,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, assert!(base.is_none()); let index = adt.variant_index_with_id(variant_id); - let field_refs = field_refs(&adt.variants[index], fields); ExprKind::Adt { adt_def: adt, variant_index: index, substs, - fields: field_refs, + fields: field_refs(cx, fields), base: None, } } @@ -581,24 +579,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, body: block::to_expr_ref(cx, body), } } - hir::ExprField(ref source, name) => { - let index = match cx.tables().expr_ty_adjusted(source).sty { - ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), - ref ty => span_bug!(expr.span, "field of non-ADT: {:?}", ty), - }; - let index = - index.unwrap_or_else(|| { - span_bug!(expr.span, "no index found for field `{}`", name.node) - }); - ExprKind::Field { - lhs: source.to_ref(), - name: Field::new(index), - } - } - hir::ExprTupField(ref source, index) => { + hir::ExprField(ref source, ..) => { ExprKind::Field { lhs: source.to_ref(), - name: Field::new(index.node as usize), + name: Field::new(cx.tcx.field_index(expr.id, cx.tables)), } } hir::ExprCast(ref source, _) => { @@ -999,13 +983,13 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef. -fn field_refs<'tcx>(variant: &'tcx VariantDef, - fields: &'tcx [hir::Field]) - -> Vec<FieldExprRef<'tcx>> { +fn field_refs<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, + fields: &'tcx [hir::Field]) + -> Vec<FieldExprRef<'tcx>> { fields.iter() .map(|field| { FieldExprRef { - name: Field::new(variant.index_of_field_named(field.name.node).unwrap()), + name: Field::new(cx.tcx.field_index(field.id, cx.tables)), expr: field.expr.to_ref(), } }) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index c3f41e8ac48..8d2b73d6ba0 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -528,28 +528,12 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatKind::Struct(ref qpath, ref fields, _) => { let def = self.tables.qpath_def(qpath, pat.hir_id); - let adt_def = match ty.sty { - ty::TyAdt(adt_def, _) => adt_def, - _ => { - span_bug!( - pat.span, - "struct pattern not applied to an ADT"); - } - }; - let variant_def = adt_def.variant_of_def(def); - let subpatterns = fields.iter() .map(|field| { - let index = variant_def.index_of_field_named(field.node.name); - let index = index.unwrap_or_else(|| { - span_bug!( - pat.span, - "no field with name {:?}", - field.node.name); - }); FieldPattern { - field: Field::new(index), + field: Field::new(self.tcx.field_index(field.node.id, + self.tables)), pattern: self.lower_pattern(&field.node.pat), } }) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3220d4d96b3..58ea8d48e97 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -194,8 +194,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M param_env, memory: Memory::new(tcx, memory_data), stack: Vec::new(), - stack_limit: tcx.sess.const_eval_stack_frame_limit.get(), - steps_remaining: tcx.sess.const_eval_step_limit.get(), + stack_limit: tcx.sess.const_eval_stack_frame_limit, + steps_remaining: tcx.sess.const_eval_step_limit, } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 8762e7550cd..a701fe31442 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,9 +14,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ -#![deny(warnings)] - #![feature(slice_patterns)] +#![feature(slice_sort_by_cached_key)] #![feature(from_ref)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -32,6 +31,8 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(rustc_diagnostic_macros)] #![feature(nonzero)] #![feature(inclusive_range_fields)] +#![feature(crate_visibility_modifier)] +#![cfg_attr(stage0, feature(try_trait))] extern crate arena; #[macro_use] @@ -53,6 +54,16 @@ extern crate log_settings; extern crate rustc_apfloat; extern crate byteorder; +#[cfg(stage0)] +macro_rules! do_catch { + ($t:expr) => { (|| ::std::ops::Try::from_ok($t) )() } +} + +#[cfg(not(stage0))] +macro_rules! do_catch { + ($t:expr) => { do catch { $t } } +} + mod diagnostics; mod borrow_check; diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 209f6dbfa48..83ef28e4f15 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -325,7 +325,7 @@ fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut roots = Vec::new(); { - let entry_fn = tcx.sess.entry_fn.borrow().map(|(node_id, _)| { + let entry_fn = tcx.sess.entry_fn.borrow().map(|(node_id, _, _)| { tcx.hir.local_def_id(node_id) }); @@ -457,7 +457,7 @@ fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Code that needs to instantiate the same function recursively // more than the recursion limit is assumed to be causing an // infinite expansion. - if recursion_depth > tcx.sess.recursion_limit.get() { + if recursion_depth > *tcx.sess.recursion_limit.get() { let error = format!("reached the recursion limit while instantiating `{}`", instance); if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { @@ -484,7 +484,7 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // which means that rustc basically hangs. // // Bail out in these cases to avoid that bad user experience. - let type_length_limit = tcx.sess.type_length_limit.get(); + let type_length_limit = *tcx.sess.type_length_limit.get(); if type_length > type_length_limit { // The instance name is already known to be too long for rustc. Use // `{:.64}` to avoid blasting the user's terminal with thousands of @@ -1038,7 +1038,7 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> { /// the return type of `main`. This is not needed when /// the user writes their own `start` manually. fn push_extra_entry_roots(&mut self) { - if self.tcx.sess.entry_type.get() != Some(config::EntryMain) { + if self.tcx.sess.entry_fn.get().map(|e| e.2) != Some(config::EntryMain) { return } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index c2f4359c008..181751f1777 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -92,7 +92,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { match *self.as_mono_item() { MonoItem::Fn(ref instance) => { let entry_def_id = - tcx.sess.entry_fn.borrow().map(|(id, _)| tcx.hir.local_def_id(id)); + tcx.sess.entry_fn.borrow().map(|(id, _, _)| tcx.hir.local_def_id(id)); // If this function isn't inlined or otherwise has explicit // linkage, then we'll be creating a globally shared version. if self.explicit_linkage(tcx).is_some() || diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index da4cb4ec789..f29f86af4ab 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -112,11 +112,11 @@ use rustc::ty::{self, TyCtxt, InstanceDef}; use rustc::ty::item_path::characteristic_def_id_of_type; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use std::collections::hash_map::Entry; +use std::cmp; use syntax::ast::NodeId; use syntax::symbol::{Symbol, InternedString}; use rustc::mir::mono::MonoItem; use monomorphize::item::{MonoItemExt, InstantiationMode}; -use core::usize; pub use rustc::mir::mono::CodegenUnit; @@ -189,11 +189,9 @@ pub trait CodegenUnitExt<'tcx> { }, item.symbol_name(tcx)) } - let items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect(); - let mut items : Vec<_> = items.iter() - .map(|il| (il, item_sort_key(tcx, il.0))).collect(); - items.sort_by(|&(_, ref key1), &(_, ref key2)| key1.cmp(key2)); - items.into_iter().map(|(&item_linkage, _)| item_linkage).collect() + let mut items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect(); + items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i)); + items } } @@ -509,7 +507,7 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< // Merge the two smallest codegen units until the target size is reached. while codegen_units.len() > target_cgu_count { // Sort small cgus to the back - codegen_units.sort_by_key(|cgu| usize::MAX - cgu.size_estimate()); + codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); let mut smallest = codegen_units.pop().unwrap(); let second_smallest = codegen_units.last_mut().unwrap(); diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 5e15348de5e..d6b3e674f8f 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -284,7 +284,8 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self.cancel_if_wrong_origin(err, o) } - fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> + fn cannot_assign(self, span: Span, desc: &str, o: Origin) + -> DiagnosticBuilder<'cx> { let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", diff --git a/src/librustc_mir/util/collect_writes.rs b/src/librustc_mir/util/collect_writes.rs new file mode 100644 index 00000000000..f04f9233447 --- /dev/null +++ b/src/librustc_mir/util/collect_writes.rs @@ -0,0 +1,67 @@ +// 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. + +use rustc::mir::{Local, Location}; +use rustc::mir::Mir; +use rustc::mir::visit::PlaceContext; +use rustc::mir::visit::Visitor; + +crate trait FindAssignments { + // Finds all statements that assign directly to local (i.e., X = ...) + // and returns their locations. + fn find_assignments(&self, local: Local) -> Vec<Location>; +} + +impl<'tcx> FindAssignments for Mir<'tcx>{ + fn find_assignments(&self, local: Local) -> Vec<Location>{ + let mut visitor = FindLocalAssignmentVisitor{ needle: local, locations: vec![]}; + visitor.visit_mir(self); + visitor.locations + } +} + +// The Visitor walks the MIR to return the assignment statements corresponding +// to a Local. +struct FindLocalAssignmentVisitor { + needle: Local, + locations: Vec<Location>, +} + +impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { + fn visit_local(&mut self, + local: &Local, + place_context: PlaceContext<'tcx>, + location: Location) { + if self.needle != *local { + return; + } + + match place_context { + PlaceContext::Store | PlaceContext::Call => { + self.locations.push(location); + } + PlaceContext::AsmOutput | + PlaceContext::Drop | + PlaceContext::Inspect | + PlaceContext::Borrow { .. } | + PlaceContext::Projection(..) | + PlaceContext::Copy | + PlaceContext::Move | + PlaceContext::StorageLive | + PlaceContext::StorageDead | + PlaceContext::Validate => { + // TO-DO + // self.super_local(local) + } + } + } + // TO-DO + // fn super_local() +} diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs index eebe5a86018..19cd3766886 100644 --- a/src/librustc_mir/util/mod.rs +++ b/src/librustc_mir/util/mod.rs @@ -17,6 +17,7 @@ mod alignment; mod graphviz; pub(crate) mod pretty; pub mod liveness; +pub mod collect_writes; pub use self::alignment::is_disaligned; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 4509cace794..a891e372ad8 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -137,7 +137,7 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( ) where F: FnMut(PassWhere, &mut dyn Write) -> io::Result<()>, { - let _: io::Result<()> = do catch { + let _: io::Result<()> = do_catch! {{ let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, source)?; writeln!(file, "// MIR for `{}`", node_path)?; writeln!(file, "// source = {:?}", source)?; @@ -150,16 +150,14 @@ fn dump_matched_mir_node<'a, 'gcx, 'tcx, F>( extra_data(PassWhere::BeforeCFG, &mut file)?; write_mir_fn(tcx, source, mir, &mut extra_data, &mut file)?; extra_data(PassWhere::AfterCFG, &mut file)?; - Ok(()) - }; + }}; if tcx.sess.opts.debugging_opts.dump_mir_graphviz { - let _: io::Result<()> = do catch { + let _: io::Result<()> = do_catch! {{ let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?; write_mir_fn_graphviz(tcx, source.def_id, mir, &mut file)?; - Ok(()) - }; + }}; } } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index 1f6cc1f71fc..e65c9de8df1 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 76cbc670969..c5d2f0041a0 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -407,7 +407,6 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node hir::ExprBlock(_) | hir::ExprIndex(..) | hir::ExprField(..) | - hir::ExprTupField(..) | hir::ExprArray(_) | hir::ExprType(..) | hir::ExprTup(..) => {} diff --git a/src/librustc_platform_intrinsics/lib.rs b/src/librustc_platform_intrinsics/lib.rs index 4cc65ee28e8..b57debdd994 100644 --- a/src/librustc_platform_intrinsics/lib.rs +++ b/src/librustc_platform_intrinsics/lib.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(warnings)] #![allow(bad_style)] pub struct Intrinsic { diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index c0f830f1fbe..622d8e51a6c 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -63,7 +63,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] #![feature(staged_api)] diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d951a7f1cc1..ee08e622390 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] @@ -569,8 +568,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { // If the expression uses FRU we need to make sure all the unmentioned fields // are checked for privacy (RFC 736). Rather than computing the set of // unmentioned fields, just check them all. - for variant_field in &variant.fields { - let field = fields.iter().find(|f| f.name.node == variant_field.name); + for (vf_index, variant_field) in variant.fields.iter().enumerate() { + let field = fields.iter().find(|f| { + self.tcx.field_index(f.id, self.tables) == vf_index + }); let (use_ctxt, span) = match field { Some(field) => (field.name.node.to_ident().span, field.span), None => (base.span, base.span), @@ -580,8 +581,8 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { } else { for field in fields { let use_ctxt = field.name.node.to_ident().span; - let field_def = variant.field_named(field.name.node); - self.check_field(use_ctxt, field.span, adt, field_def); + let index = self.tcx.field_index(field.id, self.tables); + self.check_field(use_ctxt, field.span, adt, &variant.fields[index]); } } } @@ -599,8 +600,8 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { let variant = adt.variant_of_def(def); for field in fields { let use_ctxt = field.node.name.to_ident().span; - let field_def = variant.field_named(field.node.name); - self.check_field(use_ctxt, field.span, adt, field_def); + let index = self.tcx.field_index(field.node.id, self.tables); + self.check_field(use_ctxt, field.span, adt, &variant.fields[index]); } } _ => {} diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2bf17cd1317..d32d853c18b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -11,9 +11,9 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(rustc_diagnostic_macros)] +#![feature(slice_sort_by_cached_key)] #[macro_use] extern crate log; @@ -1150,13 +1150,9 @@ impl<'a> ModuleData<'a> { fn for_each_child_stable<F: FnMut(Ident, Namespace, &'a NameBinding<'a>)>(&self, mut f: F) { let resolutions = self.resolutions.borrow(); - let mut resolutions = resolutions.iter().map(|(&(ident, ns), &resolution)| { - // Pre-compute keys for sorting - (ident.name.as_str(), ns, ident, resolution) - }) - .collect::<Vec<_>>(); - resolutions.sort_unstable_by_key(|&(str, ns, ..)| (str, ns)); - for &(_, ns, ident, resolution) in resolutions.iter() { + let mut resolutions = resolutions.iter().collect::<Vec<_>>(); + resolutions.sort_by_cached_key(|&(&(ident, ns), _)| (ident.name.as_str(), ns)); + for &(&(ident, ns), &resolution) in resolutions.iter() { resolution.borrow().binding.map(|binding| f(ident, ns, binding)); } } @@ -3341,7 +3337,9 @@ impl<'a> Resolver<'a> { let is_mod = |def| match def { Def::Mod(..) => true, _ => false }; let mut candidates = self.lookup_import_candidates(name, TypeNS, is_mod); - candidates.sort_by_key(|c| (c.path.segments.len(), c.path.to_string())); + candidates.sort_by_cached_key(|c| { + (c.path.segments.len(), c.path.to_string()) + }); if let Some(candidate) = candidates.get(0) { format!("Did you mean `{}`?", candidate.path) } else { @@ -3579,7 +3577,7 @@ impl<'a> Resolver<'a> { let name = path[path.len() - 1].name; // Make sure error reporting is deterministic. - names.sort_by_key(|name| name.as_str()); + names.sort_by_cached_key(|name| name.as_str()); match find_best_match_for_name(names.iter(), &name.as_str(), None) { Some(found) if found != name => Some(found), _ => None, diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 607701b056b..abaa02a856e 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -25,7 +25,6 @@ use rustc::hir::def::Def as HirDef; use rustc::hir::def_id::DefId; -use rustc::hir::map::Node; use rustc::ty::{self, TyCtxt}; use rustc_data_structures::fx::FxHashSet; @@ -1006,20 +1005,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { }; let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id)); - for &Spanned { - node: ref field, - span, - } in fields - { + for &Spanned { node: ref field, span } in fields { let sub_span = self.span.span_for_first_ident(span); - if let Some(f) = variant.find_field_named(field.ident.name) { + if let Some(index) = self.tcx.find_field_index(field.ident, variant) { if !self.span.filter_generated(sub_span, span) { let span = self.span_from_span(sub_span.expect("No span fund for var ref")); self.dumper.dump_ref(Ref { kind: RefKind::Variable, span, - ref_id: ::id_from_def_id(f.did), + ref_id: ::id_from_def_id(variant.fields[index].did), }); } } @@ -1638,52 +1633,6 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc } } } - ast::ExprKind::TupField(ref sub_ex, idx) => { - self.visit_expr(&sub_ex); - - let hir_node = match self.save_ctxt.tcx.hir.find(sub_ex.id) { - Some(Node::NodeExpr(expr)) => expr, - _ => { - debug!( - "Missing or weird node for sub-expression {} in {:?}", - sub_ex.id, - ex - ); - return; - } - }; - let ty = match self.save_ctxt.tables.expr_ty_adjusted_opt(&hir_node) { - Some(ty) => &ty.sty, - None => { - visit::walk_expr(self, ex); - return; - } - }; - match *ty { - ty::TyAdt(def, _) => { - let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); - if !self.span.filter_generated(sub_span, ex.span) { - let span = - self.span_from_span(sub_span.expect("No span found for var ref")); - if let Some(field) = def.non_enum_variant().fields.get(idx.node) { - let ref_id = ::id_from_def_id(field.did); - self.dumper.dump_ref(Ref { - kind: RefKind::Variable, - span, - ref_id, - }); - } else { - return; - } - } - } - ty::TyTuple(..) => {} - _ => { - debug!("Expected struct or tuple type, found {:?}", ty); - return; - } - } - } ast::ExprKind::Closure(_, _, ref decl, ref body, _fn_decl_span) => { let mut id = String::from("$"); id.push_str(&ex.id.to_string()); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 4f46fb3545b..ca19ed0df67 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -11,7 +11,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(custom_attribute)] #![feature(macro_lifetime_matcher)] #![allow(unused_attributes)] @@ -554,16 +553,18 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }; match self.tables.expr_ty_adjusted(&hir_node).sty { ty::TyAdt(def, _) if !def.is_enum() => { - let f = def.non_enum_variant().field_named(ident.name); + let variant = &def.non_enum_variant(); + let index = self.tcx.find_field_index(ident, variant).unwrap(); let sub_span = self.span_utils.span_for_last_ident(expr.span); filter!(self.span_utils, sub_span, expr.span, None); let span = self.span_from_span(sub_span.unwrap()); return Some(Data::RefData(Ref { kind: RefKind::Variable, span, - ref_id: id_from_def_id(f.did), + ref_id: id_from_def_id(variant.fields[index].did), })); } + ty::TyTuple(..) => None, _ => { debug!("Expected struct or union type, found {:?}", ty); None @@ -817,7 +818,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { field_ref: &ast::Field, variant: &ty::VariantDef, ) -> Option<Ref> { - let f = variant.find_field_named(field_ref.ident.name)?; + let index = self.tcx.find_field_index(field_ref.ident, variant).unwrap(); // We don't really need a sub-span here, but no harm done let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span); filter!(self.span_utils, sub_span, field_ref.ident.span, None); @@ -825,7 +826,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(Ref { kind: RefKind::Variable, span, - ref_id: id_from_def_id(f.did), + ref_id: id_from_def_id(variant.fields[index].did), }) } diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index d5a58c08cbe..4d93e81a78f 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -202,10 +202,6 @@ impl<'a> SpanUtils<'a> { self.sub_span_after(span, |t| t.is_keyword(keyword)) } - pub fn sub_span_after_token(&self, span: Span, tok: Token) -> Option<Span> { - self.sub_span_after(span, |t| t == tok) - } - fn sub_span_after<F: Fn(Token) -> bool>(&self, span: Span, f: F) -> Option<Span> { let mut toks = self.retokenise_span(span); loop { diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 1fe2f87128a..5f4daf0d568 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -153,7 +153,7 @@ fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>( span, for_ty, depth, ty ); - if depth >= tcx.sess.recursion_limit.get() { + if depth >= *tcx.sess.recursion_limit.get() { return Ok(DtorckConstraint { outlives: vec![], dtorck_types: vec![], diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index cfa3b6912f2..8136f6857a5 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -11,8 +11,6 @@ //! New recursive solver modeled on Chalk's recursive solver. Most of //! the guts are broken up into modules; see the comments in those modules. -#![deny(warnings)] - #![feature(crate_visibility_modifier)] #[macro_use] diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index 153b2e73033..df6793e8a60 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -11,12 +11,14 @@ use rustc::hir::{self, ImplPolarity}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, Slice, TyCtxt}; use rustc::ty::subst::Substs; -use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause}; +use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause, Goal}; use syntax::ast; use rustc_data_structures::sync::Lrc; +use std::iter; + trait Lower<T> { /// Lower a rustc construction (e.g. `ty::TraitPredicate`) to a chalk-like type. fn lower(&self) -> T; @@ -90,8 +92,30 @@ impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> { } } +/// Transforms an existing goal into a FromEnv goal. +/// +/// Used for lowered where clauses (see rustc guide). +trait IntoFromEnvGoal { + fn into_from_env_goal(self) -> Self; +} + +impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> { + fn into_from_env_goal(self) -> DomainGoal<'tcx> { + use self::DomainGoal::*; + match self { + Holds(wc_atom) => FromEnv(wc_atom), + WellFormed(..) | + FromEnv(..) | + WellFormedTy(..) | + FromEnvTy(..) | + RegionOutlives(..) | + TypeOutlives(..) => self, + } + } +} + crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Lrc<Vec<Clause<'tcx>>> + -> Lrc<&'tcx Slice<Clause<'tcx>>> { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); let item = tcx.hir.expect_item(node_id); @@ -100,16 +124,16 @@ crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id), // FIXME: other constructions e.g. traits, associated types... - _ => Lrc::new(vec![]), + _ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())), } } fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Lrc<Vec<Clause<'tcx>>> + -> Lrc<&'tcx Slice<Clause<'tcx>>> { - // Rule Implemented-From-Env (see rustc guide) - // // `trait Trait<P1..Pn> where WC { .. } // P0 == Self` + + // Rule Implemented-From-Env (see rustc guide) // // ``` // forall<Self, P1..Pn> { @@ -125,23 +149,62 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI } }; // `FromEnv(Self: Trait<P1..Pn>)` - let from_env = DomainGoal::FromEnv(trait_pred.lower()).into(); + let from_env = Goal::from(DomainGoal::FromEnv(trait_pred.lower())); // `Implemented(Self: Trait<P1..Pn>)` let impl_trait = DomainGoal::Holds(WhereClauseAtom::Implemented(trait_pred)); // `Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)` - let clause = ProgramClause { + let implemented_from_env = ProgramClause { goal: impl_trait, - hypotheses: vec![from_env], + hypotheses: tcx.mk_goals(iter::once(from_env)), }; - Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))]) + let clauses = iter::once( + Clause::ForAll(ty::Binder::dummy(implemented_from_env)) + ); + + // Rule Implied-Bound-From-Trait + // + // For each where clause WC: + // ``` + // forall<Self, P1..Pn> { + // FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn) + // } + // ``` + + // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC + // FIXME: Remove the [1..] slice; this is a hack because the query + // predicates_of currently includes the trait itself (`Self: Trait<P1..Pn>`). + let where_clauses = &tcx.predicates_of(def_id).predicates; + let implied_bound_clauses = + where_clauses[1..].into_iter() + .map(|wc| implied_bound_from_trait(tcx, trait_pred, wc)); + + Lrc::new(tcx.mk_clauses(clauses.chain(implied_bound_clauses))) +} + +/// For a given `where_clause`, returns a clause `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`. +fn implied_bound_from_trait<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + trait_pred: ty::TraitPredicate<'tcx>, + where_clause: &ty::Predicate<'tcx>, +) -> Clause<'tcx> { + // `FromEnv(Self: Trait<P1..Pn>)` + let impl_trait = DomainGoal::FromEnv(WhereClauseAtom::Implemented(trait_pred)); + + // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)` + Clause::ForAll( + where_clause.lower().map_bound(|goal| ProgramClause { + goal: goal.into_from_env_goal(), + hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))), + }) + ) } fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Lrc<Vec<Clause<'tcx>>> + -> Lrc<&'tcx Slice<Clause<'tcx>>> { if let ImplPolarity::Negative = tcx.impl_polarity(def_id) { - return Lrc::new(vec![]); + return Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())); } // Rule Implemented-From-Impl (see rustc guide) @@ -163,9 +226,11 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId // `Implemented(A0: Trait<A1..An>) :- WC` let clause = ProgramClause { goal: trait_pred, - hypotheses: where_clauses.into_iter().map(|wc| wc.into()).collect() + hypotheses: tcx.mk_goals( + where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx)) + ) }; - Lrc::new(vec![Clause::ForAll(ty::Binder::dummy(clause))]) + Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))) } pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { @@ -187,7 +252,7 @@ impl<'a, 'tcx> ClauseDumper<'a, 'tcx > { for attr in attrs { if attr.check_name("rustc_dump_program_clauses") { let clauses = self.tcx.program_clauses_for(def_id); - for clause in &*clauses { + for clause in *clauses { // Skip the top-level binder for a less verbose output let program_clause = match clause { Clause::Implies(program_clause) => program_clause, diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index 14f8694dbf7..1857df5717b 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -11,17 +11,14 @@ use rustc::traits::{Normalized, ObligationCause}; use rustc::traits::query::NoSolution; use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt}; -use rustc::util::common::CellUsizeExt; +use std::sync::atomic::Ordering; crate fn normalize_ty_after_erasing_regions<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, goal: ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Ty<'tcx> { let ParamEnvAnd { param_env, value } = goal; - tcx.sess - .perf_stats - .normalize_ty_after_erasing_regions - .increment(); + tcx.sess.perf_stats.normalize_ty_after_erasing_regions.fetch_add(1, Ordering::Relaxed); tcx.infer_ctxt().enter(|infcx| { let cause = ObligationCause::dummy(); match infcx.at(&cause, param_env).normalize(&value) { diff --git a/src/librustc_traits/normalize_projection_ty.rs b/src/librustc_traits/normalize_projection_ty.rs index 62d5ef11551..8fc00c937e6 100644 --- a/src/librustc_traits/normalize_projection_ty.rs +++ b/src/librustc_traits/normalize_projection_ty.rs @@ -13,11 +13,11 @@ use rustc::traits::{self, FulfillmentContext, Normalized, ObligationCause, SelectionContext}; use rustc::traits::query::{CanonicalProjectionGoal, NoSolution, normalize::NormalizationResult}; use rustc::ty::{ParamEnvAnd, TyCtxt}; -use rustc::util::common::CellUsizeExt; use rustc_data_structures::sync::Lrc; use syntax::ast::DUMMY_NODE_ID; use syntax_pos::DUMMY_SP; use util; +use std::sync::atomic::Ordering; crate fn normalize_projection_ty<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, @@ -25,7 +25,7 @@ crate fn normalize_projection_ty<'tcx>( ) -> Result<Lrc<Canonical<'tcx, QueryResult<'tcx, NormalizationResult<'tcx>>>>, NoSolution> { debug!("normalize_provider(goal={:#?})", goal); - tcx.sess.perf_stats.normalize_projection_ty.increment(); + tcx.sess.perf_stats.normalize_projection_ty.fetch_add(1, Ordering::Relaxed); tcx.infer_ctxt().enter(|ref infcx| { let ( ParamEnvAnd { diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs index e1c145b122d..f2dd2ed8460 100644 --- a/src/librustc_trans/allocator.rs +++ b/src/librustc_trans/allocator.rs @@ -30,7 +30,6 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) }; let i8 = llvm::LLVMInt8TypeInContext(llcx); let i8p = llvm::LLVMPointerType(i8, 0); - let usizep = llvm::LLVMPointerType(usize, 0); let void = llvm::LLVMVoidTypeInContext(llcx); for method in ALLOCATOR_METHODS { @@ -41,40 +40,21 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) args.push(usize); // size args.push(usize); // align } - AllocatorTy::LayoutRef => args.push(i8p), AllocatorTy::Ptr => args.push(i8p), - AllocatorTy::AllocErr => args.push(i8p), + AllocatorTy::Usize => args.push(usize), AllocatorTy::Bang | - AllocatorTy::ResultExcess | AllocatorTy::ResultPtr | - AllocatorTy::ResultUnit | - AllocatorTy::UsizePair | AllocatorTy::Unit => panic!("invalid allocator arg"), } } let output = match method.output { - AllocatorTy::UsizePair => { - args.push(usizep); // min - args.push(usizep); // max - None - } AllocatorTy::Bang => None, - AllocatorTy::ResultExcess => { - args.push(i8p); // excess_ptr - args.push(i8p); // err_ptr - Some(i8p) - } - AllocatorTy::ResultPtr => { - args.push(i8p); // err_ptr - Some(i8p) - } - AllocatorTy::ResultUnit => Some(i8), + AllocatorTy::ResultPtr => Some(i8p), AllocatorTy::Unit => None, - AllocatorTy::AllocErr | AllocatorTy::Layout | - AllocatorTy::LayoutRef | + AllocatorTy::Usize | AllocatorTy::Ptr => panic!("invalid allocator output"), }; let ty = llvm::LLVMFunctionType(output.unwrap_or(void), diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index acd2a765730..965a34eccb8 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -157,12 +157,12 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) .collect(); - if let Some(id) = tcx.sess.derive_registrar_fn.get() { + if let Some(id) = *tcx.sess.derive_registrar_fn.get() { let def_id = tcx.hir.local_def_id(id); reachable_non_generics.insert(def_id, SymbolExportLevel::C); } - if let Some(id) = tcx.sess.plugin_registrar_fn.get() { + if let Some(id) = *tcx.sess.plugin_registrar_fn.get() { let def_id = tcx.hir.local_def_id(id); reachable_non_generics.insert(def_id, SymbolExportLevel::C); } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index fc699f7569f..f501b1739eb 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -154,13 +154,16 @@ fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize { } } -pub fn create_target_machine(sess: &Session) -> TargetMachineRef { - target_machine_factory(sess)().unwrap_or_else(|err| { +pub fn create_target_machine(sess: &Session, find_features: bool) -> TargetMachineRef { + target_machine_factory(sess, find_features)().unwrap_or_else(|err| { llvm_err(sess.diagnostic(), err).raise() }) } -pub fn target_machine_factory(sess: &Session) +// If find_features is true this won't access `sess.crate_types` by assuming +// that `is_pie_binary` is false. When we discover LLVM target features +// `sess.crate_types` is uninitialized so we cannot access it. +pub fn target_machine_factory(sess: &Session, find_features: bool) -> Arc<Fn() -> Result<TargetMachineRef, String> + Send + Sync> { let reloc_model = get_reloc_model(sess); @@ -201,7 +204,7 @@ pub fn target_machine_factory(sess: &Session) }; let cpu = CString::new(cpu.as_bytes()).unwrap(); let features = CString::new(target_feature(sess).as_bytes()).unwrap(); - let is_pie_binary = is_pie_binary(sess); + let is_pie_binary = !find_features && is_pie_binary(sess); let trap_unreachable = sess.target.target.options.trap_unreachable; Arc::new(move || { @@ -1035,7 +1038,7 @@ pub fn start_async_translation(tcx: TyCtxt, crate_info, time_graph, - coordinator_send: tcx.tx_to_llvm_workers.clone(), + coordinator_send: tcx.tx_to_llvm_workers.lock().clone(), trans_worker_receive, shared_emitter_main, future: coordinator_thread, @@ -1428,7 +1431,7 @@ fn start_executing_work(tcx: TyCtxt, metadata_config: Arc<ModuleConfig>, allocator_config: Arc<ModuleConfig>) -> thread::JoinHandle<Result<CompiledModules, ()>> { - let coordinator_send = tcx.tx_to_llvm_workers.clone(); + let coordinator_send = tcx.tx_to_llvm_workers.lock().clone(); let sess = tcx.sess; // Compute the set of symbols we need to retain when doing LTO (if we need to) @@ -1510,7 +1513,7 @@ fn start_executing_work(tcx: TyCtxt, regular_module_config: modules_config, metadata_module_config: metadata_config, allocator_module_config: allocator_config, - tm_factory: target_machine_factory(tcx.sess), + tm_factory: target_machine_factory(tcx.sess, false), total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), @@ -2340,7 +2343,7 @@ pub(crate) fn submit_translated_module_to_llvm(tcx: TyCtxt, mtrans: ModuleTranslation, cost: u64) { let llvm_work_item = WorkItem::Optimize(mtrans); - drop(tcx.tx_to_llvm_workers.send(Box::new(Message::TranslationDone { + drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::TranslationDone { llvm_work_item, cost, }))); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 0329264a312..1da6f25fd63 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -82,7 +82,8 @@ use std::ffi::CString; use std::str; use std::sync::Arc; use std::time::{Instant, Duration}; -use std::{i32, usize}; +use std::i32; +use std::cmp; use std::sync::mpsc; use syntax_pos::Span; use syntax_pos::symbol::InternedString; @@ -517,7 +518,7 @@ pub fn set_link_section(cx: &CodegenCx, /// users main function. fn maybe_create_entry_wrapper(cx: &CodegenCx) { let (main_def_id, span) = match *cx.sess().entry_fn.borrow() { - Some((id, span)) => { + Some((id, span, _)) => { (cx.tcx.hir.local_def_id(id), span) } None => return, @@ -533,11 +534,11 @@ fn maybe_create_entry_wrapper(cx: &CodegenCx) { let main_llfn = callee::get_fn(cx, instance); - let et = cx.sess().entry_type.get().unwrap(); + let et = cx.sess().entry_fn.get().map(|e| e.2); match et { - config::EntryMain => create_entry_fn(cx, span, main_llfn, main_def_id, true), - config::EntryStart => create_entry_fn(cx, span, main_llfn, main_def_id, false), - config::EntryNone => {} // Do nothing. + Some(config::EntryMain) => create_entry_fn(cx, span, main_llfn, main_def_id, true), + Some(config::EntryStart) => create_entry_fn(cx, span, main_llfn, main_def_id, false), + None => {} // Do nothing. } fn create_entry_fn<'cx>(cx: &'cx CodegenCx, @@ -737,7 +738,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source: ModuleSource::Translated(ModuleLlvm { llcx: metadata_llcx, llmod: metadata_llmod, - tm: create_target_machine(tcx.sess), + tm: create_target_machine(tcx.sess, false), }), kind: ModuleKind::Metadata, }; @@ -795,7 +796,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, codegen_units.len()); // Translate an allocator shim, if any - let allocator_module = if let Some(kind) = tcx.sess.allocator_kind.get() { + let allocator_module = if let Some(kind) = *tcx.sess.allocator_kind.get() { unsafe { let llmod_id = "allocator"; let (llcx, llmod) = @@ -803,7 +804,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let modules = ModuleLlvm { llmod, llcx, - tm: create_target_machine(tcx.sess), + tm: create_target_machine(tcx.sess, false), }; time(tcx.sess, "write allocator module", || { allocator::trans(tcx, &modules, kind) @@ -830,7 +831,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // a bit more efficiently. let codegen_units = { let mut codegen_units = codegen_units; - codegen_units.sort_by_key(|cgu| usize::MAX - cgu.size_estimate()); + codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate())); codegen_units }; @@ -1260,7 +1261,7 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let llvm_module = ModuleLlvm { llcx: cx.llcx, llmod: cx.llmod, - tm: create_target_machine(cx.sess()), + tm: create_target_machine(cx.sess(), false), }; ModuleTranslation { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1f2c3cc883c..fe8a7052bdf 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -162,7 +162,7 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont // Ensure the data-layout values hardcoded remain the defaults. if sess.target.target.options.is_builtin { - let tm = ::back::write::create_target_machine(sess); + let tm = ::back::write::create_target_machine(sess, false); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); llvm::LLVMRustDisposeTargetMachine(tm); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 7664c88679e..28311018ee7 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -42,7 +42,7 @@ use std::ptr; use syntax_pos::{self, Span, Pos}; use syntax::ast; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, InternedString}; use rustc::ty::layout::{self, LayoutOf}; pub mod gdb; @@ -263,7 +263,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let local_id = cx.tcx.hir.as_local_node_id(def_id); match *cx.sess().entry_fn.borrow() { - Some((id, _)) => { + Some((id, _, _)) => { if local_id == Some(id) { flags = flags | DIFlags::FlagMainSubprogram; } @@ -393,7 +393,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, substs.types().zip(names).map(|(ty, name)| { let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); - let name = CString::new(name.as_str().as_bytes()).unwrap(); + let name = CString::new(name.as_bytes()).unwrap(); unsafe { llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), @@ -412,7 +412,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, return create_DIArray(DIB(cx), &template_params[..]); } - fn get_type_parameter_names(cx: &CodegenCx, generics: &ty::Generics) -> Vec<ast::Name> { + fn get_type_parameter_names(cx: &CodegenCx, generics: &ty::Generics) -> Vec<InternedString> { let mut names = generics.parent.map_or(vec![], |def_id| { get_type_parameter_names(cx, cx.tcx.generics_of(def_id)) }); diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 344f959c141..a38d51e7546 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -27,6 +26,7 @@ #![feature(libc)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] +#![feature(slice_sort_by_cached_key)] #![feature(optin_builtin_traits)] #![feature(inclusive_range_fields)] #![feature(underscore_lifetimes)] diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_trans/llvm_util.rs index 1c8f09ce7b3..fa3ecb1cc11 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_trans/llvm_util.rs @@ -134,13 +134,14 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { ("x86", "pclmulqdq") => "pclmul", ("x86", "rdrand") => "rdrnd", ("x86", "bmi1") => "bmi", + ("aarch64", "fp") => "fp-armv8", ("aarch64", "fp16") => "fullfp16", (_, s) => s, } } pub fn target_features(sess: &Session) -> Vec<Symbol> { - let target_machine = create_target_machine(sess); + let target_machine = create_target_machine(sess, true); target_feature_whitelist(sess) .iter() .filter(|feature| { @@ -178,7 +179,7 @@ pub fn print_passes() { pub(crate) fn print(req: PrintRequest, sess: &Session) { require_inited(); - let tm = create_target_machine(sess); + let tm = create_target_machine(sess, true); unsafe { match req { PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm), diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index cf47d9b62a9..0c6bc9e246b 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -15,7 +15,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -52,7 +51,7 @@ pub mod symbol_names_test; /// that actually test that compilation succeeds without /// reporting an error. pub fn check_for_rustc_errors_attr(tcx: TyCtxt) { - if let Some((id, span)) = *tcx.sess.entry_fn.borrow() { + if let Some((id, span, _)) = *tcx.sess.entry_fn.borrow() { let main_def_id = tcx.hir.local_def_id(id); if tcx.has_attr(main_def_id, "rustc_error") { diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_trans_utils/symbol_names.rs index af174f7ce85..f3b7326b210 100644 --- a/src/librustc_trans_utils/symbol_names.rs +++ b/src/librustc_trans_utils/symbol_names.rs @@ -244,11 +244,11 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance let node_id = tcx.hir.as_local_node_id(def_id); if let Some(id) = node_id { - if tcx.sess.plugin_registrar_fn.get() == Some(id) { + if *tcx.sess.plugin_registrar_fn.get() == Some(id) { let disambiguator = tcx.sess.local_crate_disambiguator(); return tcx.sess.generate_plugin_registrar_symbol(disambiguator); } - if tcx.sess.derive_registrar_fn.get() == Some(id) { + if *tcx.sess.derive_registrar_fn.get() == Some(id) { let disambiguator = tcx.sess.local_crate_disambiguator(); return tcx.sess.generate_derive_registrar_symbol(disambiguator); } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0e93277983f..c4ea543ab36 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -979,7 +979,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let item_def_id = tcx.hir.local_def_id(item_id); let generics = tcx.generics_of(item_def_id); let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id)]; - tcx.mk_param(index, tcx.hir.name(node_id)) + tcx.mk_param(index, tcx.hir.name(node_id).as_str()) } Def::SelfTy(_, Some(def_id)) => { // Self in impl (we know the concrete type). diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ae373fbad22..7b4dc60409b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -860,7 +860,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); // Index the struct fields' types. let field_map = variant.fields .iter() - .map(|field| (field.name, field)) + .enumerate() + .map(|(i, field)| (field.name.to_ident(), (i, field))) .collect::<FxHashMap<_, _>>(); // Keep track of which fields have already appeared in the pattern. @@ -869,7 +870,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let mut inexistent_fields = vec![]; // Typecheck each field. for &Spanned { node: ref field, span } in fields { - let field_ty = match used_fields.entry(field.name) { + let ident = tcx.adjust(field.name, variant.did, self.body_id).0; + let field_ty = match used_fields.entry(ident) { Occupied(occupied) => { struct_span_err!(tcx.sess, span, E0025, "field `{}` bound multiple times \ @@ -883,10 +885,10 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } Vacant(vacant) => { vacant.insert(span); - field_map.get(&field.name) - .map(|f| { + field_map.get(&ident) + .map(|(i, f)| { + self.write_field_index(field.id, *i); self.tcx.check_stability(f.did, Some(pat_id), span); - self.field_ty(span, f, substs) }) .unwrap_or_else(|| { @@ -958,8 +960,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } else if !etc { let unmentioned_fields = variant.fields .iter() - .map(|field| field.name) - .filter(|field| !used_fields.contains_key(&field)) + .map(|field| field.name.to_ident()) + .filter(|ident| !used_fields.contains_key(&ident)) .collect::<Vec<_>>(); if unmentioned_fields.len() > 0 { let field_names = if unmentioned_fields.len() == 1 { diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 1d7c533178f..a87058d1fa5 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -56,9 +56,9 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> { return Some((self.cur_ty, 0)); } - if self.steps.len() >= tcx.sess.recursion_limit.get() { + if self.steps.len() >= *tcx.sess.recursion_limit.get() { // We've reached the recursion limit, error gracefully. - let suggested_limit = tcx.sess.recursion_limit.get() * 2; + let suggested_limit = *tcx.sess.recursion_limit.get() * 2; let msg = format!("reached the recursion limit while auto-dereferencing {:?}", self.cur_ty); let error_id = (DiagnosticMessageId::ErrorId(55), Some(self.span), msg.clone()); diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 8db8e52b10d..734d72584da 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -486,11 +486,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { ty::TypeVariants::TyInfer(t) => { match t { ty::InferTy::IntVar(_) | - ty::InferTy::FloatVar(_) | - ty::InferTy::FreshIntTy(_) | - ty::InferTy::FreshFloatTy(_) => { - Err(CastError::NeedDeref) - } + ty::InferTy::FloatVar(_) => Err(CastError::NeedDeref), _ => Err(CastError::NeedViaPtr), } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 377e3a89184..da0d4509353 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -76,7 +76,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// and in libcore/intrinsics.rs pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::ForeignItem) { - let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n))); + let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)).as_str()); let name = it.name.as_str(); let (n_tps, inputs, output) = if name.starts_with("atomic_") { let split : Vec<&str> = name.split('_').collect(); @@ -341,7 +341,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::ForeignItem) { let param = |n| { - let name = Symbol::intern(&format!("P{}", n)); + let name = Symbol::intern(&format!("P{}", n)).as_str(); tcx.mk_param(n, name) }; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 3705c53a76f..7569bdccd5a 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -433,7 +433,6 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let last = exprs[exprs.len() - 1]; match last.node { hir::ExprField(ref expr, _) | - hir::ExprTupField(ref expr, _) | hir::ExprIndex(ref expr, _) | hir::ExprUnary(hir::UnDeref, ref expr) => exprs.push(&expr), _ => break, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index e33e4c51892..49d0df555fa 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -31,6 +31,7 @@ use rustc_data_structures::sync::Lrc; pub use self::MethodError::*; pub use self::CandidateSource::*; +pub use self::suggest::TraitInfo; mod confirm; pub mod probe; @@ -38,6 +39,10 @@ mod suggest; use self::probe::{IsSuggestion, ProbeScope}; +pub fn provide(providers: &mut ty::maps::Providers) { + suggest::provide(providers); +} + #[derive(Clone, Copy, Debug)] pub struct MethodCallee<'tcx> { /// Impl method ID, for inherent methods, or trait method ID, otherwise. diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index fa2022e8cc9..de570956622 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -799,7 +799,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { .collect(); // sort them by the name so we have a stable result - names.sort_by_key(|n| n.as_str()); + names.sort_by_cached_key(|n| n.as_str()); names } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 4bc2d8ce123..d8907866467 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -13,6 +13,7 @@ use check::FnCtxt; use rustc::hir::map as hir_map; +use rustc_data_structures::sync::Lrc; use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId}; @@ -26,12 +27,12 @@ use syntax::util::lev_distance::find_best_match_for_name; use errors::DiagnosticBuilder; use syntax_pos::Span; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::hir; use rustc::hir::print; use rustc::infer::type_variable::TypeVariableOrigin; use rustc::ty::TyAdt; -use std::cell; use std::cmp::Ordering; use super::{MethodError, NoMatchData, CandidateSource}; @@ -208,6 +209,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // be used exists at all, and the type is an ambiuous numeric type // ({integer}/{float}). let mut candidates = all_traits(self.tcx) + .into_iter() .filter(|info| { self.associated_item(info.def_id, item_name, Namespace::Value).is_some() }); @@ -302,8 +304,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for (ty, _) in self.autoderef(span, rcvr_ty) { match ty.sty { ty::TyAdt(def, substs) if !def.is_enum() => { - if let Some(field) = def.non_enum_variant() - .find_field_named(item_name) { + let variant = &def.non_enum_variant(); + if let Some(index) = + self.tcx.find_field_index(item_name.to_ident(), variant) { + let field = &variant.fields[index]; let snippet = tcx.sess.codemap().span_to_snippet(expr.span); let expr_string = match snippet { Ok(expr_string) => expr_string, @@ -519,6 +523,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // implement, by finding ones that have the item name, and are // legal to implement. let mut candidates = all_traits(self.tcx) + .into_iter() .filter(|info| { // we approximate the coherence rules to only suggest // traits that are legal to implement by requiring that @@ -603,18 +608,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } -pub type AllTraitsVec = Vec<DefId>; - #[derive(Copy, Clone)] pub struct TraitInfo { pub def_id: DefId, } -impl TraitInfo { - fn new(def_id: DefId) -> TraitInfo { - TraitInfo { def_id: def_id } - } -} impl PartialEq for TraitInfo { fn eq(&self, other: &TraitInfo) -> bool { self.cmp(other) == Ordering::Equal @@ -638,8 +636,12 @@ impl Ord for TraitInfo { } /// Retrieve all traits in this crate and any dependent crates. -pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> AllTraits<'a> { - if tcx.all_traits.borrow().is_none() { +pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<TraitInfo> { + tcx.all_traits(LOCAL_CRATE).iter().map(|&def_id| TraitInfo { def_id }).collect() +} + +/// Compute all traits in this crate and any dependent crates. +fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId> { use rustc::hir::itemlikevisit; let mut traits = vec![]; @@ -649,7 +651,7 @@ pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> AllTraits<'a> // meh. struct Visitor<'a, 'tcx: 'a> { map: &'a hir_map::Map<'tcx>, - traits: &'a mut AllTraitsVec, + traits: &'a mut Vec<DefId>, } impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'v hir::Item) { @@ -676,7 +678,7 @@ pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> AllTraits<'a> // Cross-crate: let mut external_mods = FxHashSet(); fn handle_external_def(tcx: TyCtxt, - traits: &mut AllTraitsVec, + traits: &mut Vec<DefId>, external_mods: &mut FxHashSet<DefId>, def: Def) { let def_id = def.def_id(); @@ -703,43 +705,16 @@ pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> AllTraits<'a> handle_external_def(tcx, &mut traits, &mut external_mods, Def::Mod(def_id)); } - *tcx.all_traits.borrow_mut() = Some(traits); - } - - let borrow = tcx.all_traits.borrow(); - assert!(borrow.is_some()); - AllTraits { - borrow, - idx: 0, - } + traits } -pub struct AllTraits<'a> { - borrow: cell::Ref<'a, Option<AllTraitsVec>>, - idx: usize, -} - -impl<'a> Iterator for AllTraits<'a> { - type Item = TraitInfo; - - fn next(&mut self) -> Option<TraitInfo> { - let AllTraits { ref borrow, ref mut idx } = *self; - // ugh. - borrow.as_ref().unwrap().get(*idx).map(|info| { - *idx += 1; - TraitInfo::new(*info) - }) - } - - fn size_hint(&self) -> (usize, Option<usize>) { - let len = self.borrow.as_ref().unwrap().len() - self.idx; - (len, Some(len)) +pub fn provide(providers: &mut ty::maps::Providers) { + providers.all_traits = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + Lrc::new(compute_all_traits(tcx)) } } -impl<'a> ExactSizeIterator for AllTraits<'a> {} - - struct UsePlacementFinder<'a, 'tcx: 'a, 'gcx: 'tcx> { target_module: ast::NodeId, span: Option<Span>, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6c18f8d285d..ca35153d571 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -85,7 +85,7 @@ use self::method::MethodCallee; use self::TupleArgumentsFlag::*; use astconv::AstConv; -use hir::def::{Def, CtorKind}; +use hir::def::Def; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use std::slice; use namespace::Namespace; @@ -121,7 +121,7 @@ use std::ops::{self, Deref}; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::codemap::{self, original_sp, Spanned}; +use syntax::codemap::{original_sp, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; use syntax::symbol::{Symbol, InternedString, keywords}; @@ -730,6 +730,7 @@ fn check_impl_item_well_formed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: De } pub fn provide(providers: &mut Providers) { + method::provide(providers); *providers = Providers { typeck_item_bodies, typeck_tables_of, @@ -1127,10 +1128,10 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Check that the main return type implements the termination trait. if let Some(term_id) = fcx.tcx.lang_items().termination() { - if let Some((id, _)) = *fcx.tcx.sess.entry_fn.borrow() { + if let Some((id, _, entry_type)) = *fcx.tcx.sess.entry_fn.borrow() { if id == fn_id { - match fcx.sess().entry_type.get() { - Some(config::EntryMain) => { + match entry_type { + config::EntryMain => { let substs = fcx.tcx.mk_substs(iter::once(Kind::from(ret_ty))); let trait_ref = ty::TraitRef::new(term_id, substs); let return_ty_span = decl.output.span(); @@ -1141,7 +1142,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, traits::Obligation::new( cause, param_env, trait_ref.to_predicate())); }, - _ => {}, + config::EntryStart => {}, } } } @@ -1553,8 +1554,19 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId } fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) { - if tcx.adt_def(def_id).repr.packed() { - if tcx.adt_def(def_id).repr.align > 0 { + let repr = tcx.adt_def(def_id).repr; + if repr.packed() { + for attr in tcx.get_attrs(def_id).iter() { + for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) { + if let attr::ReprPacked(pack) = r { + if pack != repr.pack { + struct_span_err!(tcx.sess, sp, E0634, + "type has conflicting packed representation hints").emit(); + } + } + } + } + if repr.align > 0 { struct_span_err!(tcx.sess, sp, E0587, "type has conflicting packed and align representation hints").emit(); } @@ -1926,6 +1938,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + pub fn write_field_index(&self, node_id: ast::NodeId, index: usize) { + let hir_id = self.tcx.hir.node_to_hir_id(node_id); + self.tables.borrow_mut().field_indices_mut().insert(hir_id, index); + } + // The NodeId and the ItemLocalId must identify the same item. We just pass // both of them for consistency checking. pub fn write_method_call(&self, @@ -2254,7 +2271,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprUnary(hir::UnDeref, _) | hir::ExprField(..) | - hir::ExprTupField(..) | hir::ExprIndex(..) => { true } @@ -3058,20 +3074,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let (ident, def_scope) = self.tcx.adjust(field.node, base_def.did, self.body_id); let fields = &base_def.non_enum_variant().fields; - if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) { + if let Some(index) = fields.iter().position(|f| f.name.to_ident() == ident) { + let field = &fields[index]; let field_ty = self.field_ty(expr.span, field, substs); if field.vis.is_accessible_from(def_scope, self.tcx) { let adjustments = autoderef.adjust_steps(needs); self.apply_adjustments(base, adjustments); autoderef.finalize(); + self.write_field_index(expr.id, index); self.tcx.check_stability(field.did, Some(expr.id), expr.span); - return field_ty; } private_candidate = Some((base_def.did, field_ty)); } } + ty::TyTuple(ref tys) => { + let fstr = field.node.as_str(); + if let Ok(index) = fstr.parse::<usize>() { + if fstr == index.to_string() { + if let Some(field_ty) = tys.get(index) { + let adjustments = autoderef.adjust_steps(needs); + self.apply_adjustments(base, adjustments); + autoderef.finalize(); + + self.write_field_index(expr.id, index); + return field_ty; + } + } + } + } _ => {} } } @@ -3177,78 +3209,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { display } - // Check tuple index expressions - fn check_tup_field(&self, - expr: &'gcx hir::Expr, - needs: Needs, - base: &'gcx hir::Expr, - idx: codemap::Spanned<usize>) -> Ty<'tcx> { - let expr_t = self.check_expr_with_needs(base, needs); - let expr_t = self.structurally_resolved_type(expr.span, - expr_t); - let mut private_candidate = None; - let mut tuple_like = false; - let mut autoderef = self.autoderef(expr.span, expr_t); - while let Some((base_t, _)) = autoderef.next() { - let field = match base_t.sty { - ty::TyAdt(base_def, substs) if base_def.is_struct() => { - tuple_like = base_def.non_enum_variant().ctor_kind == CtorKind::Fn; - if !tuple_like { continue } - - debug!("tuple struct named {:?}", base_t); - let ident = - ast::Ident::new(Symbol::intern(&idx.node.to_string()), idx.span.modern()); - let (ident, def_scope) = - self.tcx.adjust_ident(ident, base_def.did, self.body_id); - let fields = &base_def.non_enum_variant().fields; - if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) { - let field_ty = self.field_ty(expr.span, field, substs); - if field.vis.is_accessible_from(def_scope, self.tcx) { - self.tcx.check_stability(field.did, Some(expr.id), expr.span); - Some(field_ty) - } else { - private_candidate = Some((base_def.did, field_ty)); - None - } - } else { - None - } - } - ty::TyTuple(ref v) => { - tuple_like = true; - v.get(idx.node).cloned() - } - _ => continue - }; - - if let Some(field_ty) = field { - let adjustments = autoderef.adjust_steps(needs); - self.apply_adjustments(base, adjustments); - autoderef.finalize(); - return field_ty; - } - } - autoderef.unambiguous_final_ty(); - - if let Some((did, field_ty)) = private_candidate { - let struct_path = self.tcx().item_path_str(did); - struct_span_err!(self.tcx().sess, expr.span, E0611, - "field `{}` of tuple-struct `{}` is private", - idx.node, struct_path).emit(); - return field_ty; - } - - if tuple_like { - type_error_struct!(self.tcx().sess, expr.span, expr_t, E0612, - "attempted out-of-bounds tuple index `{}` on type `{}`", - idx.node, expr_t).emit(); - } else { - self.no_such_field_err(expr.span, idx.node, expr_t).emit(); - } - - self.tcx().types.err - } - fn no_such_field_err<T: Display>(&self, span: Span, field: T, expr_t: &ty::TyS) -> DiagnosticBuilder { type_error_struct!(self.tcx().sess, span, expr_t, E0609, @@ -3331,8 +3291,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; let mut remaining_fields = FxHashMap(); - for field in &variant.fields { - remaining_fields.insert(field.name.to_ident(), field); + for (i, field) in variant.fields.iter().enumerate() { + remaining_fields.insert(field.name.to_ident(), (i, field)); } let mut seen_fields = FxHashMap(); @@ -3342,8 +3302,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Typecheck each field. for field in ast_fields { let ident = tcx.adjust(field.name.node, variant.did, self.body_id).0; - let field_type = if let Some(v_field) = remaining_fields.remove(&ident) { - seen_fields.insert(field.name.node, field.span); + let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { + seen_fields.insert(ident, field.span); + self.write_field_index(field.id, i); // we don't look at stability attributes on // struct-like enums (yet...), but it's definitely not @@ -3355,18 +3316,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.field_ty(field.span, v_field, substs) } else { error_happened = true; - if let Some(_) = variant.find_field_named(field.name.node) { + if let Some(prev_span) = seen_fields.get(&ident) { let mut err = struct_span_err!(self.tcx.sess, field.name.span, E0062, "field `{}` specified more than once", - field.name.node); + ident); err.span_label(field.name.span, "used more than once"); - - if let Some(prev_span) = seen_fields.get(&field.name.node) { - err.span_label(*prev_span, format!("first use of `{}`", field.name.node)); - } + err.span_label(*prev_span, format!("first use of `{}`", ident)); err.emit(); } else { @@ -4109,9 +4067,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprField(ref base, ref field) => { self.check_field(expr, needs, &base, field) } - hir::ExprTupField(ref base, idx) => { - self.check_tup_field(expr, needs, &base, idx) - } hir::ExprIndex(ref base, ref idx) => { let base_t = self.check_expr_with_needs(&base, needs); let idx_t = self.check_expr(&idx); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 7dc73a1d5f0..6348f386177 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -655,7 +655,7 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) { // local so it should be okay to just unwrap everything. let trait_def_id = impl_params[&method_param.name]; let trait_decl_span = tcx.def_span(trait_def_id); - error_194(tcx, type_span, trait_decl_span, method_param.name); + error_194(tcx, type_span, trait_decl_span, &method_param.name[..]); } } } @@ -759,7 +759,7 @@ fn error_392<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, param_name: ast: err } -fn error_194(tcx: TyCtxt, span: Span, trait_decl_span: Span, name: ast::Name) { +fn error_194(tcx: TyCtxt, span: Span, trait_decl_span: Span, name: &str) { struct_span_err!(tcx.sess, span, E0194, "type parameter `{}` shadows another type parameter of the same name", name) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index bbd04e0b19a..6e0d7dd8508 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -226,13 +226,24 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { self.visit_node_id(e.span, e.hir_id); - if let hir::ExprClosure(_, _, body, _, _) = e.node { - let body = self.fcx.tcx.hir.body(body); - for arg in &body.arguments { - self.visit_node_id(e.span, arg.hir_id); - } + match e.node { + hir::ExprClosure(_, _, body, _, _) => { + let body = self.fcx.tcx.hir.body(body); + for arg in &body.arguments { + self.visit_node_id(e.span, arg.hir_id); + } - self.visit_body(body); + self.visit_body(body); + } + hir::ExprStruct(_, ref fields, _) => { + for field in fields { + self.visit_field_id(field.id); + } + } + hir::ExprField(..) => { + self.visit_field_id(e.id); + } + _ => {} } intravisit::walk_expr(self, e); @@ -254,6 +265,11 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { .expect("missing binding mode"); self.tables.pat_binding_modes_mut().insert(p.hir_id, bm); } + hir::PatKind::Struct(_, ref fields, _) => { + for field in fields { + self.visit_field_id(field.node.id); + } + } _ => {} }; @@ -384,6 +400,13 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } + fn visit_field_id(&mut self, node_id: ast::NodeId) { + let hir_id = self.tcx().hir.node_to_hir_id(node_id); + if let Some(index) = self.fcx.tables.borrow_mut().field_indices_mut().remove(hir_id) { + self.tables.field_indices_mut().insert(hir_id, index); + } + } + fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) { // Export associated path extensions and method resultions. if let Some(def) = self.fcx diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 59156bf0dfe..3939c3a0627 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -64,6 +64,7 @@ pub fn provide(providers: &mut Providers) { type_of, generics_of, predicates_of, + explicit_predicates_of, super_predicates_of, type_param_predicates, trait_def, @@ -241,7 +242,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_owner_def_id = tcx.hir.local_def_id(param_owner); let generics = tcx.generics_of(param_owner_def_id); let index = generics.type_param_to_index[&def_id]; - let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id)); + let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id).as_str()); // Don't look for bounds where the type parameter isn't in scope. let parent = if item_def_id == param_owner_def_id { @@ -513,11 +514,11 @@ fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, discr: ty::VariantDiscr, def: &hir::VariantData) -> ty::VariantDef { - let mut seen_fields: FxHashMap<ast::Name, Span> = FxHashMap(); + let mut seen_fields: FxHashMap<ast::Ident, Span> = FxHashMap(); let node_id = tcx.hir.as_local_node_id(did).unwrap(); let fields = def.fields().iter().map(|f| { let fid = tcx.hir.local_def_id(f.id); - let dup_span = seen_fields.get(&f.name).cloned(); + let dup_span = seen_fields.get(&f.name.to_ident()).cloned(); if let Some(prev_span) = dup_span { struct_span_err!(tcx.sess, f.span, E0124, "field `{}` is already declared", @@ -526,7 +527,7 @@ fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .span_label(prev_span, format!("`{}` first declared here", f.name)) .emit(); } else { - seen_fields.insert(f.name, f.span); + seen_fields.insert(f.name.to_ident(), f.span); } ty::FieldDef { @@ -839,7 +840,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opt_self = Some(ty::TypeParameterDef { index: 0, - name: keywords::SelfType.name(), + name: keywords::SelfType.name().as_str(), def_id: tcx.hir.local_def_id(param_id), has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -915,7 +916,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TypeParameterDef { index: type_start + i as u32, - name: p.name, + name: p.name.as_str(), def_id: tcx.hir.local_def_id(p.id), has_default: p.default.is_some(), object_lifetime_default: @@ -934,7 +935,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // add a dummy parameter for the closure kind types.push(ty::TypeParameterDef { index: type_start, - name: Symbol::intern("<closure_kind>"), + name: Symbol::intern("<closure_kind>").as_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -945,7 +946,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // add a dummy parameter for the closure signature types.push(ty::TypeParameterDef { index: type_start + 1, - name: Symbol::intern("<closure_signature>"), + name: Symbol::intern("<closure_signature>").as_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -956,7 +957,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.with_freevars(node_id, |fv| { types.extend(fv.iter().zip(2..).map(|(_, i)| ty::TypeParameterDef { index: type_start + i, - name: Symbol::intern("<upvar>"), + name: Symbol::intern("<upvar>").as_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -1296,13 +1297,17 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::GenericPredicates<'tcx> { let explicit = explicit_predicates_of(tcx, def_id); + let predicates = if tcx.sess.features_untracked().infer_outlives_requirements { + [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat() + } else { explicit.predicates }; + ty::GenericPredicates { parent: explicit.parent, - predicates: [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat() + predicates: predicates, } } -fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::GenericPredicates<'tcx> { use rustc::hir::map::*; @@ -1436,7 +1441,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Collect the predicates that were written inline by the user on each // type parameter (e.g., `<T:Foo>`). for param in ast_generics.ty_params() { - let param_ty = ty::ParamTy::new(index, param.name).to_ty(tcx); + let param_ty = ty::ParamTy::new(index, param.name.as_str()).to_ty(tcx); index += 1; let bounds = compute_bounds(&icx, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 79d7c8e7282..ae3b2b22ea1 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4138,86 +4138,6 @@ https://doc.rust-lang.org/book/first-edition/primitive-types.html https://doc.rust-lang.org/book/first-edition/structs.html "##, -E0611: r##" -Attempted to access a private field on a tuple-struct. - -Erroneous code example: - -```compile_fail,E0611 -mod some_module { - pub struct Foo(u32); - - impl Foo { - pub fn new() -> Foo { Foo(0) } - } -} - -let y = some_module::Foo::new(); -println!("{}", y.0); // error: field `0` of tuple-struct `some_module::Foo` - // is private -``` - -Since the field is private, you have two solutions: - -1) Make the field public: - -``` -mod some_module { - pub struct Foo(pub u32); // The field is now public. - - impl Foo { - pub fn new() -> Foo { Foo(0) } - } -} - -let y = some_module::Foo::new(); -println!("{}", y.0); // So we can access it directly. -``` - -2) Add a getter function to keep the field private but allow for accessing its -value: - -``` -mod some_module { - pub struct Foo(u32); - - impl Foo { - pub fn new() -> Foo { Foo(0) } - - // We add the getter function. - pub fn get(&self) -> &u32 { &self.0 } - } -} - -let y = some_module::Foo::new(); -println!("{}", y.get()); // So we can get the value through the function. -``` -"##, - -E0612: r##" -Attempted out-of-bounds tuple index. - -Erroneous code example: - -```compile_fail,E0612 -struct Foo(u32); - -let y = Foo(0); -println!("{}", y.1); // error: attempted out-of-bounds tuple index `1` - // on type `Foo` -``` - -If a tuple/tuple-struct type has n fields, you can only try to access these n -fields from 0 to (n - 1). So in this case, you can only index `0`. Example: - -``` -struct Foo(u32); - -let y = Foo(0); -println!("{}", y.0); // ok! -``` -"##, - E0614: r##" Attempted to dereference a variable which cannot be dereferenced. @@ -4836,14 +4756,17 @@ register_diagnostics! { // E0563, // cannot determine a type for this `impl Trait`: {} // removed in 6383de15 E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` - E0587, // struct has conflicting packed and align representation hints - E0588, // packed struct cannot transitively contain a `[repr(align)]` struct + E0587, // type has conflicting packed and align representation hints + E0588, // packed type cannot transitively contain a `[repr(align)]` type E0592, // duplicate definitions with name `{}` +// E0611, // merged into E0616 +// E0612, // merged into E0609 // E0613, // Removed (merged with E0609) - E0640, // infer outlives E0627, // yield statement outside of generator literal E0632, // cannot provide explicit type parameters when `impl Trait` is used in // argument position. + E0634, // type has conflicting packed representaton hints + E0640, // infer outlives requirements E0641, // cannot cast to/from a pointer with an unknown kind E0645, // trait aliases not finished E0907, // type inside generator must be known in this context diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 6f71db998bd..a4477e80b98 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -68,7 +68,6 @@ This API is completely unstable and subject to change. #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![allow(non_camel_case_types)] @@ -77,12 +76,13 @@ This API is completely unstable and subject to change. #![feature(crate_visibility_modifier)] #![feature(from_ref)] #![feature(exhaustive_patterns)] -#![feature(option_filter)] #![feature(quote)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] +#![feature(slice_sort_by_cached_key)] #![feature(dyn_trait)] +#![feature(underscore_lifetimes)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -289,12 +289,10 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() { - match tcx.sess.entry_type.get() { - Some(config::EntryMain) => check_main_fn_ty(tcx, id, sp), - Some(config::EntryStart) => check_start_fn_ty(tcx, id, sp), - Some(config::EntryNone) => {} - None => bug!("entry function without a type") + if let Some((id, sp, entry_type)) = *tcx.sess.entry_fn.borrow() { + match entry_type { + config::EntryMain => check_main_fn_ty(tcx, id, sp), + config::EntryStart => check_start_fn_ty(tcx, id, sp), } } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs new file mode 100644 index 00000000000..9a8fd46b0ef --- /dev/null +++ b/src/librustc_typeck/outlives/explicit.rs @@ -0,0 +1,82 @@ +// Copyright 2013 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 hir::map as hir_map; +use rustc::hir; +use rustc::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::ty::maps::Providers; +use rustc::ty::{self, CratePredicatesMap, TyCtxt}; +use rustc_data_structures::sync::Lrc; +use util::nodemap::FxHashMap; + +pub fn explicit_predicates<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + crate_num: CrateNum, +) -> FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> { + assert_eq!(crate_num, LOCAL_CRATE); + let mut predicates: FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> = FxHashMap(); + + // iterate over the entire crate + tcx.hir.krate().visit_all_item_likes(&mut ExplicitVisitor { + tcx: tcx, + explicit_predicates: &mut predicates, + crate_num: crate_num, + }); + + predicates +} + +pub struct ExplicitVisitor<'cx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'tcx, 'tcx>, + explicit_predicates: &'cx mut FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>, + crate_num: CrateNum, +} + +impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> { + fn visit_item(&mut self, item: &'tcx hir::Item) { + let def_id = DefId { + krate: self.crate_num, + index: item.hir_id.owner, + }; + + let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id); + + let filtered_predicates = local_explicit_predicate + .predicates + .into_iter() + .filter(|pred| match pred { + ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => true, + + ty::Predicate::Trait(..) + | ty::Predicate::Projection(..) + | ty::Predicate::WellFormed(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::ConstEvaluatable(..) => false, + }) + .collect(); + + match item.node { + hir::ItemStruct(..) | hir::ItemEnum(..) => { + self.tcx.adt_def(def_id); + } + _ => {} + } + + self.explicit_predicates + .insert(def_id, Lrc::new(filtered_predicates)); + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {} + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {} +} diff --git a/src/librustc_typeck/outlives/implicit_empty.rs b/src/librustc_typeck/outlives/implicit_empty.rs new file mode 100644 index 00000000000..b2259c63683 --- /dev/null +++ b/src/librustc_typeck/outlives/implicit_empty.rs @@ -0,0 +1,52 @@ +// Copyright 2013 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 hir::map as hir_map; +use rustc::hir; +use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::ty::maps::Providers; +use rustc::ty::{self, CratePredicatesMap, TyCtxt}; +use rustc_data_structures::sync::Lrc; +use util::nodemap::FxHashMap; + +// Create the sets of inferred predicates for each type. These sets +// are initially empty but will grow during the inference step. +pub fn empty_predicate_map<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, +) -> FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> { + let mut predicates = FxHashMap(); + + // iterate over the entire crate + tcx.hir + .krate() + .visit_all_item_likes(&mut EmptyImplicitVisitor { + tcx, + predicates: &mut predicates, + }); + + predicates +} + +pub struct EmptyImplicitVisitor<'cx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'tcx, 'tcx>, + predicates: &'cx mut FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>, +} + +impl<'a, 'p, 'v> ItemLikeVisitor<'v> for EmptyImplicitVisitor<'a, 'p> { + fn visit_item(&mut self, item: &hir::Item) { + self.predicates + .insert(self.tcx.hir.local_def_id(item.id), Lrc::new(Vec::new())); + } + + fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {} + + fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {} +} diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs new file mode 100644 index 00000000000..ac53a6d4a3f --- /dev/null +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -0,0 +1,442 @@ +// Copyright 2013 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(unused)] + +use rustc::hir; +use rustc::hir::def::{CtorKind, Def}; +use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE}; +use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::hir::map as hir_map; +use rustc::ty::Slice; +use rustc::ty::maps::Providers; +use rustc::ty::outlives::Component; +use rustc::ty::subst::{Kind, Subst, UnpackedKind}; +use rustc::ty::{self, AdtKind, CratePredicatesMap, Region, RegionKind, ReprOptions, + ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; +use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync::Lrc; +use syntax::{abi, ast}; +use syntax_pos::{Span, DUMMY_SP}; + +/// Infer predicates for the items in the crate. +/// +/// global_inferred_outlives: this is initially the empty map that +/// was generated by walking the items in the crate. This will +/// now be filled with inferred predicates. +pub fn infer_predicates<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>, +) -> FxHashMap<DefId, RequiredPredicates<'tcx>> { + debug!("infer_predicates"); + + let mut predicates_added = true; + + let mut global_inferred_outlives = FxHashMap::default(); + + // If new predicates were added then we need to re-calculate + // all crates since there could be new implied predicates. + while predicates_added { + predicates_added = false; + + let mut visitor = InferVisitor { + tcx: tcx, + global_inferred_outlives: &mut global_inferred_outlives, + predicates_added: &mut predicates_added, + explicit_map: explicit_map, + }; + + // Visit all the crates and infer predicates + tcx.hir.krate().visit_all_item_likes(&mut visitor); + } + + global_inferred_outlives +} + +pub struct InferVisitor<'cx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'tcx, 'tcx>, + global_inferred_outlives: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>, + predicates_added: &'cx mut bool, + explicit_map: &'cx FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>, +} + +/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred +/// must be added to the struct header. +type RequiredPredicates<'tcx> = FxHashSet<ty::OutlivesPredicate<Kind<'tcx>, ty::Region<'tcx>>>; + +impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + let item_did = self.tcx.hir.local_def_id(item.id); + + debug!("InferVisitor::visit_item(item={:?})", item_did); + + let node_id = self.tcx + .hir + .as_local_node_id(item_did) + .expect("expected local def-id"); + let item = match self.tcx.hir.get(node_id) { + hir::map::NodeItem(item) => item, + _ => bug!(), + }; + + let mut item_required_predicates = RequiredPredicates::default(); + match item.node { + hir::ItemUnion(..) | hir::ItemEnum(..) | hir::ItemStruct(..) => { + let adt_def = self.tcx.adt_def(item_did); + + // Iterate over all fields in item_did + for field_def in adt_def.all_fields() { + // Calculating the predicate requirements necessary + // for item_did. + // + // For field of type &'a T (reference) or TyAdt + // (struct/enum/union) there will be outlive + // requirements for adt_def. + let field_ty = self.tcx.type_of(field_def.did); + insert_required_predicates_to_be_wf( + self.tcx, + field_ty, + self.global_inferred_outlives, + &mut item_required_predicates, + self.explicit_map, + ); + } + } + + _ => {} + }; + + // If new predicates were added (`local_predicate_map` has more + // predicates than the `global_inferred_outlives`), the new predicates + // might result in implied predicates for their parent types. + // Therefore mark `predicates_added` as true and which will ensure + // we walk the crates again and re-calculate predicates for all + // items. + let item_predicates_len: usize = self.global_inferred_outlives + .get(&item_did) + .map(|p| p.len()) + .unwrap_or(0); + if item_required_predicates.len() > item_predicates_len { + *self.predicates_added = true; + self.global_inferred_outlives + .insert(item_did, item_required_predicates); + } + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {} + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {} +} + +fn insert_required_predicates_to_be_wf<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + field_ty: Ty<'tcx>, + global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>, + required_predicates: &mut RequiredPredicates<'tcx>, + explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>, +) { + for ty in field_ty.walk() { + match ty.sty { + // The field is of type &'a T which means that we will have + // a predicate requirement of T: 'a (T outlives 'a). + // + // We also want to calculate potential predicates for the T + ty::TyRef(region, mt) => { + insert_outlives_predicate(tcx, mt.ty.into(), region, required_predicates); + } + + // For each TyAdt (struct/enum/union) type `Foo<'a, T>`, we + // can load the current set of inferred and explicit + // predicates from `global_inferred_outlives` and filter the + // ones that are TypeOutlives. + // + ty::TyAdt(def, substs) => { + // First check the inferred predicates + // + // Example 1: + // + // struct Foo<'a, T> { + // field1: Bar<'a, T> + // } + // + // struct Bar<'b, U> { + // field2: &'b U + // } + // + // Here, when processing the type of `field1`, we would + // request the set of implicit predicates computed for `Bar` + // thus far. This will initially come back empty, but in next + // round we will get `U: 'b`. We then apply the substitution + // `['b => 'a, U => T]` and thus get the requirement that `T: + // 'a` holds for `Foo`. + if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) { + for unsubstituted_predicate in unsubstituted_predicates { + // `unsubstituted_predicate` is `U: 'b` in the + // example above. So apply the substitution to + // get `T: 'a` (or `predicate`): + let predicate = unsubstituted_predicate.subst(tcx, substs); + insert_outlives_predicate( + tcx, + predicate.0, + predicate.1, + required_predicates, + ); + } + } + + // Check if the type has any explicit predicates that need + // to be added to `required_predicates` + // let _: () = substs.region_at(0); + check_explicit_predicates(tcx, &def.did, substs, required_predicates, explicit_map); + } + + ty::TyDynamic(obj, region) => { + // FIXME This corresponds to `dyn Trait<..>`. In this + // case, we should use the explicit predicates as + // well. + if let Some(p) = obj.principal() { + check_explicit_predicates( + tcx, + &p.skip_binder().def_id, + &[region.into()], + required_predicates, + explicit_map, + ); + } + } + + ty::TyProjection(obj) => { + // FIXME This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the + // explicit predicates as well. + check_explicit_predicates( + tcx, + &obj.item_def_id, + obj.substs, + required_predicates, + explicit_map, + ); + } + + _ => {} + } + } +} + +/// We also have to check the explicit predicates +/// declared on the type. +/// +/// struct Foo<'a, T> { +/// field1: Bar<T> +/// } +/// +/// struct Bar<U> where U: 'static, U: Foo { +/// ... +/// } +/// +/// Here, we should fetch the explicit predicates, which +/// will give us `U: 'static` and `U: Foo`. The latter we +/// can ignore, but we will want to process `U: 'static`, +/// applying the substitution as above. +fn check_explicit_predicates<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + def_id: &DefId, + substs: &[Kind<'tcx>], + required_predicates: &mut RequiredPredicates<'tcx>, + explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>, +) { + if let Some(general_predicates) = explicit_map.get(def_id) { + for general_predicate in general_predicates.iter() { + match general_predicate { + // `poly` is `PolyTypeOutlivesPredicate<OutlivesPredicate<Ty>>` + // where OutlivesPredicate<type1, region1> is the predicate + // we want to add. + ty::Predicate::TypeOutlives(poly) => { + let predicate = poly.0.subst(tcx, substs); + insert_outlives_predicate( + tcx, + predicate.0.into(), + predicate.1, + required_predicates, + ); + } + + // `poly` is `PolyRegionOutlivesPredicate<OutlivesPredicate<Ty>>` + // where OutlivesPredicate<region1, region2> is the predicate + // we want to add. + ty::Predicate::RegionOutlives(poly) => { + let predicate = poly.0.subst(tcx, substs); + insert_outlives_predicate( + tcx, + predicate.0.into(), + predicate.1, + required_predicates, + ); + } + + ty::Predicate::Trait(..) + | ty::Predicate::Projection(..) + | ty::Predicate::WellFormed(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::ConstEvaluatable(..) => (), + } + } + } +} + +/// Given a requirement `T: 'a` or `'b: 'a`, deduce the +/// outlives_component and add it to `required_predicates` +fn insert_outlives_predicate<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + kind: Kind<'tcx>, + outlived_region: Region<'tcx>, + required_predicates: &mut RequiredPredicates<'tcx>, +) { + // If the `'a` region is bound within the field type itself, we + // don't want to propagate this constraint to the header. + if !is_free_region(outlived_region) { + return; + } + + match kind.unpack() { + UnpackedKind::Type(ty) => { + // `T: 'outlived_region` for some type `T` + // But T could be a lot of things: + // e.g., if `T = &'b u32`, then `'b: 'outlived_region` is + // what we want to add. + // + // Or if within `struct Foo<U>` you had `T = Vec<U>`, then + // we would want to add `U: 'outlived_region` + for component in tcx.outlives_components(ty) { + match component { + Component::Region(r) => { + // This would arise from something like: + // + // ``` + // struct Foo<'a, 'b> { + // x: &'a &'b u32 + // } + // ``` + // + // Here `outlived_region = 'a` and `kind = &'b + // u32`. Decomposing `&'b u32` into + // components would yield `'b`, and we add the + // where clause that `'b: 'a`. + insert_outlives_predicate( + tcx, + r.into(), + outlived_region, + required_predicates, + ); + } + + Component::Param(param_ty) => { + // param_ty: ty::ParamTy + // This would arise from something like: + // + // ``` + // struct Foo<'a, U> { + // x: &'a Vec<U> + // } + // ``` + // + // Here `outlived_region = 'a` and `kind = + // Vec<U>`. Decomposing `Vec<U>` into + // components would yield `U`, and we add the + // where clause that `U: 'a`. + let ty: Ty<'tcx> = tcx.mk_param(param_ty.idx, param_ty.name); + required_predicates + .insert(ty::OutlivesPredicate(ty.into(), outlived_region)); + } + + Component::Projection(proj_ty) => { + // This would arise from something like: + // + // ``` + // struct Foo<'a, T: Iterator> { + // x: &'a <T as Iterator>::Item + // } + // ``` + // + // Here we want to add an explicit `where <T as Iterator>::Item: 'a`. + let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs); + required_predicates + .insert(ty::OutlivesPredicate(ty.into(), outlived_region)); + } + + Component::EscapingProjection(_) => { + // As above, but the projection involves + // late-bound regions. Therefore, the WF + // requirement is not checked in type definition + // but at fn call site, so ignore it. + // + // ``` + // struct Foo<'a, T: Iterator> { + // x: for<'b> fn(<&'b T as Iterator>::Item) + // // ^^^^^^^^^^^^^^^^^^^^^^^^^ + // } + // ``` + // + // Since `'b` is not in scope on `Foo`, can't + // do anything here, ignore it. + } + + Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"), + } + } + } + + UnpackedKind::Lifetime(r) => { + if !is_free_region(r) { + return; + } + required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region)); + } + } +} + +fn is_free_region(region: Region<'_>) -> bool { + // First, screen for regions that might appear in a type header. + match region { + // *These* correspond to `T: 'a` relationships where `'a` is + // either declared on the type or `'static`: + // + // struct Foo<'a, T> { + // field: &'a T, // this would generate a ReEarlyBound referencing `'a` + // field2: &'static T, // this would generate a ReStatic + // } + // + // We care about these, so fall through. + RegionKind::ReStatic | RegionKind::ReEarlyBound(_) => true, + + // Late-bound regions can appear in `fn` types: + // + // struct Foo<T> { + // field: for<'b> fn(&'b T) // e.g., 'b here + // } + // + // The type above might generate a `T: 'b` bound, but we can + // ignore it. We can't put it on the struct header anyway. + RegionKind::ReLateBound(..) => false, + + // These regions don't appear in types from type declarations: + RegionKind::ReEmpty + | RegionKind::ReErased + | RegionKind::ReClosureBound(..) + | RegionKind::ReCanonical(..) + | RegionKind::ReScope(..) + | RegionKind::ReVar(..) + | RegionKind::ReSkolemized(..) + | RegionKind::ReFree(..) => { + bug!("unexpected region in outlives inference: {:?}", region); + } + } +} diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index 1127028cbc8..bad0c68a6fe 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -7,23 +7,105 @@ // <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 rustc::hir::def_id::DefId; -use rustc::ty::{self, TyCtxt}; +#![allow(unused)] +#[allow(dead_code)] +use hir::map as hir_map; +use rustc::dep_graph::DepKind; +use rustc::hir; +use rustc::hir::Ty_::*; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::maps::Providers; +use rustc::ty::subst::UnpackedKind; +use rustc::ty::{self, CratePredicatesMap, TyCtxt}; +use rustc_data_structures::sync::Lrc; +use util::nodemap::FxHashMap; +mod explicit; +mod implicit_empty; +mod implicit_infer; /// Code to write unit test for outlives. pub mod test; pub fn provide(providers: &mut Providers) { *providers = Providers { inferred_outlives_of, + inferred_outlives_crate, ..*providers }; } -//todo -fn inferred_outlives_of<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, _def_id: DefId) - -> Vec<ty::Predicate<'tcx>> { - Vec::new() +fn inferred_outlives_of<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + item_def_id: DefId, +) -> Lrc<Vec<ty::Predicate<'tcx>>> { + let id = tcx.hir + .as_local_node_id(item_def_id) + .expect("expected local def-id"); + + match tcx.hir.get(id) { + hir_map::NodeItem(item) => match item.node { + hir::ItemStruct(..) | hir::ItemEnum(..) | hir::ItemUnion(..) => { + let crate_map = tcx.inferred_outlives_crate(LOCAL_CRATE); + let dep_node = item_def_id.to_dep_node(tcx, DepKind::InferredOutlivesOf); + tcx.dep_graph.read(dep_node); + + crate_map + .predicates + .get(&item_def_id) + .unwrap_or(&crate_map.empty_predicate) + .clone() + } + + _ => Lrc::new(Vec::new()), + }, + + _ => Lrc::new(Vec::new()), + } +} + +fn inferred_outlives_crate<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + crate_num: CrateNum, +) -> Lrc<CratePredicatesMap<'tcx>> { + // Compute a map from each struct/enum/union S to the **explicit** + // outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote. + // Typically there won't be many of these, except in older code where + // they were mandatory. Nonetheless, we have to ensure that every such + // predicate is satisfied, so they form a kind of base set of requirements + // for the type. + + // Compute the inferred predicates + let exp = explicit::explicit_predicates(tcx, crate_num); + let mut global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp); + + // Convert the inferred predicates into the "collected" form the + // global data structure expects. + // + // FIXME -- consider correcting impedance mismatch in some way, + // probably by updating the global data structure. + let mut predicates = global_inferred_outlives + .iter() + .map(|(&def_id, set)| { + let vec: Vec<ty::Predicate<'tcx>> = set.iter() + .map( + |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() { + UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder( + ty::OutlivesPredicate(ty1, region2), + )), + UnpackedKind::Lifetime(region1) => ty::Predicate::RegionOutlives( + ty::Binder(ty::OutlivesPredicate(region1, region2)), + ), + }, + ) + .collect(); + (def_id, Lrc::new(vec)) + }) + .collect(); + + let empty_predicate = Lrc::new(Vec::new()); + + Lrc::new(ty::CratePredicatesMap { + predicates, + empty_predicate, + }) } diff --git a/src/librustc_typeck/outlives/test.rs b/src/librustc_typeck/outlives/test.rs index 196e6605494..c3c2ae667dd 100644 --- a/src/librustc_typeck/outlives/test.rs +++ b/src/librustc_typeck/outlives/test.rs @@ -13,11 +13,13 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::ty::TyCtxt; pub fn test_inferred_outlives<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.hir.krate().visit_all_item_likes(&mut OutlivesTest { tcx }); + tcx.hir + .krate() + .visit_all_item_likes(&mut OutlivesTest { tcx }); } struct OutlivesTest<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx> + tcx: TyCtxt<'a, 'tcx, 'tcx>, } impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> { @@ -28,14 +30,16 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> { // attribute and report an error with various results if found. if self.tcx.has_attr(item_def_id, "rustc_outlives") { let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id); - span_err!(self.tcx.sess, - item.span, - E0640, - "{:?}", - inferred_outlives_of); + span_err!( + self.tcx.sess, + item.span, + E0640, + "{:?}", + inferred_outlives_of + ); } } - fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) { } - fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { } + fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {} + fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {} } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index a87e1df5efc..888148352c7 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -260,7 +260,9 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { P(hir::Path { span: DUMMY_SP, def: Def::TyParam(param.def_id), - segments: HirVec::from_vec(vec![hir::PathSegment::from_name(param.name)]), + segments: HirVec::from_vec(vec![ + hir::PathSegment::from_name(Symbol::intern(¶m.name)) + ]), }), )), span: DUMMY_SP, @@ -1435,9 +1437,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { // involved (impls rarely have more than a few bounds) means that it // shouldn't matter in practice. fn unstable_debug_sort<T: Debug>(&self, vec: &mut Vec<T>) { - vec.sort_unstable_by(|first, second| { - format!("{:?}", first).cmp(&format!("{:?}", second)) - }); + vec.sort_by_cached_key(|x| format!("{:?}", x)) } fn is_fn_ty(&self, tcx: &TyCtxt, ty: &Type) -> bool { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b57c9589afa..da8085d84c3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -27,7 +27,7 @@ use syntax::codemap::{dummy_spanned, Spanned}; use syntax::feature_gate::UnstableFeatures; use syntax::ptr::P; use syntax::symbol::keywords; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, InternedString}; use syntax_pos::{self, DUMMY_SP, Pos, FileName}; use rustc::middle::const_val::ConstVal; @@ -1787,7 +1787,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics, // predicates field (see rustc_typeck::collect::ty_generics), so remove // them. let stripped_typarams = gens.types.iter().filter_map(|tp| { - if tp.name == keywords::SelfType.name() { + if tp.name == keywords::SelfType.name().as_str() { assert_eq!(tp.index, 0); None } else { @@ -3367,6 +3367,12 @@ impl Clean<String> for ast::Name { } } +impl Clean<String> for InternedString { + fn clean(&self, _: &DocContext) -> String { + self.to_string() + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Typedef { pub type_: Type, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 72c4c4e4495..9e2c7bd7ef1 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1087,7 +1087,8 @@ impl<'a> SourceCollector<'a> { href.push_str(component); href.push('/'); }); - let mut fname = p.file_name().expect("source has no filename") + let mut fname = p.file_name() + .expect("source has no filename") .to_os_string(); fname.push(".html"); cur.push(&fname); @@ -1373,6 +1374,135 @@ impl<'a> Cache { } } +#[derive(Debug, Eq, PartialEq, Hash)] +struct ItemEntry { + url: String, + name: String, +} + +impl ItemEntry { + fn new(mut url: String, name: String) -> ItemEntry { + while url.starts_with('/') { + url.remove(0); + } + ItemEntry { + url, + name, + } + } +} + +impl fmt::Display for ItemEntry { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "<a href='{}'>{}</a>", self.url, Escape(&self.name)) + } +} + +impl PartialOrd for ItemEntry { + fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for ItemEntry { + fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering { + self.name.cmp(&other.name) + } +} + +#[derive(Debug)] +struct AllTypes { + structs: HashSet<ItemEntry>, + enums: HashSet<ItemEntry>, + unions: HashSet<ItemEntry>, + primitives: HashSet<ItemEntry>, + traits: HashSet<ItemEntry>, + macros: HashSet<ItemEntry>, + functions: HashSet<ItemEntry>, + typedefs: HashSet<ItemEntry>, + statics: HashSet<ItemEntry>, + constants: HashSet<ItemEntry>, +} + +impl AllTypes { + fn new() -> AllTypes { + AllTypes { + structs: HashSet::with_capacity(100), + enums: HashSet::with_capacity(100), + unions: HashSet::with_capacity(100), + primitives: HashSet::with_capacity(26), + traits: HashSet::with_capacity(100), + macros: HashSet::with_capacity(100), + functions: HashSet::with_capacity(100), + typedefs: HashSet::with_capacity(100), + statics: HashSet::with_capacity(100), + constants: HashSet::with_capacity(100), + } + } + + fn append(&mut self, item_name: String, item_type: &ItemType) { + let mut url: Vec<_> = item_name.split("::").skip(1).collect(); + if let Some(name) = url.pop() { + let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name); + url.push(name); + let name = url.join("::"); + match *item_type { + ItemType::Struct => self.structs.insert(ItemEntry::new(new_url, name)), + ItemType::Enum => self.enums.insert(ItemEntry::new(new_url, name)), + ItemType::Union => self.unions.insert(ItemEntry::new(new_url, name)), + ItemType::Primitive => self.primitives.insert(ItemEntry::new(new_url, name)), + ItemType::Trait => self.traits.insert(ItemEntry::new(new_url, name)), + ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)), + ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)), + ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)), + ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)), + ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)), + _ => true, + }; + } + } +} + +fn print_entries(f: &mut fmt::Formatter, e: &HashSet<ItemEntry>, title: &str, + class: &str) -> fmt::Result { + if !e.is_empty() { + let mut e: Vec<&ItemEntry> = e.iter().collect(); + e.sort(); + write!(f, "<h3 id='{}'>{}</h3><ul class='{} docblock'>{}</ul>", + title, + Escape(title), + class, + e.iter().map(|s| format!("<li>{}</li>", s)).collect::<String>())?; + } + Ok(()) +} + +impl fmt::Display for AllTypes { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, +"<h1 class='fqn'>\ + <span class='in-band'>List of all items</span>\ + <span class='out-of-band'>\ + <span id='render-detail'>\ + <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" title=\"collapse all docs\">\ + [<span class='inner'>−</span>]\ + </a>\ + </span> + </span> +</h1>")?; + print_entries(f, &self.structs, "Structs", "structs")?; + print_entries(f, &self.enums, "Enums", "enums")?; + print_entries(f, &self.unions, "Unions", "unions")?; + print_entries(f, &self.primitives, "Primitives", "primitives")?; + print_entries(f, &self.traits, "Traits", "traits")?; + print_entries(f, &self.macros, "Macros", "macros")?; + print_entries(f, &self.functions, "Functions", "functions")?; + print_entries(f, &self.typedefs, "Typedefs", "typedefs")?; + print_entries(f, &self.statics, "Statics", "statics")?; + print_entries(f, &self.constants, "Constants", "constants") + } +} + impl Context { /// String representation of how to get back to the root path of the 'doc/' /// folder in terms of a relative URL. @@ -1414,16 +1544,52 @@ impl Context { Some(i) => i, None => return Ok(()), }; + let final_file = self.dst.join(&krate.name) + .join("all.html"); + let crate_name = krate.name.clone(); item.name = Some(krate.name); - // Render the crate documentation - let mut work = vec![(self, item)]; + let mut all = AllTypes::new(); - while let Some((mut cx, item)) = work.pop() { - cx.item(item, |cx, item| { - work.push((cx.clone(), item)) - })? + { + // Render the crate documentation + let mut work = vec![(self.clone(), item)]; + + while let Some((mut cx, item)) = work.pop() { + cx.item(item, &mut all, |cx, item| { + work.push((cx.clone(), item)) + })? + } } + + let mut w = BufWriter::new(try_err!(File::create(&final_file), &final_file)); + let mut root_path = self.dst.to_str().expect("invalid path").to_owned(); + if !root_path.ends_with('/') { + root_path.push('/'); + } + let page = layout::Page { + title: "List of all items in this crate", + css_class: "mod", + root_path: "../", + description: "List of all items in this crate", + keywords: BASIC_KEYWORDS, + resource_suffix: &self.shared.resource_suffix, + }; + let sidebar = if let Some(ref version) = cache().crate_version { + format!("<p class='location'>Crate {}</p>\ + <div class='block version'>\ + <p>Version {}</p>\ + </div>\ + <a id='all-types' href='index.html'><p>Back to index</p></a>", + crate_name, version) + } else { + String::new() + }; + try_err!(layout::render(&mut w, &self.shared.layout, + &page, &sidebar, &all, + self.shared.css_file_extension.is_some(), + &self.shared.themes), + &final_file); Ok(()) } @@ -1496,8 +1662,8 @@ impl Context { /// all sub-items which need to be rendered. /// /// The rendering driver uses this closure to queue up more work. - fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where - F: FnMut(&mut Context, clean::Item), + fn item<F>(&mut self, item: clean::Item, all: &mut AllTypes, mut f: F) -> Result<(), Error> + where F: FnMut(&mut Context, clean::Item), { // Stripped modules survive the rustdoc passes (i.e. `strip-private`) // if they contain impls for public types. These modules can also @@ -1544,7 +1710,7 @@ impl Context { } for item in m.items { - f(this,item); + f(this, item); } Ok(()) @@ -1562,13 +1728,14 @@ impl Context { let mut dst = try_err!(File::create(&joint_dst), &joint_dst); try_err!(dst.write_all(&buf), &joint_dst); + all.append(full_path(self, &item), &item_type); // Redirect from a sane URL using the namespace to Rustdoc's // URL for the page. let redir_name = format!("{}.{}.html", name, item_type.name_space()); let redir_dst = self.dst.join(redir_name); if let Ok(redirect_out) = OpenOptions::new().create_new(true) - .write(true) - .open(&redir_dst) { + .write(true) + .open(&redir_dst) { let mut redirect_out = BufWriter::new(redirect_out); try_err!(layout::redirect(&mut redirect_out, file_name), &redir_dst); } @@ -1730,11 +1897,12 @@ impl<'a> fmt::Display for Item<'a> { version)?; } write!(fmt, - r##"<span id='render-detail'> - <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> - [<span class='inner'>−</span>] - </a> - </span>"##)?; + "<span id='render-detail'>\ + <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \ + title=\"collapse all docs\">\ + [<span class='inner'>−</span>]\ + </a>\ + </span>")?; // Write `src` tag // @@ -3567,24 +3735,23 @@ impl<'a> fmt::Display for Sidebar<'a> { if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union() || it.is_enum() || it.is_mod() || it.is_typedef() { - write!(fmt, "<p class='location'>")?; - match it.inner { - clean::StructItem(..) => write!(fmt, "Struct ")?, - clean::TraitItem(..) => write!(fmt, "Trait ")?, - clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, - clean::UnionItem(..) => write!(fmt, "Union ")?, - clean::EnumItem(..) => write!(fmt, "Enum ")?, - clean::TypedefItem(..) => write!(fmt, "Type Definition ")?, - clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?, - clean::ModuleItem(..) => if it.is_crate() { - write!(fmt, "Crate ")?; - } else { - write!(fmt, "Module ")?; + write!(fmt, "<p class='location'>{}{}</p>", + match it.inner { + clean::StructItem(..) => "Struct ", + clean::TraitItem(..) => "Trait ", + clean::PrimitiveItem(..) => "Primitive Type ", + clean::UnionItem(..) => "Union ", + clean::EnumItem(..) => "Enum ", + clean::TypedefItem(..) => "Type Definition ", + clean::ForeignTypeItem => "Foreign Type ", + clean::ModuleItem(..) => if it.is_crate() { + "Crate " + } else { + "Module " + }, + _ => "", }, - _ => (), - } - write!(fmt, "{}", it.name.as_ref().unwrap())?; - write!(fmt, "</p>")?; + it.name.as_ref().unwrap())?; } if it.is_crate() { @@ -3592,8 +3759,10 @@ impl<'a> fmt::Display for Sidebar<'a> { write!(fmt, "<div class='block version'>\ <p>Version {}</p>\ - </div>", - version)?; + </div> + <a id='all-types' href='all.html'><p>See all {}'s items</p></a>", + version, + it.name.as_ref().unwrap())?; } } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index f4918033c8e..4c6c8dcfdda 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1294,3 +1294,21 @@ kbd { font-size: 19px; display: block; } + +#main > ul { + padding-left: 10px; +} +#main > ul > li { + list-style: none; +} +#all-types { + text-align: center; + border: 1px solid; + margin: 0 10px; + margin-bottom: 10px; + display: block; + border-radius: 7px; +} +#all-types > p { + margin: 5px 0; +} \ No newline at end of file diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 09776569f80..93971a205bf 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -389,3 +389,10 @@ kbd { background: #f0f0f0; } } + +#all-types { + background-color: #505050; +} +#all-types:hover { + background-color: #606060; +} diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 2334a272855..e13818b4bd2 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -383,3 +383,10 @@ kbd { background: #fff; } } + +#all-types { + background-color: #fff; +} +#all-types:hover { + background-color: #f9f9f9; +} \ No newline at end of file diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 42e87f88fd4..8463475afab 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -12,7 +12,6 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] -#![deny(warnings)] #![feature(ascii_ctype)] #![feature(rustc_private)] @@ -20,8 +19,8 @@ #![feature(box_syntax)] #![feature(fs_read_write)] #![feature(set_stdio)] +#![feature(slice_sort_by_cached_key)] #![feature(test)] -#![feature(unicode)] #![feature(vec_remove_item)] #![feature(entry_and_modify)] @@ -42,7 +41,6 @@ extern crate serialize; #[macro_use] extern crate syntax; extern crate syntax_pos; extern crate test as testing; -extern crate std_unicode; #[macro_use] extern crate log; extern crate rustc_errors as errors; extern crate pulldown_cmark; diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index f78eed30694..22d27b6697a 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -19,7 +19,6 @@ Core encoding and decoding interfaces. html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] #![feature(box_syntax)] #![feature(core_intrinsics)] diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs new file mode 100644 index 00000000000..ff578ec42d2 --- /dev/null +++ b/src/libstd/alloc.rs @@ -0,0 +1,121 @@ +// 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. + +//! dox + +#![unstable(issue = "32838", feature = "allocator_api")] + +#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; +#[doc(inline)] pub use alloc_crate::alloc::Global; +#[doc(inline)] pub use alloc_system::System; +#[doc(inline)] pub use core::alloc::*; + +#[cfg(not(test))] +#[doc(hidden)] +#[allow(unused_attributes)] +pub mod __default_lib_allocator { + use super::{System, Layout, GlobalAlloc, Opaque}; + // for symbol names src/librustc/middle/allocator.rs + // for signatures src/librustc_allocator/lib.rs + + // linkage directives are provided as part of the current compiler allocator + // ABI + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + System.alloc(layout) as *mut u8 + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_oom() -> ! { + System.oom() + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, + size: usize, + align: usize) { + System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align)) + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_realloc(ptr: *mut u8, + old_size: usize, + align: usize, + new_size: usize) -> *mut u8 { + let old_layout = Layout::from_size_align_unchecked(old_size, align); + System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8 + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 { + let layout = Layout::from_size_align_unchecked(size, align); + System.alloc_zeroed(layout) as *mut u8 + } + + #[cfg(stage0)] + pub mod stage0 { + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_usable_size(_layout: *const u8, + _min: *mut usize, + _max: *mut usize) { + unimplemented!() + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_alloc_excess(_size: usize, + _align: usize, + _excess: *mut usize, + _err: *mut u8) -> *mut u8 { + unimplemented!() + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_realloc_excess(_ptr: *mut u8, + _old_size: usize, + _old_align: usize, + _new_size: usize, + _new_align: usize, + _excess: *mut usize, + _err: *mut u8) -> *mut u8 { + unimplemented!() + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_grow_in_place(_ptr: *mut u8, + _old_size: usize, + _old_align: usize, + _new_size: usize, + _new_align: usize) -> u8 { + unimplemented!() + } + + #[no_mangle] + #[rustc_std_internal_symbol] + pub unsafe extern fn __rdl_shrink_in_place(_ptr: *mut u8, + _old_size: usize, + _old_align: usize, + _new_size: usize, + _new_align: usize) -> u8 { + unimplemented!() + } + + } +} diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index e0b48e565d0..20a4f9b508d 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,10 +11,8 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::heap::Heap; -use alloc::allocator::CollectionAllocErr; +use alloc::{Global, Alloc, CollectionAllocErr}; use cell::Cell; -use core::heap::Alloc; use borrow::Borrow; use cmp::max; use fmt::{self, Debug}; @@ -786,7 +784,7 @@ impl<K, V, S> HashMap<K, V, S> pub fn reserve(&mut self, additional: usize) { match self.try_reserve(additional) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e), + Err(CollectionAllocErr::AllocErr) => Global.oom(), Ok(()) => { /* yay */ } } } @@ -3636,7 +3634,7 @@ mod test_map { if let Err(CapacityOverflow) = empty_bytes.try_reserve(max_no_ovf) { } else { panic!("isize::MAX + 1 should trigger a CapacityOverflow!") } } else { - if let Err(AllocErr(_)) = empty_bytes.try_reserve(max_no_ovf) { + if let Err(AllocErr) = empty_bytes.try_reserve(max_no_ovf) { } else { panic!("isize::MAX + 1 should trigger an OOM!") } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index fa6053d3f6d..93f059076d7 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::heap::Heap; -use core::heap::{Alloc, Layout}; - +use alloc::{Global, Alloc, Layout, CollectionAllocErr}; use cmp; use hash::{BuildHasher, Hash, Hasher}; use marker; @@ -18,7 +16,6 @@ use mem::{align_of, size_of, needs_drop}; use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique, NonNull}; -use alloc::allocator::CollectionAllocErr; use self::BucketState::*; @@ -757,15 +754,13 @@ impl<K, V> RawTable<K, V> { return Err(CollectionAllocErr::CapacityOverflow); } - let buffer = Heap.alloc(Layout::from_size_align(size, alignment) - .ok_or(CollectionAllocErr::CapacityOverflow)?)?; - - let hashes = buffer as *mut HashUint; + let buffer = Global.alloc(Layout::from_size_align(size, alignment) + .map_err(|_| CollectionAllocErr::CapacityOverflow)?)?; Ok(RawTable { capacity_mask: capacity.wrapping_sub(1), size: 0, - hashes: TaggedHashUintPtr::new(hashes), + hashes: TaggedHashUintPtr::new(buffer.cast().as_ptr()), marker: marker::PhantomData, }) } @@ -775,7 +770,7 @@ impl<K, V> RawTable<K, V> { unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> { match Self::try_new_uninitialized(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e), + Err(CollectionAllocErr::AllocErr) => Global.oom(), Ok(table) => { table } } } @@ -814,7 +809,7 @@ impl<K, V> RawTable<K, V> { pub fn new(capacity: usize) -> RawTable<K, V> { match Self::try_new(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr(e)) => Heap.oom(e), + Err(CollectionAllocErr::AllocErr) => Global.oom(), Ok(table) => { table } } } @@ -1188,8 +1183,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> { debug_assert!(!oflo, "should be impossible"); unsafe { - Heap.dealloc(self.hashes.ptr() as *mut u8, - Layout::from_size_align(size, align).unwrap()); + Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), + Layout::from_size_align(size, align).unwrap()); // Remember how everything was allocated out of one buffer // during initialization? We only need one call to free here. } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index c7ad27d8d26..9cf73824dea 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -424,13 +424,13 @@ #[doc(hidden)] pub use ops::Bound; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{BinaryHeap, BTreeMap, BTreeSet}; +pub use alloc_crate::{BinaryHeap, BTreeMap, BTreeSet}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{LinkedList, VecDeque}; +pub use alloc_crate::{LinkedList, VecDeque}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{binary_heap, btree_map, btree_set}; +pub use alloc_crate::{binary_heap, btree_map, btree_set}; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::{linked_list, vec_deque}; +pub use alloc_crate::{linked_list, vec_deque}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_map::HashMap; @@ -446,7 +446,7 @@ pub mod range { } #[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub use alloc::allocator::CollectionAllocErr; +pub use heap::CollectionAllocErr; mod hash; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 3d0c96585b5..3c209928d43 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -51,13 +51,13 @@ // coherence challenge (e.g., specialization, neg impls, etc) we can // reconsider what crate these items belong in. -use alloc::allocator; use any::TypeId; use borrow::Cow; use cell; use char; use core::array; use fmt::{self, Debug, Display}; +use heap::{AllocErr, LayoutErr, CannotReallocInPlace}; use mem::transmute; use num; use str; @@ -241,18 +241,27 @@ impl Error for ! { #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838")] -impl Error for allocator::AllocErr { +impl Error for AllocErr { fn description(&self) -> &str { - allocator::AllocErr::description(self) + "memory allocation failed" } } #[unstable(feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838")] -impl Error for allocator::CannotReallocInPlace { +impl Error for LayoutErr { fn description(&self) -> &str { - allocator::CannotReallocInPlace::description(self) + "invalid parameters to Layout::from_size_align" + } +} + +#[unstable(feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked.", + issue = "32838")] +impl Error for CannotReallocInPlace { + fn description(&self) -> &str { + CannotReallocInPlace::description(self) } } diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ceb019bc95b..ca39089a958 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -329,6 +329,57 @@ impl f32 { unsafe { intrinsics::fmaf32(self, a, b) } } + /// Calculates Euclidean division, the matching method for `mod_euc`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.mod_euc(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn div_euc(self, rhs: f32) -> f32 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + } + q + } + + /// Calculates the Euclidean modulo (self mod rhs), which is never negative. + /// + /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f32 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.mod_euc(b), 3.0); + /// assert_eq!((-a).mod_euc(b), 1.0); + /// assert_eq!(a.mod_euc(-b), 3.0); + /// assert_eq!((-a).mod_euc(-b), 1.0); + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn mod_euc(self, rhs: f32) -> f32 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 97adf108b73..a9585670ad0 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -315,6 +315,56 @@ impl f64 { unsafe { intrinsics::fmaf64(self, a, b) } } + /// Calculates Euclidean division, the matching method for `mod_euc`. + /// + /// This computes the integer `n` such that + /// `self = n * rhs + self.mod_euc(rhs)`. + /// In other words, the result is `self / rhs` rounded to the integer `n` + /// such that `self >= n * rhs`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn div_euc(self, rhs: f64) -> f64 { + let q = (self / rhs).trunc(); + if self % rhs < 0.0 { + return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } + } + q + } + + /// Calculates the Euclidean modulo (self mod rhs), which is never negative. + /// + /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. + /// + /// ``` + /// #![feature(euclidean_division)] + /// let a: f64 = 7.0; + /// let b = 4.0; + /// assert_eq!(a.mod_euc(b), 3.0); + /// assert_eq!((-a).mod_euc(b), 1.0); + /// assert_eq!(a.mod_euc(-b), 3.0); + /// assert_eq!((-a).mod_euc(-b), 1.0); + /// ``` + #[inline] + #[unstable(feature = "euclidean_division", issue = "49048")] + pub fn mod_euc(self, rhs: f64) -> f64 { + let r = self % rhs; + if r < 0.0 { + r + rhs.abs() + } else { + r + } + } + /// Takes the reciprocal (inverse) of a number, `1/x`. /// /// ``` diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs deleted file mode 100644 index 4a391372c3a..00000000000 --- a/src/libstd/heap.rs +++ /dev/null @@ -1,176 +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. - -//! dox - -#![unstable(issue = "32838", feature = "allocator_api")] - -pub use alloc::heap::Heap; -pub use alloc_system::System; -pub use core::heap::*; - -#[cfg(not(test))] -#[doc(hidden)] -#[allow(unused_attributes)] -pub mod __default_lib_allocator { - use super::{System, Layout, Alloc, AllocErr}; - use ptr; - - // for symbol names src/librustc/middle/allocator.rs - // for signatures src/librustc_allocator/lib.rs - - // linkage directives are provided as part of the current compiler allocator - // ABI - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc(layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_oom(err: *const u8) -> ! { - System.oom((*(err as *const AllocErr)).clone()) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, - size: usize, - align: usize) { - System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_usable_size(layout: *const u8, - min: *mut usize, - max: *mut usize) { - let pair = System.usable_size(&*(layout as *const Layout)); - *min = pair.0; - *max = pair.1; - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc(ptr, old_layout, new_layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_zeroed(size: usize, - align: usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_zeroed(layout) { - Ok(p) => p, - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_alloc_excess(size: usize, - align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let layout = Layout::from_size_align_unchecked(size, align); - match System.alloc_excess(layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - excess: *mut usize, - err: *mut u8) -> *mut u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.realloc_excess(ptr, old_layout, new_layout) { - Ok(p) => { - *excess = p.1; - p.0 - } - Err(e) => { - ptr::write(err as *mut AllocErr, e); - 0 as *mut u8 - } - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.grow_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(_) => 0, - } - } - - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize) -> u8 { - let old_layout = Layout::from_size_align_unchecked(old_size, old_align); - let new_layout = Layout::from_size_align_unchecked(new_size, new_align); - match System.shrink_in_place(ptr, old_layout, new_layout) { - Ok(()) => 1, - Err(_) => 0, - } - } -} diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 3b8c42ddb39..b02e133ee4d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1829,7 +1829,6 @@ impl<T> Take<T> { /// # Examples /// /// ```no_run - /// #![feature(take_set_limit)] /// use std::io; /// use std::io::prelude::*; /// use std::fs::File; @@ -1845,7 +1844,7 @@ impl<T> Take<T> { /// Ok(()) /// } /// ``` - #[unstable(feature = "take_set_limit", issue = "42781")] + #[stable(feature = "take_set_limit", since = "1.27.0")] pub fn set_limit(&mut self, limit: u64) { self.limit = limit; } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3227aa9acff..a34fcb5a7f9 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -227,10 +227,6 @@ // Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] -// Turn warnings into errors, but only after stage0, where it can be useful for -// code to emit warnings during language transitions -#![cfg_attr(not(stage0), deny(warnings))] - // std may use features in a platform-specific way #![allow(unused_features)] @@ -279,6 +275,7 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] +#![feature(nonnull_cast)] #![feature(exhaustive_patterns)] #![feature(nonzero)] #![feature(num_bits_bytes)] @@ -311,7 +308,6 @@ #![feature(toowned_clone_into)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(unicode)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_push_all)] @@ -356,9 +352,8 @@ extern crate core as __core; #[macro_use] #[macro_reexport(vec, format)] -extern crate alloc; +extern crate alloc as alloc_crate; extern crate alloc_system; -extern crate std_unicode; #[doc(masked)] extern crate libc; @@ -443,23 +438,23 @@ pub use core::u32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::u64; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::boxed; +pub use alloc_crate::boxed; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::rc; +pub use alloc_crate::rc; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::borrow; +pub use alloc_crate::borrow; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::fmt; +pub use alloc_crate::fmt; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::slice; +pub use alloc_crate::slice; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::str; +pub use alloc_crate::str; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::string; +pub use alloc_crate::string; #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::vec; +pub use alloc_crate::vec; #[stable(feature = "rust1", since = "1.0.0")] -pub use std_unicode::char; +pub use core::char; #[stable(feature = "i128", since = "1.26.0")] pub use core::u128; @@ -483,7 +478,14 @@ pub mod path; pub mod process; pub mod sync; pub mod time; -pub mod heap; +pub mod alloc; + +#[unstable(feature = "allocator_api", issue = "32838")] +#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] +/// Use the `alloc` module instead. +pub mod heap { + pub use alloc::*; +} // Platform-abstraction modules #[macro_use] diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index 289b47b3484..642b284c6c7 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -18,7 +18,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::arc::{Arc, Weak}; +pub use alloc_crate::arc::{Arc, Weak}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::sync::atomic; diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 296773d20f6..df945ac3859 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -23,10 +23,9 @@ pub use self::PopResult::*; -use alloc::boxed::Box; use core::ptr; use core::cell::UnsafeCell; - +use boxed::Box; use sync::atomic::{AtomicPtr, Ordering}; /// A result of the `pop` function. diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index cc4be92276a..9482f6958b3 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -16,7 +16,7 @@ // http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue -use alloc::boxed::Box; +use boxed::Box; use core::ptr; use core::cell::UnsafeCell; diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index a22d9053b69..5d66936b2a4 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use cmp; use ffi::CStr; use io; diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index da27787babb..eb3a1ead58c 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index f20350269b7..110d46ca3ab 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use ffi::CStr; use io; use mem; diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index e43bc6da5f1..01c0fb830aa 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 2db3d4a5744..9e388808030 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use cmp; use ffi::CStr; use io; diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs index 84f560af69b..e0da5bdf36c 100644 --- a/src/libstd/sys/wasm/os_str.rs +++ b/src/libstd/sys/wasm/os_str.rs @@ -19,7 +19,7 @@ use rc::Rc; use sync::Arc; use sys_common::{AsInner, IntoInner}; use sys_common::bytestring::debug_fmt_bytestring; -use std_unicode::lossy::Utf8Lossy; +use core::str::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 7345843b975..728e678a2e8 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use ffi::CStr; use io; use sys::{unsupported, Void}; diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index bd5507e8f89..be442f41374 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -31,7 +31,7 @@ use sys::stdio; use sys::cvt; use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::process::{CommandEnv, EnvKey}; -use alloc::borrow::Borrow; +use borrow::Borrow; //////////////////////////////////////////////////////////////////////////////// // Command diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 4b3d1b586b5..b6f63303dc2 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use io; use ffi::CStr; use mem; diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs index ce6fd4cb075..26da51c9825 100644 --- a/src/libstd/sys_common/at_exit_imp.rs +++ b/src/libstd/sys_common/at_exit_imp.rs @@ -12,7 +12,7 @@ //! //! Documentation can be found on the `rt::at_exit` function. -use alloc::boxed::FnBox; +use boxed::FnBox; use ptr; use sys_common::mutex::Mutex; diff --git a/src/libstd/sys_common/bytestring.rs b/src/libstd/sys_common/bytestring.rs index eb9cad09915..971b83938c1 100644 --- a/src/libstd/sys_common/bytestring.rs +++ b/src/libstd/sys_common/bytestring.rs @@ -11,7 +11,7 @@ #![allow(dead_code)] use fmt::{Formatter, Result, Write}; -use std_unicode::lossy::{Utf8Lossy, Utf8LossyChunk}; +use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter) -> Result { // Writes out a valid unicode string with the correct escape sequences diff --git a/src/libstd/sys_common/process.rs b/src/libstd/sys_common/process.rs index d0c5951bd6c..ddf0ebe603e 100644 --- a/src/libstd/sys_common/process.rs +++ b/src/libstd/sys_common/process.rs @@ -14,7 +14,7 @@ use ffi::{OsStr, OsString}; use env; use collections::BTreeMap; -use alloc::borrow::Borrow; +use borrow::Borrow; pub trait EnvKey: From<OsString> + Into<OsString> + diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs index f1379b6ec63..da6f58ef6bb 100644 --- a/src/libstd/sys_common/thread.rs +++ b/src/libstd/sys_common/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::boxed::FnBox; +use boxed::FnBox; use env; use sync::atomic::{self, Ordering}; use sys::stack_overflow; diff --git a/src/libstd_unicode/Cargo.toml b/src/libstd_unicode/Cargo.toml index 283070a0e2c..b1c55c2e4b6 100644 --- a/src/libstd_unicode/Cargo.toml +++ b/src/libstd_unicode/Cargo.toml @@ -9,10 +9,6 @@ path = "lib.rs" test = false bench = false -[[test]] -name = "std_unicode_tests" -path = "tests/lib.rs" - [dependencies] core = { path = "../libcore" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index c22ea1671fa..c0d47f1fcb4 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -27,39 +27,10 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] -#![deny(warnings)] -#![deny(missing_debug_implementations)] #![no_std] -#![feature(ascii_ctype)] -#![feature(core_char_ext)] -#![feature(str_internals)] -#![feature(decode_utf8)] -#![feature(fn_traits)] -#![feature(lang_items)] -#![feature(non_exhaustive)] +#![feature(unicode_internals)] #![feature(staged_api)] -#![feature(unboxed_closures)] +#![rustc_deprecated(since = "1.27.0", reason = "moved into libcore")] -mod bool_trie; -mod tables; -mod u_str; -mod version; -pub mod char; -pub mod lossy; - -#[allow(deprecated)] -pub mod str { - pub use u_str::{SplitWhitespace, UnicodeStr}; - pub use u_str::Utf16Encoder; -} - -// For use in liballoc, not re-exported in libstd. -pub mod derived_property { - pub use tables::derived_property::{Case_Ignorable, Cased}; -} - -// For use in libsyntax -pub mod property { - pub use tables::property::Pattern_White_Space; -} +pub use core::unicode::*; diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs deleted file mode 100644 index a72e1210d93..00000000000 --- a/src/libstd_unicode/u_str.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2012-2014 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. - -//! Unicode-intensive string manipulations. -//! -//! This module provides functionality to `str` that requires the Unicode -//! methods provided by the unicode parts of the CharExt trait. - -use core::char; -use core::iter::{Filter, FusedIterator}; -use core::str::Split; - -/// An iterator over the non-whitespace substrings of a string, -/// separated by any amount of whitespace. -/// -/// This struct is created by the [`split_whitespace`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace -/// [`str`]: ../../std/primitive.str.html -#[stable(feature = "split_whitespace", since = "1.1.0")] -#[derive(Clone, Debug)] -pub struct SplitWhitespace<'a> { - inner: Filter<Split<'a, IsWhitespace>, IsNotEmpty>, -} - -/// Methods for Unicode string slices -#[allow(missing_docs)] // docs in liballoc -pub trait UnicodeStr { - fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; - fn is_whitespace(&self) -> bool; - fn is_alphanumeric(&self) -> bool; - fn trim(&self) -> &str; - fn trim_left(&self) -> &str; - fn trim_right(&self) -> &str; -} - -impl UnicodeStr for str { - #[inline] - fn split_whitespace(&self) -> SplitWhitespace { - SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } - } - - #[inline] - fn is_whitespace(&self) -> bool { - self.chars().all(|c| c.is_whitespace()) - } - - #[inline] - fn is_alphanumeric(&self) -> bool { - self.chars().all(|c| c.is_alphanumeric()) - } - - #[inline] - fn trim(&self) -> &str { - self.trim_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_left(&self) -> &str { - self.trim_left_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_right(&self) -> &str { - self.trim_right_matches(|c: char| c.is_whitespace()) - } -} - -/// Iterator adaptor for encoding `char`s to UTF-16. -#[derive(Clone)] -#[allow(missing_debug_implementations)] -pub struct Utf16Encoder<I> { - chars: I, - extra: u16, -} - -impl<I> Utf16Encoder<I> { - /// Create a UTF-16 encoder from any `char` iterator. - pub fn new(chars: I) -> Utf16Encoder<I> - where I: Iterator<Item = char> - { - Utf16Encoder { - chars, - extra: 0, - } - } -} - -impl<I> Iterator for Utf16Encoder<I> - where I: Iterator<Item = char> -{ - type Item = u16; - - #[inline] - fn next(&mut self) -> Option<u16> { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; 2]; - self.chars.next().map(|ch| { - let n = CharExt::encode_utf16(ch, &mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - let (low, high) = self.chars.size_hint(); - // every char gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) - } -} - -impl<I> FusedIterator for Utf16Encoder<I> - where I: FusedIterator<Item = char> {} - -#[derive(Clone)] -struct IsWhitespace; - -impl FnOnce<(char, )> for IsWhitespace { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool { - self.call_mut(arg) - } -} - -impl FnMut<(char, )> for IsWhitespace { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool { - arg.0.is_whitespace() - } -} - -#[derive(Clone)] -struct IsNotEmpty; - -impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { - self.call_mut(arg) - } -} - -impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { - !arg.0.is_empty() - } -} - - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> Iterator for SplitWhitespace<'a> { - type Item = &'a str; - - fn next(&mut self) -> Option<&'a str> { - self.inner.next() - } -} - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { - fn next_back(&mut self) -> Option<&'a str> { - self.inner.next_back() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a> FusedIterator for SplitWhitespace<'a> {} diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e7900af7f12..91c9a1524e1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1018,7 +1018,6 @@ impl Expr { ExprKind::Assign(..) => ExprPrecedence::Assign, ExprKind::AssignOp(..) => ExprPrecedence::AssignOp, ExprKind::Field(..) => ExprPrecedence::Field, - ExprKind::TupField(..) => ExprPrecedence::TupField, ExprKind::Index(..) => ExprPrecedence::Index, ExprKind::Range(..) => ExprPrecedence::Range, ExprKind::Path(..) => ExprPrecedence::Path, @@ -1133,12 +1132,8 @@ pub enum ExprKind { /// /// For example, `a += 1`. AssignOp(BinOp, P<Expr>, P<Expr>), - /// Access of a named struct field (`obj.foo`) + /// Access of a named (`obj.foo`) or unnamed (`obj.0`) struct field Field(P<Expr>, Ident), - /// Access of an unnamed field of a struct or tuple-struct - /// - /// For example, `foo.0`. - TupField(P<Expr>, Spanned<usize>), /// An indexing operation (`foo[2]`) Index(P<Expr>, P<Expr>), /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`) diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 2812e1238e9..c68a743303a 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -993,7 +993,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> let word = &*mi.ident.name.as_str(); let hint = match word { "C" => Some(ReprC), - "packed" => Some(ReprPacked), + "packed" => Some(ReprPacked(1)), "simd" => Some(ReprSimd), "transparent" => Some(ReprTransparent), _ => match int_type_of_word(word) { @@ -1009,27 +1009,41 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> acc.push(h); } } else if let Some((name, value)) = item.name_value_literal() { - if name == "align" { - recognised = true; - let mut align_error = None; - if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node { - if align.is_power_of_two() { + let parse_alignment = |node: &ast::LitKind| -> Result<u32, &'static str> { + if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { + if literal.is_power_of_two() { // rustc::ty::layout::Align restricts align to <= 2147483647 - if align <= 2147483647 { - acc.push(ReprAlign(align as u32)); + if *literal <= 2147483647 { + Ok(*literal as u32) } else { - align_error = Some("larger than 2147483647"); + Err("larger than 2147483647") } } else { - align_error = Some("not a power of two"); + Err("not a power of two") } } else { - align_error = Some("not an unsuffixed integer"); - } - if let Some(align_error) = align_error { - span_err!(diagnostic, item.span, E0589, - "invalid `repr(align)` attribute: {}", align_error); + Err("not an unsuffixed integer") } + }; + + let mut literal_error = None; + if name == "align" { + recognised = true; + match parse_alignment(&value.node) { + Ok(literal) => acc.push(ReprAlign(literal)), + Err(message) => literal_error = Some(message) + }; + } + else if name == "packed" { + recognised = true; + match parse_alignment(&value.node) { + Ok(literal) => acc.push(ReprPacked(literal)), + Err(message) => literal_error = Some(message) + }; + } + if let Some(literal_error) = literal_error { + span_err!(diagnostic, item.span, E0589, + "invalid `repr(align)` attribute: {}", literal_error); } } if !recognised { @@ -1065,7 +1079,7 @@ fn int_type_of_word(s: &str) -> Option<IntType> { pub enum ReprAttr { ReprInt(IntType), ReprC, - ReprPacked, + ReprPacked(u32), ReprSimd, ReprTransparent, ReprAlign(u32), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a09bea25a24..c25a7686bea 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -28,7 +28,7 @@ use std::collections::HashMap; use std::iter; use std::path::PathBuf; use std::rc::Rc; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{self, Lrc}; use std::default::Default; use tokenstream::{self, TokenStream}; @@ -565,26 +565,26 @@ pub enum SyntaxExtension { /// `#[derive(...)]` is a `MultiItemDecorator`. /// /// Prefer ProcMacro or MultiModifier since they are more flexible. - MultiDecorator(Box<MultiItemDecorator>), + MultiDecorator(Box<MultiItemDecorator + sync::Sync + sync::Send>), /// A syntax extension that is attached to an item and modifies it /// in-place. Also allows decoration, i.e., creating new items. - MultiModifier(Box<MultiItemModifier>), + MultiModifier(Box<MultiItemModifier + sync::Sync + sync::Send>), /// A function-like procedural macro. TokenStream -> TokenStream. - ProcMacro(Box<ProcMacro>), + ProcMacro(Box<ProcMacro + sync::Sync + sync::Send>), /// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream. /// The first TokenSteam is the attribute, the second is the annotated item. /// Allows modification of the input items and adding new items, similar to /// MultiModifier, but uses TokenStreams, rather than AST nodes. - AttrProcMacro(Box<AttrProcMacro>), + AttrProcMacro(Box<AttrProcMacro + sync::Sync + sync::Send>), /// A normal, function-like syntax extension. /// /// `bytes!` is a `NormalTT`. NormalTT { - expander: Box<TTMacroExpander>, + expander: Box<TTMacroExpander + sync::Sync + sync::Send>, def_info: Option<(ast::NodeId, Span)>, /// Whether the contents of the macro can /// directly use `#[unstable]` things (true == yes). @@ -599,13 +599,15 @@ pub enum SyntaxExtension { /// A function-like syntax extension that has an extra ident before /// the block. /// - IdentTT(Box<IdentMacroExpander>, Option<Span>, bool), + IdentTT(Box<IdentMacroExpander + sync::Sync + sync::Send>, Option<Span>, bool), /// An attribute-like procedural macro. TokenStream -> TokenStream. /// The input is the annotated item. /// Allows generating code to implement a Trait for a given struct /// or enum item. - ProcMacroDerive(Box<MultiItemModifier>, Vec<Symbol> /* inert attribute names */), + ProcMacroDerive(Box<MultiItemModifier + + sync::Sync + + sync::Send>, Vec<Symbol> /* inert attribute names */), /// An attribute-like procedural macro that derives a builtin trait. BuiltinDerive(BuiltinDeriveFn), @@ -613,7 +615,7 @@ pub enum SyntaxExtension { /// A declarative macro, e.g. `macro m() {}`. /// /// The second element is the definition site span. - DeclMacro(Box<TTMacroExpander>, Option<(ast::NodeId, Span)>), + DeclMacro(Box<TTMacroExpander + sync::Sync + sync::Send>, Option<(ast::NodeId, Span)>), } impl SyntaxExtension { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 062f3ce1127..36244f0a3c4 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -636,8 +636,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(sp, ast::ExprKind::Field(expr, ident.with_span_pos(sp))) } fn expr_tup_field_access(&self, sp: Span, expr: P<ast::Expr>, idx: usize) -> P<ast::Expr> { - let id = Spanned { node: idx, span: sp }; - self.expr(sp, ast::ExprKind::TupField(expr, id)) + let ident = Ident::from_str(&idx.to_string()).with_span_pos(sp); + self.expr(sp, ast::ExprKind::Field(expr, ident)) } fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> { self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Immutable, e)) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0a3cd66d897..73ebfc20876 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -426,12 +426,18 @@ declare_features! ( // Use `?` as the Kleene "at most one" operator (active, macro_at_most_once_rep, "1.25.0", Some(48075), None), + // Infer outlives requirements; RFC 2093 + (active, infer_outlives_requirements, "1.26.0", Some(44493), None), + // Multiple patterns with `|` in `if let` and `while let` (active, if_while_or_patterns, "1.26.0", Some(48215), None), // Parentheses in patterns (active, pattern_parentheses, "1.26.0", None, None), + // Allows `#[repr(packed)]` attribute on structs + (active, repr_packed, "1.26.0", Some(33158), None), + // `use path as _;` and `extern crate c as _;` (active, underscore_imports, "1.26.0", Some(48216), None), @@ -1020,6 +1026,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "never will be stable", cfg_fn!(rustc_attrs))), + // RFC #2093 + ("infer_outlives_requirements", Normal, Gated(Stability::Unstable, + "infer_outlives_requirements", + "infer outlives requirements is an experimental feature", + cfg_fn!(infer_outlives_requirements))), + ("wasm_custom_section", Whitelisted, Gated(Stability::Unstable, "wasm_custom_section", "attribute is currently unstable", @@ -1439,11 +1451,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - // allow attr_literals in #[repr(align(x))] - let mut is_repr_align = false; + // allow attr_literals in #[repr(align(x))] and #[repr(packed(n))] + let mut allow_attr_literal = false; if attr.path == "repr" { if let Some(content) = attr.meta_item_list() { - is_repr_align = content.iter().any(|c| c.check_name("align")); + allow_attr_literal = content.iter().any( + |c| c.check_name("align") || c.check_name("packed")); } } @@ -1451,7 +1464,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { return } - if !is_repr_align { + if !allow_attr_literal { let meta = panictry!(attr.parse_meta(self.context.parse_sess)); if contains_novel_literal(&meta) { gate_feature_post!(&self, attr_literals, attr.span, @@ -1535,6 +1548,13 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { "the `#[repr(transparent)]` attribute \ is experimental"); } + if let Some((name, _)) = item.name_value_literal() { + if name == "packed" { + gate_feature_post!(&self, repr_packed, attr.span, + "the `#[repr(packed(n))]` attribute \ + is experimental"); + } + } } } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index ba6703b9c74..a0cd831a9ba 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1267,11 +1267,6 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Field(el, ident) => { ExprKind::Field(folder.fold_expr(el), folder.fold_ident(ident)) } - ExprKind::TupField(el, index) => { - ExprKind::TupField(folder.fold_expr(el), - respan(folder.new_span(index.span), - folder.fold_usize(index.node))) - } ExprKind::Index(el, er) => { ExprKind::Index(folder.fold_expr(el), folder.fold_expr(er)) } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index c456dc45d21..ad98e2a6b71 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -18,22 +18,24 @@ html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![deny(warnings)] -#![feature(unicode)] +#![feature(unicode_internals)] #![feature(rustc_diagnostic_macros)] +#![feature(slice_sort_by_cached_key)] #![feature(non_exhaustive)] #![feature(const_atomic_usize_new)] #![feature(rustc_attrs)] +#![recursion_limit="256"] + // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] extern crate rustc_cratesio_shim; #[macro_use] extern crate bitflags; +extern crate core; extern crate serialize; #[macro_use] extern crate log; -extern crate std_unicode; pub extern crate rustc_errors as errors; extern crate syntax_pos; extern crate rustc_data_structures; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 152c4c31eb3..cb3323c7eca 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -15,7 +15,7 @@ use errors::{FatalError, DiagnosticBuilder}; use parse::{token, ParseSess}; use str::char_at; use symbol::{Symbol, keywords}; -use std_unicode::property::Pattern_White_Space; +use core::unicode::property::Pattern_White_Space; use std::borrow::Cow; use std::char; @@ -1781,7 +1781,6 @@ mod tests { use errors; use feature_gate::UnstableFeatures; use parse::token; - use std::cell::RefCell; use std::collections::HashSet; use std::io; use std::path::PathBuf; @@ -1797,12 +1796,12 @@ mod tests { span_diagnostic: errors::Handler::with_emitter(true, false, Box::new(emitter)), unstable_features: UnstableFeatures::from_environment(), config: CrateConfig::new(), - included_mod_stack: RefCell::new(Vec::new()), + included_mod_stack: Lock::new(Vec::new()), code_map: cm, - missing_fragment_specifiers: RefCell::new(HashSet::new()), - raw_identifier_spans: RefCell::new(Vec::new()), + missing_fragment_specifiers: Lock::new(HashSet::new()), + raw_identifier_spans: Lock::new(Vec::new()), registered_diagnostics: Lock::new(ErrorMap::new()), - non_modrs_mods: RefCell::new(vec![]), + non_modrs_mods: Lock::new(vec![]), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 428b3b136df..ff63c9a5c6d 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -23,7 +23,6 @@ use symbol::Symbol; use tokenstream::{TokenStream, TokenTree}; use diagnostics::plugin::ErrorMap; -use std::cell::RefCell; use std::collections::HashSet; use std::iter; use std::path::{Path, PathBuf}; @@ -46,17 +45,17 @@ pub struct ParseSess { pub span_diagnostic: Handler, pub unstable_features: UnstableFeatures, pub config: CrateConfig, - pub missing_fragment_specifiers: RefCell<HashSet<Span>>, + pub missing_fragment_specifiers: Lock<HashSet<Span>>, /// Places where raw identifiers were used. This is used for feature gating /// raw identifiers - pub raw_identifier_spans: RefCell<Vec<Span>>, + pub raw_identifier_spans: Lock<Vec<Span>>, /// The registered diagnostics codes pub registered_diagnostics: Lock<ErrorMap>, // Spans where a `mod foo;` statement was included in a non-mod.rs file. // These are used to issue errors if the non_modrs_mods feature is not enabled. - pub non_modrs_mods: RefCell<Vec<(ast::Ident, Span)>>, + pub non_modrs_mods: Lock<Vec<(ast::Ident, Span)>>, /// Used to determine and report recursive mod inclusions - included_mod_stack: RefCell<Vec<PathBuf>>, + included_mod_stack: Lock<Vec<PathBuf>>, code_map: Lrc<CodeMap>, } @@ -75,12 +74,12 @@ impl ParseSess { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(), config: HashSet::new(), - missing_fragment_specifiers: RefCell::new(HashSet::new()), - raw_identifier_spans: RefCell::new(Vec::new()), + missing_fragment_specifiers: Lock::new(HashSet::new()), + raw_identifier_spans: Lock::new(Vec::new()), registered_diagnostics: Lock::new(ErrorMap::new()), - included_mod_stack: RefCell::new(vec![]), + included_mod_stack: Lock::new(vec![]), code_map, - non_modrs_mods: RefCell::new(vec![]), + non_modrs_mods: Lock::new(vec![]), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e6da5bcaa3a..a7a9ce74512 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -689,7 +689,7 @@ impl<'a> Parser<'a> { .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) .chain(self.expected_tokens.iter().cloned()) .collect::<Vec<_>>(); - expected.sort_by(|a, b| a.to_string().cmp(&b.to_string())); + expected.sort_by_cached_key(|x| x.to_string()); expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); @@ -2144,10 +2144,6 @@ impl<'a> Parser<'a> { } } - pub fn mk_tup_field(&mut self, expr: P<Expr>, idx: codemap::Spanned<usize>) -> ast::ExprKind { - ExprKind::TupField(expr, idx) - } - pub fn mk_assign_op(&mut self, binop: ast::BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind { ExprKind::AssignOp(binop, lhs, rhs) @@ -2605,35 +2601,11 @@ impl<'a> Parser<'a> { token::Ident(..) => { e = self.parse_dot_suffix(e, lo)?; } - token::Literal(token::Integer(index_ident), suf) => { - let sp = self.span; - - // A tuple index may not have a suffix - self.expect_no_suffix(sp, "tuple index", suf); - - let idx_span = self.span; + token::Literal(token::Integer(name), _) => { + let span = self.span; self.bump(); - - let invalid_msg = "invalid tuple or struct index"; - - let index = index_ident.as_str().parse::<usize>().ok(); - match index { - Some(n) => { - if n.to_string() != index_ident.as_str() { - let mut err = self.struct_span_err(self.prev_span, invalid_msg); - err.span_suggestion(self.prev_span, - "try simplifying the index", - n.to_string()); - err.emit(); - } - let field = self.mk_tup_field(e, respan(idx_span, n)); - e = self.mk_expr(lo.to(idx_span), field, ThinVec::new()); - } - None => { - let prev_span = self.prev_span; - self.span_err(prev_span, invalid_msg); - } - } + let field = ExprKind::Field(e, Ident::new(name, span)); + e = self.mk_expr(lo.to(span), field, ThinVec::new()); } token::Literal(token::Float(n), _suf) => { self.bump(); @@ -2830,7 +2802,48 @@ impl<'a> Parser<'a> { let (span, e) = self.interpolated_or_expr_span(e)?; (lo.to(span), ExprKind::Box(e)) } - _ => return self.parse_dot_or_call_expr(Some(attrs)) + token::Ident(..) if self.token.is_ident_named("not") => { + // `not` is just an ordinary identifier in Rust-the-language, + // but as `rustc`-the-compiler, we can issue clever diagnostics + // for confused users who really want to say `!` + let token_cannot_continue_expr = |t: &token::Token| match *t { + // These tokens can start an expression after `!`, but + // can't continue an expression after an ident + token::Ident(ident, is_raw) => token::ident_can_begin_expr(ident, is_raw), + token::Literal(..) | token::Pound => true, + token::Interpolated(ref nt) => match nt.0 { + token::NtIdent(..) | token::NtExpr(..) | + token::NtBlock(..) | token::NtPath(..) => true, + _ => false, + }, + _ => false + }; + let cannot_continue_expr = self.look_ahead(1, token_cannot_continue_expr); + if cannot_continue_expr { + self.bump(); + // Emit the error ... + let mut err = self.diagnostic() + .struct_span_err(self.span, + &format!("unexpected {} after identifier", + self.this_token_descr())); + // span the `not` plus trailing whitespace to avoid + // trailing whitespace after the `!` in our suggestion + let to_replace = self.sess.codemap() + .span_until_non_whitespace(lo.to(self.span)); + err.span_suggestion_short(to_replace, + "use `!` to perform logical negation", + "!".to_owned()); + err.emit(); + // —and recover! (just as if we were in the block + // for the `token::Not` arm) + let e = self.parse_prefix_expr(None); + let (span, e) = self.interpolated_or_expr_span(e)?; + (lo.to(span), self.mk_unary(UnOp::Not, e)) + } else { + return self.parse_dot_or_call_expr(Some(attrs)); + } + } + _ => { return self.parse_dot_or_call_expr(Some(attrs)); } }; return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } @@ -4486,6 +4499,11 @@ impl<'a> Parser<'a> { // Which is valid in other languages, but not Rust. match self.parse_stmt_without_recovery(false) { Ok(Some(stmt)) => { + if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) { + // if the next token is an open brace (e.g., `if a b {`), the place- + // inside-a-block suggestion would be more likely wrong than right + return Err(e); + } let mut stmt_span = stmt.span; // expand the span to include the semicolon, if it exists if self.eat(&token::Semi) { @@ -7012,7 +7030,7 @@ impl<'a> Parser<'a> { match self.token { token::Ident(ident, false) if ident.name == keywords::Underscore.name() => { self.bump(); // `_` - Ok(Some(Ident { name: ident.name.gensymed(), ..ident })) + Ok(Some(Ident::new(ident.name.gensymed(), ident.span))) } _ => self.parse_ident().map(Some), } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 6544619af9c..8da79f92768 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -25,9 +25,8 @@ use syntax_pos::{self, Span, FileName}; use tokenstream::{TokenStream, TokenTree}; use tokenstream; -use std::cell::Cell; use std::{cmp, fmt}; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{Lrc, Lock}; #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] pub enum BinOpToken { @@ -91,7 +90,7 @@ impl Lit { } } -fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool { +pub(crate) fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool { let ident_token: Token = Ident(ident, is_raw); !ident_token.is_reserved_ident() || @@ -348,6 +347,15 @@ impl Token { self.lifetime().is_some() } + /// Returns `true` if the token is a identifier whose name is the given + /// string slice. + pub fn is_ident_named(&self, name: &str) -> bool { + match self.ident() { + Some((ident, _)) => ident.name.as_str() == name, + None => false + } + } + /// Returns `true` if the token is a documentation comment. pub fn is_doc_comment(&self) -> bool { match *self { @@ -618,15 +626,8 @@ pub fn is_op(tok: &Token) -> bool { } } -pub struct LazyTokenStream(Cell<Option<TokenStream>>); - -impl Clone for LazyTokenStream { - fn clone(&self) -> Self { - let opt_stream = self.0.take(); - self.0.set(opt_stream.clone()); - LazyTokenStream(Cell::new(opt_stream)) - } -} +#[derive(Clone)] +pub struct LazyTokenStream(Lock<Option<TokenStream>>); impl cmp::Eq for LazyTokenStream {} impl PartialEq for LazyTokenStream { @@ -643,15 +644,14 @@ impl fmt::Debug for LazyTokenStream { impl LazyTokenStream { pub fn new() -> Self { - LazyTokenStream(Cell::new(None)) + LazyTokenStream(Lock::new(None)) } pub fn force<F: FnOnce() -> TokenStream>(&self, f: F) -> TokenStream { - let mut opt_stream = self.0.take(); + let mut opt_stream = self.0.lock(); if opt_stream.is_none() { - opt_stream = Some(f()); + *opt_stream = Some(f()); } - self.0.set(opt_stream.clone()); opt_stream.clone().unwrap() } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8168db19058..3741850b8a9 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1966,8 +1966,7 @@ impl<'a> State<'a> { args: &[P<ast::Expr>]) -> io::Result<()> { let prec = match func.node { - ast::ExprKind::Field(..) | - ast::ExprKind::TupField(..) => parser::PREC_FORCE_PAREN, + ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, _ => parser::PREC_POSTFIX, }; @@ -2203,11 +2202,6 @@ impl<'a> State<'a> { self.s.word(".")?; self.print_ident(ident)?; } - ast::ExprKind::TupField(ref expr, id) => { - self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX)?; - self.s.word(".")?; - self.print_usize(id.node)?; - } ast::ExprKind::Index(ref expr, ref index) => { self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX)?; self.s.word("[")?; diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 4770273e8c4..524f9f127f5 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -251,7 +251,6 @@ pub enum ExprPrecedence { Call, MethodCall, Field, - TupField, Index, Try, InlineAsm, @@ -320,7 +319,6 @@ impl ExprPrecedence { ExprPrecedence::Call | ExprPrecedence::MethodCall | ExprPrecedence::Field | - ExprPrecedence::TupField | ExprPrecedence::Index | ExprPrecedence::Try | ExprPrecedence::InlineAsm | @@ -365,7 +363,6 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { ast::ExprKind::Cast(ref x, _) | ast::ExprKind::Type(ref x, _) | ast::ExprKind::Field(ref x, _) | - ast::ExprKind::TupField(ref x, _) | ast::ExprKind::Index(ref x, _) => { // &X { y: 1 }, X { y: 1 }.y contains_exterior_struct_lit(&x) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index fdb3e2c5f31..8743840e443 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -749,9 +749,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(subexpression); visitor.visit_ident(ident); } - ExprKind::TupField(ref subexpression, _) => { - visitor.visit_expr(subexpression); - } ExprKind::Index(ref main_expression, ref index_expression) => { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 4126ce79f35..66053e037e1 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -413,8 +413,12 @@ impl<'a> TraitDef<'a> { match *item { Annotatable::Item(ref item) => { let is_packed = item.attrs.iter().any(|attr| { - attr::find_repr_attrs(&cx.parse_sess.span_diagnostic, attr) - .contains(&attr::ReprPacked) + for r in attr::find_repr_attrs(&cx.parse_sess.span_diagnostic, attr) { + if let attr::ReprPacked(_) = r { + return true; + } + } + false }); let has_no_type_params = match item.node { ast::ItemKind::Struct(_, ref generics) | @@ -831,7 +835,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> & for a in type_attrs { for r in &attr::find_repr_attrs(diagnostic, a) { repr_type_name = match *r { - attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent => + attr::ReprPacked(_) | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent => continue, attr::ReprC => "i32", diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 249a64b353f..97e34c554d1 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -13,7 +13,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(proc_macro_internals)] #![feature(decl_macro)] diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index c180563450f..8cb5776fdeb 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -432,6 +432,7 @@ pub enum ExpnFormat { pub enum CompilerDesugaringKind { DotFill, QuestionMark, + Catch, } impl CompilerDesugaringKind { @@ -440,6 +441,7 @@ impl CompilerDesugaringKind { let s = match *self { DotFill => "...", QuestionMark => "?", + Catch => "do catch", }; Symbol::intern(s) } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 33428eb271a..9a7d1fd8ee6 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -17,7 +17,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![deny(warnings)] #![feature(const_fn)] #![feature(custom_attribute)] diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index ad0e582b1c3..a012f4e776f 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -46,7 +46,6 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] #![deny(missing_docs)] -#![deny(warnings)] #![cfg_attr(windows, feature(libc))] // Handle rustfmt skips diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index b8be1aeff17..9291eaa910b 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -31,7 +31,6 @@ #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "https://doc.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![deny(warnings)] #![feature(asm)] #![feature(fnbox)] #![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc))] diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs index 5347c781218..2b3c19c067e 100644 --- a/src/libunwind/lib.rs +++ b/src/libunwind/lib.rs @@ -10,7 +10,6 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] -#![deny(warnings)] #![feature(cfg_target_vendor)] #![feature(link_cfg)] diff --git a/src/llvm b/src/llvm -Subproject 6ceaaa4b0176a200e4bbd347d6a991ab6c776ed +Subproject 7243155b1c3da0a980c868a87adebf00e0b3398 diff --git a/src/rustc/dlmalloc_shim/Cargo.toml b/src/rustc/dlmalloc_shim/Cargo.toml index d2fe159d806..b6f8550829f 100644 --- a/src/rustc/dlmalloc_shim/Cargo.toml +++ b/src/rustc/dlmalloc_shim/Cargo.toml @@ -12,4 +12,3 @@ doc = false [dependencies] core = { path = "../../libcore" } compiler_builtins = { path = "../../rustc/compiler_builtins_shim" } -alloc = { path = "../../liballoc" } diff --git a/src/rustc/rustc.rs b/src/rustc/rustc.rs index 9fa33f911a1..a888838ce43 100644 --- a/src/rustc/rustc.rs +++ b/src/rustc/rustc.rs @@ -13,6 +13,7 @@ // Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread // for the rationale. +#[allow(unused_attributes)] #[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")] // We only build for msvc and gnu now, but we use a exhaustive condition here // so we can expect either the stack size to be set or the build fails. diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index c4c0f1ab6e6..c3fc3e5452c 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-03-10 +2018-04-05 diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs index 9c56a316b34..415ee6eb7ea 100644 --- a/src/test/codegen/link_section.rs +++ b/src/test/codegen/link_section.rs @@ -15,8 +15,14 @@ // CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" #[no_mangle] #[link_section = ".test_one"] +#[cfg(target_endian = "little")] pub static VAR1: u32 = 1; +#[no_mangle] +#[link_section = ".test_one"] +#[cfg(target_endian = "big")] +pub static VAR1: u32 = 0x01000000; + pub enum E { A(u32), B(f32) diff --git a/src/test/codegen/packed.rs b/src/test/codegen/packed.rs index 022f581278c..0693eae7d78 100644 --- a/src/test/codegen/packed.rs +++ b/src/test/codegen/packed.rs @@ -11,16 +11,23 @@ // compile-flags: -C no-prepopulate-passes #![crate_type = "lib"] +#![feature(repr_packed)] #[repr(packed)] -pub struct Packed { +pub struct Packed1 { dealign: u8, data: u32 } -// CHECK-LABEL: @write_pkd +#[repr(packed(2))] +pub struct Packed2 { + dealign: u8, + data: u32 +} + +// CHECK-LABEL: @write_pkd1 #[no_mangle] -pub fn write_pkd(pkd: &mut Packed) -> u32 { +pub fn write_pkd1(pkd: &mut Packed1) -> u32 { // CHECK: %{{.*}} = load i32, i32* %{{.*}}, align 1 // CHECK: store i32 42, i32* %{{.*}}, align 1 let result = pkd.data; @@ -28,43 +35,94 @@ pub fn write_pkd(pkd: &mut Packed) -> u32 { result } +// CHECK-LABEL: @write_pkd2 +#[no_mangle] +pub fn write_pkd2(pkd: &mut Packed2) -> u32 { +// CHECK: %{{.*}} = load i32, i32* %{{.*}}, align 2 +// CHECK: store i32 42, i32* %{{.*}}, align 2 + let result = pkd.data; + pkd.data = 42; + result +} + pub struct Array([i32; 8]); #[repr(packed)] -pub struct BigPacked { +pub struct BigPacked1 { + dealign: u8, + data: Array +} + +#[repr(packed(2))] +pub struct BigPacked2 { dealign: u8, data: Array } -// CHECK-LABEL: @call_pkd +// CHECK-LABEL: @call_pkd1 #[no_mangle] -pub fn call_pkd(f: fn() -> Array) -> BigPacked { +pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array // CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) // CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 32, i32 1, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an // unaligned destination. - BigPacked { dealign: 0, data: f() } + BigPacked1 { dealign: 0, data: f() } +} + +// CHECK-LABEL: @call_pkd2 +#[no_mangle] +pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { +// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array +// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]]) +// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 32, i32 2, i1 false) + // check that calls whose destination is a field of a packed struct + // go through an alloca rather than calling the function with an + // unaligned destination. + BigPacked2 { dealign: 0, data: f() } } #[repr(packed)] #[derive(Copy, Clone)] -pub struct PackedPair(u8, u32); +pub struct Packed1Pair(u8, u32); -// CHECK-LABEL: @pkd_pair +#[repr(packed(2))] +#[derive(Copy, Clone)] +pub struct Packed2Pair(u8, u32); + +// CHECK-LABEL: @pkd1_pair #[no_mangle] -pub fn pkd_pair(pair1: &mut PackedPair, pair2: &mut PackedPair) { +pub fn pkd1_pair(pair1: &mut Packed1Pair, pair2: &mut Packed1Pair) { // CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 5, i32 1, i1 false) *pair2 = *pair1; } +// CHECK-LABEL: @pkd2_pair +#[no_mangle] +pub fn pkd2_pair(pair1: &mut Packed2Pair, pair2: &mut Packed2Pair) { +// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 6, i32 2, i1 false) + *pair2 = *pair1; +} + #[repr(packed)] #[derive(Copy, Clone)] -pub struct PackedNestedPair((u32, u32)); +pub struct Packed1NestedPair((u32, u32)); + +#[repr(packed(2))] +#[derive(Copy, Clone)] +pub struct Packed2NestedPair((u32, u32)); -// CHECK-LABEL: @pkd_nested_pair +// CHECK-LABEL: @pkd1_nested_pair #[no_mangle] -pub fn pkd_nested_pair(pair1: &mut PackedNestedPair, pair2: &mut PackedNestedPair) { +pub fn pkd1_nested_pair(pair1: &mut Packed1NestedPair, pair2: &mut Packed1NestedPair) { // CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 8, i32 1, i1 false) *pair2 = *pair1; } + +// CHECK-LABEL: @pkd2_nested_pair +#[no_mangle] +pub fn pkd2_nested_pair(pair1: &mut Packed2NestedPair, pair2: &mut Packed2NestedPair) { +// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 8, i32 2, i1 false) + *pair2 = *pair1; +} + diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs index e4301435063..1479d0b6264 100644 --- a/src/test/compile-fail/allocator/not-an-allocator.rs +++ b/src/test/compile-fail/allocator/not-an-allocator.rs @@ -12,15 +12,10 @@ #[global_allocator] static A: usize = 0; -//~^ the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: -//~| the trait bound `&usize: +//~^ the trait bound `usize: +//~| the trait bound `usize: +//~| the trait bound `usize: +//~| the trait bound `usize: +//~| the trait bound `usize: fn main() {} diff --git a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs index 8a09ab3fd06..fbdd013024d 100644 --- a/src/test/compile-fail/borrowck/borrowck-issue-14498.rs +++ b/src/test/compile-fail/borrowck/borrowck-issue-14498.rs @@ -27,7 +27,7 @@ fn indirect_write_to_imm_box() { let y: Box<_> = box &mut x; let p = &y; ***p = 2; //[ast]~ ERROR cannot assign to data in a `&` reference - //[mir]~^ ERROR cannot assign to immutable item `***p` + //[mir]~^ ERROR cannot assign to data in a `&` reference drop(p); } diff --git a/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs index a214e3c126e..eec7df84c82 100644 --- a/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs +++ b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs @@ -36,7 +36,7 @@ fn main() { let mut line1 = Line::default(); let _moved = line1.origin; - let _ = line1.origin.x + 1; //[ast]~ ERROR use of collaterally moved value: `line1.origin.x` + let _ = line1.origin.x + 1; //[ast]~ ERROR use of moved value: `line1.origin.x` //[mir]~^ [E0382] let mut line2 = Line::default(); diff --git a/src/test/compile-fail/catch-bad-lifetime.rs b/src/test/compile-fail/catch-bad-lifetime.rs index f24561b8887..f332ffd4494 100644 --- a/src/test/compile-fail/catch-bad-lifetime.rs +++ b/src/test/compile-fail/catch-bad-lifetime.rs @@ -21,7 +21,6 @@ pub fn main() { //~^ ERROR `my_string` does not live long enough Err(my_str) ?; Err("") ?; - Ok(()) }; } @@ -32,7 +31,6 @@ pub fn main() { let mut j: Result<(), &mut i32> = do catch { Err(k) ?; i = 10; //~ ERROR cannot assign to `i` because it is borrowed - Ok(()) }; ::std::mem::drop(k); //~ ERROR use of moved value: `k` i = 40; //~ ERROR cannot assign to `i` because it is borrowed diff --git a/src/test/compile-fail/catch-bad-type.rs b/src/test/compile-fail/catch-bad-type.rs index cff9f508275..b369847699b 100644 --- a/src/test/compile-fail/catch-bad-type.rs +++ b/src/test/compile-fail/catch-bad-type.rs @@ -11,11 +11,18 @@ #![feature(catch_expr)] pub fn main() { - let res: Result<i32, i32> = do catch { + let res: Result<u32, i32> = do catch { Err("")?; //~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied - Ok(5) + 5 }; + let res: Result<i32, i32> = do catch { - Ok("") //~ mismatched types + "" //~ ERROR type mismatch }; + + let res: Result<i32, i32> = do catch { }; //~ ERROR type mismatch + + let res: () = do catch { }; //~ the trait bound `(): std::ops::Try` is not satisfied + + let res: i32 = do catch { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied } diff --git a/src/test/compile-fail/catch-maybe-bad-lifetime.rs b/src/test/compile-fail/catch-maybe-bad-lifetime.rs index b783a3dd786..faefb5ef18a 100644 --- a/src/test/compile-fail/catch-maybe-bad-lifetime.rs +++ b/src/test/compile-fail/catch-maybe-bad-lifetime.rs @@ -17,7 +17,7 @@ pub fn main() { let mut i = 222; let x: Result<&i32, ()> = do catch { Err(())?; - Ok(&i) + &i }; x.ok().cloned(); i = 0; //~ ERROR cannot assign to `i` because it is borrowed @@ -29,7 +29,6 @@ pub fn main() { let _y: Result<(), ()> = do catch { Err(())?; ::std::mem::drop(x); - Ok(()) }; println!("{}", x); //~ ERROR use of moved value: `x` } @@ -42,7 +41,6 @@ pub fn main() { let x: Result<(), ()> = do catch { Err(())?; j = &i; - Ok(()) }; i = 0; //~ ERROR cannot assign to `i` because it is borrowed let _ = i; diff --git a/src/test/compile-fail/catch-opt-init.rs b/src/test/compile-fail/catch-opt-init.rs index 48284b4cb90..0c41102e3be 100644 --- a/src/test/compile-fail/catch-opt-init.rs +++ b/src/test/compile-fail/catch-opt-init.rs @@ -19,7 +19,6 @@ pub fn main() { cfg_res = 5; Ok::<(), ()>(())?; use_val(cfg_res); - Ok(()) }; assert_eq!(cfg_res, 5); //~ ERROR use of possibly uninitialized variable } diff --git a/src/test/compile-fail/conflicting-repr-hints.rs b/src/test/compile-fail/conflicting-repr-hints.rs index 8acc8b7bb1e..426f60c6b09 100644 --- a/src/test/compile-fail/conflicting-repr-hints.rs +++ b/src/test/compile-fail/conflicting-repr-hints.rs @@ -9,6 +9,7 @@ // except according to those terms. #![allow(dead_code)] +#![feature(repr_packed)] #[repr(C)] enum A { A } @@ -36,6 +37,16 @@ struct G(i32); //~ ERROR type has conflicting packed and align representation hi #[repr(packed)] struct H(i32); //~ ERROR type has conflicting packed and align representation hints +#[repr(packed, packed(2))] +struct I(i32); //~ ERROR type has conflicting packed representation hints + +#[repr(packed(2))] +#[repr(packed)] +struct J(i32); //~ ERROR type has conflicting packed representation hints + +#[repr(packed, packed(1))] +struct K(i32); + #[repr(packed, align(8))] union X { //~ ERROR type has conflicting packed and align representation hints i: i32 diff --git a/src/test/compile-fail/issue-19244-1.rs b/src/test/compile-fail/issue-19244-1.rs index 0fa1a154772..df34aab4b8f 100644 --- a/src/test/compile-fail/issue-19244-1.rs +++ b/src/test/compile-fail/issue-19244-1.rs @@ -12,5 +12,5 @@ const TUP: (usize,) = (42,); fn main() { let a: [isize; TUP.1]; - //~^ ERROR attempted out-of-bounds tuple index + //~^ ERROR no field `1` on type `(usize,)` } diff --git a/src/test/compile-fail/lint-non-uppercase-statics.rs b/src/test/compile-fail/lint-non-uppercase-statics.rs index 463a93612ca..84cc24a0010 100644 --- a/src/test/compile-fail/lint-non-uppercase-statics.rs +++ b/src/test/compile-fail/lint-non-uppercase-statics.rs @@ -16,4 +16,7 @@ static foo: isize = 1; //~ ERROR static variable `foo` should have an upper case static mut bar: isize = 1; //~^ ERROR static variable `bar` should have an upper case name such as `BAR` +#[no_mangle] +pub static extern_foo: isize = 1; // OK, because #[no_mangle] supersedes the warning + fn main() { } diff --git a/src/test/compile-fail/outlives-associated-types.rs b/src/test/compile-fail/outlives-associated-types.rs index 778394c9fc8..5c392223f88 100644 --- a/src/test/compile-fail/outlives-associated-types.rs +++ b/src/test/compile-fail/outlives-associated-types.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + // Test that the outlives computation runs for now... #![feature(rustc_attrs)] @@ -16,7 +18,7 @@ // https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md#example-1-a-reference #[rustc_outlives] -struct Direct<'a, T> { //~ ERROR 19:1: 21:2: [] [E0640] +struct Direct<'a, T> { //~ ERROR 21:1: 23:2: [Binder(OutlivesPredicate(T, ReEarlyBound(0, 'a)))] [E0640] field: &'a T } diff --git a/src/test/compile-fail/single-primitive-inherent-impl.rs b/src/test/compile-fail/single-primitive-inherent-impl.rs index 5ceb870528a..365387c3e5e 100644 --- a/src/test/compile-fail/single-primitive-inherent-impl.rs +++ b/src/test/compile-fail/single-primitive-inherent-impl.rs @@ -15,9 +15,9 @@ #![no_std] // OK -#[lang = "char"] -impl char {} +#[lang = "str"] +impl str {} -impl char { -//~^ error: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive +impl str { +//~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive } diff --git a/src/test/compile-fail/struct-field-privacy.rs b/src/test/compile-fail/struct-field-privacy.rs index 5b2e04e25a9..f487ef62aa4 100644 --- a/src/test/compile-fail/struct-field-privacy.rs +++ b/src/test/compile-fail/struct-field-privacy.rs @@ -42,7 +42,7 @@ fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B, z: inner::Z) { e.b; //~ ERROR: field `b` of struct `xc::B` is private z.0; - z.1; //~ ERROR: field `1` of tuple-struct `inner::Z` is private + z.1; //~ ERROR: field `1` of struct `inner::Z` is private } fn main() {} diff --git a/src/test/compile-fail/tuple-index-out-of-bounds.rs b/src/test/compile-fail/tuple-index-out-of-bounds.rs index 4597cf3d350..35b843676b4 100644 --- a/src/test/compile-fail/tuple-index-out-of-bounds.rs +++ b/src/test/compile-fail/tuple-index-out-of-bounds.rs @@ -15,10 +15,10 @@ fn main() { origin.0; origin.1; origin.2; - //~^ ERROR attempted out-of-bounds tuple index `2` on type `Point` + //~^ ERROR no field `2` on type `Point` let tuple = (0, 0); tuple.0; tuple.1; tuple.2; - //~^ ERROR attempted out-of-bounds tuple index `2` on type `({integer}, {integer})` + //~^ ERROR no field `2` on type `({integer}, {integer})` } diff --git a/src/test/mir-opt/end_region_cyclic.rs b/src/test/mir-opt/end_region_cyclic.rs index 83425a72f45..9c939d0d2fb 100644 --- a/src/test/mir-opt/end_region_cyclic.rs +++ b/src/test/mir-opt/end_region_cyclic.rs @@ -40,29 +40,29 @@ fn query() -> bool { true } // END RUST SOURCE // START rustc.main.SimplifyCfg-qualify-consts.after.mir -// fn main() -> () { +// fn main() -> (){ // let mut _0: (); // scope 1 { -// let _2: S<'35_0rs>; +// let _2: S<'36_0rs>; +// } +// scope 2 { // } -// ... // let mut _1: (); -// let mut _3: std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>; -// let mut _4: std::option::Option<&'35_0rs S<'35_0rs>>; +// let mut _3: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>; +// let mut _4: std::option::Option<&'36_0rs S<'36_0rs>>; // let mut _5: (); -// let mut _6: &'16s std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>; -// let mut _7: std::option::Option<&'35_0rs S<'35_0rs>>; -// let mut _8: &'35_0rs S<'35_0rs>; -// let mut _9: &'35_0rs S<'35_0rs>; +// let mut _6: &'17s std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>; +// let mut _7: std::option::Option<&'36_0rs S<'36_0rs>>; +// let mut _8: &'36_0rs S<'36_0rs>; +// let mut _9: &'36_0rs S<'36_0rs>; // let mut _10: (); // let mut _11: bool; // let mut _12: !; // let mut _13: (); -// let mut _14: &'33s std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>; -// let mut _15: std::option::Option<&'35_0rs S<'35_0rs>>; -// let mut _16: &'35_0rs S<'35_0rs>; -// let mut _17: &'35_0rs S<'35_0rs>; -// +// let mut _14: &'34s std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>; +// let mut _15: std::option::Option<&'36_0rs S<'36_0rs>>; +// let mut _16: &'36_0rs S<'36_0rs>; +// let mut _17: &'36_0rs S<'36_0rs>; // bb0: { // goto -> bb1; // } @@ -73,7 +73,7 @@ fn query() -> bool { true } // StorageLive(_2); // StorageLive(_3); // StorageLive(_4); -// _4 = std::option::Option<&'35_0rs S<'35_0rs>>::None; +// _4 = std::option::Option<&'36_0rs S<'36_0rs>>::None; // _3 = const <std::cell::Cell<T>>::new(move _4) -> [return: bb4, unwind: bb3]; // } // bb3: { @@ -81,21 +81,21 @@ fn query() -> bool { true } // } // bb4: { // StorageDead(_4); -// _2 = S<'35_0rs> { r: move _3 }; +// _2 = S<'36_0rs> { r: move _3 }; // StorageDead(_3); // StorageLive(_6); -// _6 = &'16s (_2.0: std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>); +// _6 = &'17s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>); // StorageLive(_7); // StorageLive(_8); // StorageLive(_9); -// _9 = &'35_0rs _2; -// _8 = &'35_0rs (*_9); -// _7 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _8,); +// _9 = &'36_0rs _2; +// _8 = &'36_0rs (*_9); +// _7 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _8,); // StorageDead(_8); // _5 = const <std::cell::Cell<T>>::set(move _6, move _7) -> [return: bb5, unwind: bb3]; // } // bb5: { -// EndRegion('16s); +// EndRegion('17s); // StorageDead(_7); // StorageDead(_6); // StorageDead(_9); @@ -108,7 +108,7 @@ fn query() -> bool { true } // bb7: { // _0 = (); // StorageDead(_11); -// EndRegion('35_0rs); +// EndRegion('36_0rs); // StorageDead(_2); // return; // } @@ -116,23 +116,23 @@ fn query() -> bool { true } // _10 = (); // StorageDead(_11); // StorageLive(_14); -// _14 = &'33s (_2.0: std::cell::Cell<std::option::Option<&'35_0rs S<'35_0rs>>>); +// _14 = &'34s (_2.0: std::cell::Cell<std::option::Option<&'36_0rs S<'36_0rs>>>); // StorageLive(_15); // StorageLive(_16); // StorageLive(_17); -// _17 = &'35_0rs _2; -// _16 = &'35_0rs (*_17); -// _15 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _16,); +// _17 = &'36_0rs _2; +// _16 = &'36_0rs (*_17); +// _15 = std::option::Option<&'36_0rs S<'36_0rs>>::Some(move _16,); // StorageDead(_16); // _13 = const <std::cell::Cell<T>>::set(move _14, move _15) -> [return: bb9, unwind: bb3]; // } // bb9: { -// EndRegion('33s); +// EndRegion('34s); // StorageDead(_15); // StorageDead(_14); // StorageDead(_17); // _1 = (); -// EndRegion('35_0rs); +// EndRegion('36_0rs); // StorageDead(_2); // goto -> bb1; // } diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs index 80e75fcee8a..79645bd3600 100644 --- a/src/test/mir-opt/validate_3.rs +++ b/src/test/mir-opt/validate_3.rs @@ -29,34 +29,46 @@ fn main() { // END RUST SOURCE // START rustc.main.EraseRegions.after.mir -// fn main() -> () { -// ... +// fn main() -> (){ +// let mut _0: (); +// scope 1 { +// let _1: Test; +// scope 3 { +// let _2: &ReErased Test; +// } +// scope 4 { +// } +// } +// scope 2 { +// } +// let mut _3: (); +// let mut _4: &ReErased i32; // let mut _5: &ReErased i32; // bb0: { // StorageLive(_1); // _1 = Test { x: const 0i32 }; // StorageLive(_2); -// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 }))), [_1: Test]); +// Validate(Suspend(ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 }))), [_1: Test]); // _2 = &ReErased _1; -// Validate(Acquire, [(*_2): Test/ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })) (imm)]); +// Validate(Acquire, [(*_2): Test/ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })) (imm)]); // StorageLive(_4); // StorageLive(_5); -// Validate(Suspend(ReScope(Node(ItemLocalId(17)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 })) (imm)]); +// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 })) (imm)]); // _5 = &ReErased ((*_2).0: i32); -// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(17))) (imm)]); -// Validate(Suspend(ReScope(Node(ItemLocalId(17)))), [(*_5): i32/ReScope(Node(ItemLocalId(17))) (imm)]); +// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]); +// Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [(*_5): i32/ReScope(Node(ItemLocalId(18))) (imm)]); // _4 = &ReErased (*_5); -// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(17))) (imm)]); -// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(17))) i32]); +// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(18))) (imm)]); +// Validate(Release, [_3: (), _4: &ReScope(Node(ItemLocalId(18))) i32]); // _3 = const foo(move _4) -> bb1; // } // bb1: { // Validate(Acquire, [_3: ()]); -// EndRegion(ReScope(Node(ItemLocalId(17)))); +// EndRegion(ReScope(Node(ItemLocalId(18)))); // StorageDead(_4); // StorageDead(_5); // _0 = (); -// EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(19), first_statement_index: 3 }))); +// EndRegion(ReScope(Remainder(BlockRemainder { block: ItemLocalId(20), first_statement_index: 3 }))); // StorageDead(_2); // StorageDead(_1); // return; diff --git a/src/test/run-make-fulldeps/std-core-cycle/bar.rs b/src/test/run-make-fulldeps/std-core-cycle/bar.rs index 6def5b6f5e1..62fd2ade1ca 100644 --- a/src/test/run-make-fulldeps/std-core-cycle/bar.rs +++ b/src/test/run-make-fulldeps/std-core-cycle/bar.rs @@ -11,16 +11,16 @@ #![feature(allocator_api)] #![crate_type = "rlib"] -use std::heap::*; +use std::alloc::*; pub struct A; -unsafe impl<'a> Alloc for &'a A { - unsafe fn alloc(&mut self, _: Layout) -> Result<*mut u8, AllocErr> { +unsafe impl GlobalAlloc for A { + unsafe fn alloc(&self, _: Layout) -> *mut Opaque { loop {} } - unsafe fn dealloc(&mut self, _ptr: *mut u8, _: Layout) { + unsafe fn dealloc(&self, _ptr: *mut Opaque, _: Layout) { loop {} } } diff --git a/src/test/run-pass/align-struct.rs b/src/test/run-pass/align-struct.rs index dea8462705f..2b6a151574a 100644 --- a/src/test/run-pass/align-struct.rs +++ b/src/test/run-pass/align-struct.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(box_syntax)] +#![feature(repr_packed)] use std::mem; @@ -60,6 +61,18 @@ struct AlignContainsPacked { b: Packed, } +#[repr(C, packed(4))] +struct Packed4C { + a: u32, + b: u64, +} + +#[repr(align(16))] +struct AlignContainsPacked4C { + a: Packed4C, + b: u64, +} + // The align limit was originally smaller (2^15). // Check that it works with big numbers. #[repr(align(0x10000))] @@ -218,6 +231,15 @@ pub fn main() { assert_eq!(mem::size_of_val(&a), 16); assert!(is_aligned_to(&a, 16)); + assert_eq!(mem::align_of::<AlignContainsPacked4C>(), 16); + assert_eq!(mem::size_of::<AlignContainsPacked4C>(), 32); + let a = AlignContainsPacked4C { a: Packed4C{ a: 1, b: 2 }, b: 3 }; + assert_eq!(mem::align_of_val(&a), 16); + assert_eq!(mem::align_of_val(&a.a), 4); + assert_eq!(mem::align_of_val(&a.b), mem::align_of::<u64>()); + assert_eq!(mem::size_of_val(&a), 32); + assert!(is_aligned_to(&a, 16)); + let mut large = box AlignLarge { stuff: [0; 0x10000], }; diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index eaa5bc90805..38b8ab50cc7 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -14,8 +14,8 @@ use std::heap::{Heap, Alloc}; fn main() { unsafe { - let ptr = Heap.alloc_one::<i32>().unwrap_or_else(|e| { - Heap.oom(e) + let ptr = Heap.alloc_one::<i32>().unwrap_or_else(|_| { + Heap.oom() }); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs index 8f4fbcd5ab1..e6a2e22983b 100644 --- a/src/test/run-pass/allocator/auxiliary/custom.rs +++ b/src/test/run-pass/allocator/auxiliary/custom.rs @@ -13,18 +13,18 @@ #![feature(heap_api, allocator_api)] #![crate_type = "rlib"] -use std::heap::{Alloc, System, AllocErr, Layout}; +use std::heap::{GlobalAlloc, System, Layout, Opaque}; use std::sync::atomic::{AtomicUsize, Ordering}; pub struct A(pub AtomicUsize); -unsafe impl<'a> Alloc for &'a A { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { +unsafe impl GlobalAlloc for A { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { self.0.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { self.0.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs index 22081678fb9..415d39a593e 100644 --- a/src/test/run-pass/allocator/custom.rs +++ b/src/test/run-pass/allocator/custom.rs @@ -15,20 +15,20 @@ extern crate helper; -use std::heap::{Heap, Alloc, System, Layout, AllocErr}; +use std::alloc::{self, Global, Alloc, System, Layout, Opaque}; use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; static HITS: AtomicUsize = ATOMIC_USIZE_INIT; struct A; -unsafe impl<'a> Alloc for &'a A { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { +unsafe impl alloc::GlobalAlloc for A { + unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { HITS.fetch_add(1, Ordering::SeqCst); System.alloc(layout) } - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); System.dealloc(ptr, layout) } @@ -45,10 +45,10 @@ fn main() { unsafe { let layout = Layout::from_size_align(4, 2).unwrap(); - let ptr = Heap.alloc(layout.clone()).unwrap(); + let ptr = Global.alloc(layout.clone()).unwrap(); helper::work_with(&ptr); assert_eq!(HITS.load(Ordering::SeqCst), n + 1); - Heap.dealloc(ptr, layout.clone()); + Global.dealloc(ptr, layout.clone()); assert_eq!(HITS.load(Ordering::SeqCst), n + 2); let s = String::with_capacity(10); diff --git a/src/test/run-pass/allocator/xcrate-use.rs b/src/test/run-pass/allocator/xcrate-use.rs index 04d2ef466e7..78d604a7108 100644 --- a/src/test/run-pass/allocator/xcrate-use.rs +++ b/src/test/run-pass/allocator/xcrate-use.rs @@ -17,7 +17,7 @@ extern crate custom; extern crate helper; -use std::heap::{Heap, Alloc, System, Layout}; +use std::alloc::{Global, Alloc, System, Layout}; use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; #[global_allocator] @@ -28,10 +28,10 @@ fn main() { let n = GLOBAL.0.load(Ordering::SeqCst); let layout = Layout::from_size_align(4, 2).unwrap(); - let ptr = Heap.alloc(layout.clone()).unwrap(); + let ptr = Global.alloc(layout.clone()).unwrap(); helper::work_with(&ptr); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); - Heap.dealloc(ptr, layout.clone()); + Global.dealloc(ptr, layout.clone()); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); let ptr = System.alloc(layout.clone()).unwrap(); diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs index 155fb5d6c5d..b8e844522dc 100644 --- a/src/test/run-pass/allocator/xcrate-use2.rs +++ b/src/test/run-pass/allocator/xcrate-use2.rs @@ -19,7 +19,7 @@ extern crate custom; extern crate custom_as_global; extern crate helper; -use std::heap::{Heap, Alloc, System, Layout}; +use std::alloc::{Global, Alloc, GlobalAlloc, System, Layout}; use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT}; static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT); @@ -30,25 +30,25 @@ fn main() { let layout = Layout::from_size_align(4, 2).unwrap(); // Global allocator routes to the `custom_as_global` global - let ptr = Heap.alloc(layout.clone()).unwrap(); + let ptr = Global.alloc(layout.clone()); helper::work_with(&ptr); assert_eq!(custom_as_global::get(), n + 1); - Heap.dealloc(ptr, layout.clone()); + Global.dealloc(ptr, layout.clone()); assert_eq!(custom_as_global::get(), n + 2); // Usage of the system allocator avoids all globals - let ptr = System.alloc(layout.clone()).unwrap(); + let ptr = System.alloc(layout.clone()); helper::work_with(&ptr); assert_eq!(custom_as_global::get(), n + 2); System.dealloc(ptr, layout.clone()); assert_eq!(custom_as_global::get(), n + 2); // Usage of our personal allocator doesn't affect other instances - let ptr = (&GLOBAL).alloc(layout.clone()).unwrap(); + let ptr = GLOBAL.alloc(layout.clone()); helper::work_with(&ptr); assert_eq!(custom_as_global::get(), n + 2); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 1); - (&GLOBAL).dealloc(ptr, layout); + GLOBAL.dealloc(ptr, layout); assert_eq!(custom_as_global::get(), n + 2); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 2); } diff --git a/src/test/run-pass/auxiliary/packed.rs b/src/test/run-pass/auxiliary/packed.rs index 86f5f93e3cf..828be41cd41 100644 --- a/src/test/run-pass/auxiliary/packed.rs +++ b/src/test/run-pass/auxiliary/packed.rs @@ -8,8 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(repr_packed)] + #[repr(packed)] -pub struct S { +pub struct P1S5 { a: u8, b: u32 } + +#[repr(packed(2))] +pub struct P2S6 { + a: u8, + b: u32, + c: u8 +} + +#[repr(C, packed(2))] +pub struct P2CS8 { + a: u8, + b: u32, + c: u8 +} diff --git a/src/test/run-pass/cast.rs b/src/test/run-pass/cast.rs index bb60626a4bf..80fa5362a8b 100644 --- a/src/test/run-pass/cast.rs +++ b/src/test/run-pass/cast.rs @@ -19,4 +19,9 @@ pub fn main() { assert_eq!(i as u8 as i8, 'Q' as u8 as i8); assert_eq!(0x51 as char, 'Q'); assert_eq!(0 as u32, false as u32); + + // Test that `_` is correctly inferred. + let x = &"hello"; + let mut y = x as *const _; + y = 0 as *const _; } diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs index 310b6ea5bcc..c23bca7f49e 100644 --- a/src/test/run-pass/catch-expr.rs +++ b/src/test/run-pass/catch-expr.rs @@ -13,11 +13,11 @@ struct catch {} pub fn main() { - let catch_result = do catch { + let catch_result: Option<_> = do catch { let x = 5; x }; - assert_eq!(catch_result, 5); + assert_eq!(catch_result, Some(5)); let mut catch = true; while catch { catch = false; } @@ -30,16 +30,16 @@ pub fn main() { _ => {} }; - let catch_err = do catch { + let catch_err: Result<_, i32> = do catch { Err(22)?; - Ok(1) + 1 }; assert_eq!(catch_err, Err(22)); let catch_okay: Result<i32, i32> = do catch { if false { Err(25)?; } Ok::<(), i32>(())?; - Ok(28) + 28 }; assert_eq!(catch_okay, Ok(28)); @@ -47,14 +47,13 @@ pub fn main() { for i in 0..10 { if i < 5 { Ok::<i32, i32>(i)?; } else { Err(i)?; } } - Ok(22) + 22 }; assert_eq!(catch_from_loop, Err(5)); let cfg_init; let _res: Result<(), ()> = do catch { cfg_init = 5; - Ok(()) }; assert_eq!(cfg_init, 5); @@ -62,19 +61,19 @@ pub fn main() { let _res: Result<(), ()> = do catch { cfg_init_2 = 6; Err(())?; - Ok(()) }; assert_eq!(cfg_init_2, 6); let my_string = "test".to_string(); let res: Result<&str, ()> = do catch { - Ok(&my_string) + // Unfortunately, deref doesn't fire here (#49356) + &my_string[..] }; assert_eq!(res, Ok("test")); - do catch { - () - } + let my_opt: Option<_> = do catch { () }; + assert_eq!(my_opt, Some(())); - (); + let my_opt: Option<_> = do catch { }; + assert_eq!(my_opt, Some(())); } diff --git a/src/test/run-pass/char_unicode.rs b/src/test/run-pass/char_unicode.rs index b4884acdd07..bfc7faac06e 100644 --- a/src/test/run-pass/char_unicode.rs +++ b/src/test/run-pass/char_unicode.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(unicode)] - +#![feature(unicode_version)] /// Tests access to the internal Unicode Version type and value. pub fn main() { diff --git a/src/test/run-pass/issue-48159.rs b/src/test/run-pass/issue-48159.rs new file mode 100644 index 00000000000..ce4585607e9 --- /dev/null +++ b/src/test/run-pass/issue-48159.rs @@ -0,0 +1,37 @@ +// 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. + +#![feature(repr_packed)] +#![allow(non_camel_case_types)] + +use std::mem; + +pub enum c_void {} + +type uintptr_t = usize; +type int16_t = u16; +type uint16_t = int16_t; +type uint32_t = u32; +type intptr_t = uintptr_t; + +#[repr(C)] +#[repr(packed(4))] +pub struct kevent { + pub ident: uintptr_t, + pub filter: int16_t, + pub flags: uint16_t, + pub fflags: uint32_t, + pub data: intptr_t, + pub udata: *mut c_void, +} + +fn main() { + assert_eq!(mem::align_of::<kevent>(), 4); +} diff --git a/src/test/run-pass/issue-49556.rs b/src/test/run-pass/issue-49556.rs new file mode 100644 index 00000000000..70ccee99f66 --- /dev/null +++ b/src/test/run-pass/issue-49556.rs @@ -0,0 +1,22 @@ +// 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. + +fn iter<'a>(data: &'a [usize]) -> impl Iterator<Item = usize> + 'a { + data.iter() + .map( + |x| x // fn(&'a usize) -> &'(ReScope) usize + ) + .map( + |x| *x // fn(&'(ReScope) usize) -> usize + ) +} + +fn main() { +} diff --git a/src/test/run-pass/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs b/src/test/run-pass/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs new file mode 100644 index 00000000000..51b2b5a4f7c --- /dev/null +++ b/src/test/run-pass/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs @@ -0,0 +1,24 @@ +// 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(non_shorthand_field_patterns)] + +pub struct Value<A> { pub value: A } + +#[macro_export] +macro_rules! pat { + ($a:pat) => { + Value { value: $a } + }; +} + +fn main() { + let pat!(value) = Value { value: () }; +} diff --git a/src/test/run-pass/packed-struct-borrow-element.rs b/src/test/run-pass/packed-struct-borrow-element.rs index e725b25efee..c8a8643ed6b 100644 --- a/src/test/run-pass/packed-struct-borrow-element.rs +++ b/src/test/run-pass/packed-struct-borrow-element.rs @@ -10,15 +10,36 @@ // ignore-emscripten weird assertion? +#![feature(repr_packed)] + #[repr(packed)] -struct Foo { +struct Foo1 { + bar: u8, + baz: usize +} + +#[repr(packed(2))] +struct Foo2 { + bar: u8, + baz: usize +} + +#[repr(C, packed(4))] +struct Foo4C { bar: u8, baz: usize } pub fn main() { - let foo = Foo { bar: 1, baz: 2 }; + let foo = Foo1 { bar: 1, baz: 2 }; let brw = unsafe { &foo.baz }; + assert_eq!(*brw, 2); + let foo = Foo2 { bar: 1, baz: 2 }; + let brw = unsafe { &foo.baz }; + assert_eq!(*brw, 2); + + let foo = Foo4C { bar: 1, baz: 2 }; + let brw = unsafe { &foo.baz }; assert_eq!(*brw, 2); } diff --git a/src/test/run-pass/packed-struct-generic-size.rs b/src/test/run-pass/packed-struct-generic-size.rs index 4e1f62b28ab..127d873b2d9 100644 --- a/src/test/run-pass/packed-struct-generic-size.rs +++ b/src/test/run-pass/packed-struct-generic-size.rs @@ -8,18 +8,45 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(repr_packed)] use std::mem; #[repr(packed)] -struct S<T, S> { +struct P1<T, S> { a: T, b: u8, c: S } +#[repr(packed(2))] +struct P2<T, S> { + a: T, + b: u8, + c: S +} + +#[repr(C, packed(4))] +struct P4C<T, S> { + a: T, + b: u8, + c: S +} + +macro_rules! check { + ($t:ty, $align:expr, $size:expr) => ({ + assert_eq!(mem::align_of::<$t>(), $align); + assert_eq!(mem::size_of::<$t>(), $size); + }); +} + pub fn main() { - assert_eq!(mem::size_of::<S<u8, u8>>(), 3); + check!(P1::<u8, u8>, 1, 3); + check!(P1::<u64, u16>, 1, 11); + + check!(P2::<u8, u8>, 1, 3); + check!(P2::<u64, u16>, 2, 12); - assert_eq!(mem::size_of::<S<u64, u16>>(), 11); + check!(P4C::<u8, u8>, 1, 3); + check!(P4C::<u16, u64>, 4, 12); } diff --git a/src/test/run-pass/packed-struct-match.rs b/src/test/run-pass/packed-struct-match.rs index 3cd254014c1..c02d524d763 100644 --- a/src/test/run-pass/packed-struct-match.rs +++ b/src/test/run-pass/packed-struct-match.rs @@ -8,17 +8,46 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(repr_packed)] #[repr(packed)] -struct Foo { +struct Foo1 { + bar: u8, + baz: usize +} + +#[repr(packed(2))] +struct Foo2 { + bar: u8, + baz: usize +} + +#[repr(C, packed(4))] +struct Foo4C { bar: u8, baz: usize } pub fn main() { - let foo = Foo { bar: 1, baz: 2 }; - match foo { - Foo {bar, baz} => { + let foo1 = Foo1 { bar: 1, baz: 2 }; + match foo1 { + Foo1 {bar, baz} => { + assert_eq!(bar, 1); + assert_eq!(baz, 2); + } + } + + let foo2 = Foo2 { bar: 1, baz: 2 }; + match foo2 { + Foo2 {bar, baz} => { + assert_eq!(bar, 1); + assert_eq!(baz, 2); + } + } + + let foo4 = Foo4C { bar: 1, baz: 2 }; + match foo4 { + Foo4C {bar, baz} => { assert_eq!(bar, 1); assert_eq!(baz, 2); } diff --git a/src/test/run-pass/packed-struct-size-xc.rs b/src/test/run-pass/packed-struct-size-xc.rs index 372693433db..48f34554ca1 100644 --- a/src/test/run-pass/packed-struct-size-xc.rs +++ b/src/test/run-pass/packed-struct-size-xc.rs @@ -15,6 +15,15 @@ extern crate packed; use std::mem; +macro_rules! check { + ($t:ty, $align:expr, $size:expr) => ({ + assert_eq!(mem::align_of::<$t>(), $align); + assert_eq!(mem::size_of::<$t>(), $size); + }); +} + pub fn main() { - assert_eq!(mem::size_of::<packed::S>(), 5); + check!(packed::P1S5, 1, 5); + check!(packed::P2S6, 2, 6); + check!(packed::P2CS8, 2, 8); } diff --git a/src/test/run-pass/packed-struct-size.rs b/src/test/run-pass/packed-struct-size.rs index 754a3573339..f8e23610fe2 100644 --- a/src/test/run-pass/packed-struct-size.rs +++ b/src/test/run-pass/packed-struct-size.rs @@ -7,44 +7,116 @@ // <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. - +#![feature(repr_packed)] use std::mem; #[repr(packed)] -struct S4 { +struct P1S4 { + a: u8, + b: [u8; 3], +} + +#[repr(packed(2))] +struct P2S4 { a: u8, b: [u8; 3], } #[repr(packed)] -struct S5 { +struct P1S5 { + a: u8, + b: u32 +} + +#[repr(packed(2))] +struct P2S2 { + a: u8, + b: u8 +} + +#[repr(packed(2))] +struct P2S6 { a: u8, b: u32 } +#[repr(packed(2))] +struct P2S12 { + a: u32, + b: u64 +} + #[repr(packed)] -struct S13 { +struct P1S13 { a: i64, b: f32, c: u8, } +#[repr(packed(2))] +struct P2S14 { + a: i64, + b: f32, + c: u8, +} + +#[repr(packed(4))] +struct P4S16 { + a: u8, + b: f32, + c: i64, + d: u16, +} + +#[repr(C, packed(4))] +struct P4CS20 { + a: u8, + b: f32, + c: i64, + d: u16, +} + enum Foo { Bar = 1, Baz = 2 } #[repr(packed)] -struct S3_Foo { +struct P1S3_Foo { + a: u8, + b: u16, + c: Foo +} + +#[repr(packed(2))] +struct P2_Foo { + a: Foo, +} + +#[repr(packed(2))] +struct P2S3_Foo { a: u8, b: u16, c: Foo } #[repr(packed)] -struct S7_Option { +struct P1S7_Option { + a: f32, + b: u8, + c: u16, + d: Option<Box<f64>> +} + +#[repr(packed(2))] +struct P2_Option { + a: Option<Box<f64>> +} + +#[repr(packed(2))] +struct P2S7_Option { a: f32, b: u8, c: u16, @@ -52,15 +124,41 @@ struct S7_Option { } // Placing packed structs in statics should work -static TEST_S4: S4 = S4 { a: 1, b: [2, 3, 4] }; -static TEST_S5: S5 = S5 { a: 3, b: 67 }; -static TEST_S3_Foo: S3_Foo = S3_Foo { a: 1, b: 2, c: Foo::Baz }; +static TEST_P1S4: P1S4 = P1S4 { a: 1, b: [2, 3, 4] }; +static TEST_P1S5: P1S5 = P1S5 { a: 3, b: 67 }; +static TEST_P1S3_Foo: P1S3_Foo = P1S3_Foo { a: 1, b: 2, c: Foo::Baz }; +static TEST_P2S2: P2S2 = P2S2 { a: 1, b: 2 }; +static TEST_P2S4: P2S4 = P2S4 { a: 1, b: [2, 3, 4] }; +static TEST_P2S6: P2S6 = P2S6 { a: 1, b: 2 }; +static TEST_P2S12: P2S12 = P2S12 { a: 1, b: 2 }; +static TEST_P4S16: P4S16 = P4S16 { a: 1, b: 2.0, c: 3, d: 4 }; +static TEST_P4CS20: P4CS20 = P4CS20 { a: 1, b: 2.0, c: 3, d: 4 }; +fn align_to(value: usize, align: usize) -> usize { + (value + (align - 1)) & !(align - 1) +} + +macro_rules! check { + ($t:ty, $align:expr, $size:expr) => ({ + assert_eq!(mem::align_of::<$t>(), $align); + assert_eq!(mem::size_of::<$t>(), $size); + }); +} pub fn main() { - assert_eq!(mem::size_of::<S4>(), 4); - assert_eq!(mem::size_of::<S5>(), 5); - assert_eq!(mem::size_of::<S13>(), 13); - assert_eq!(mem::size_of::<S3_Foo>(), 3 + mem::size_of::<Foo>()); - assert_eq!(mem::size_of::<S7_Option>(), 7 + mem::size_of::<Option<Box<f64>>>()); + check!(P1S4, 1, 4); + check!(P1S5, 1, 5); + check!(P1S13, 1, 13); + check!(P1S3_Foo, 1, 3 + mem::size_of::<Foo>()); + check!(P1S7_Option, 1, 7 + mem::size_of::<Option<Box<f64>>>()); + + check!(P2S2, 1, 2); + check!(P2S4, 1, 4); + check!(P2S6, 2, 6); + check!(P2S12, 2, 12); + check!(P2S14, 2, 14); + check!(P4S16, 4, 16); + check!(P4CS20, 4, 20); + check!(P2S3_Foo, 2, align_to(3 + mem::size_of::<P2_Foo>(), 2)); + check!(P2S7_Option, 2, align_to(7 + mem::size_of::<P2_Option>(), 2)); } diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs index 57407b84223..9d8b3d0d074 100644 --- a/src/test/run-pass/packed-struct-vec.rs +++ b/src/test/run-pass/packed-struct-vec.rs @@ -8,28 +8,80 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(repr_packed)] + use std::fmt; use std::mem; #[repr(packed)] #[derive(Copy, Clone)] -struct Foo { +struct Foo1 { bar: u8, baz: u64 } -impl PartialEq for Foo { - fn eq(&self, other: &Foo) -> bool { +impl PartialEq for Foo1 { + fn eq(&self, other: &Foo1) -> bool { self.bar == other.bar && self.baz == other.baz } } -impl fmt::Debug for Foo { +impl fmt::Debug for Foo1 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let bar = self.bar; let baz = self.baz; - f.debug_struct("Foo") + f.debug_struct("Foo1") + .field("bar", &bar) + .field("baz", &baz) + .finish() + } +} + +#[repr(packed(2))] +#[derive(Copy, Clone)] +struct Foo2 { + bar: u8, + baz: u64 +} + +impl PartialEq for Foo2 { + fn eq(&self, other: &Foo2) -> bool { + self.bar == other.bar && self.baz == other.baz + } +} + +impl fmt::Debug for Foo2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bar = self.bar; + let baz = self.baz; + + f.debug_struct("Foo2") + .field("bar", &bar) + .field("baz", &baz) + .finish() + } +} + +#[repr(C, packed(4))] +#[derive(Copy, Clone)] +struct Foo4C { + bar: u8, + baz: u64 +} + +impl PartialEq for Foo4C { + fn eq(&self, other: &Foo4C) -> bool { + self.bar == other.bar && self.baz == other.baz + } +} + +impl fmt::Debug for Foo4C { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bar = self.bar; + let baz = self.baz; + + f.debug_struct("Foo4C") .field("bar", &bar) .field("baz", &baz) .finish() @@ -37,15 +89,42 @@ impl fmt::Debug for Foo { } pub fn main() { - let foos = [Foo { bar: 1, baz: 2 }; 10]; + let foo1s = [Foo1 { bar: 1, baz: 2 }; 10]; + + assert_eq!(mem::align_of::<[Foo1; 10]>(), 1); + assert_eq!(mem::size_of::<[Foo1; 10]>(), 90); + + for i in 0..10 { + assert_eq!(foo1s[i], Foo1 { bar: 1, baz: 2}); + } + + for &foo in &foo1s { + assert_eq!(foo, Foo1 { bar: 1, baz: 2 }); + } + + let foo2s = [Foo2 { bar: 1, baz: 2 }; 10]; + + assert_eq!(mem::align_of::<[Foo2; 10]>(), 2); + assert_eq!(mem::size_of::<[Foo2; 10]>(), 100); + + for i in 0..10 { + assert_eq!(foo2s[i], Foo2 { bar: 1, baz: 2}); + } + + for &foo in &foo2s { + assert_eq!(foo, Foo2 { bar: 1, baz: 2 }); + } + + let foo4s = [Foo4C { bar: 1, baz: 2 }; 10]; - assert_eq!(mem::size_of::<[Foo; 10]>(), 90); + assert_eq!(mem::align_of::<[Foo4C; 10]>(), 4); + assert_eq!(mem::size_of::<[Foo4C; 10]>(), 120); for i in 0..10 { - assert_eq!(foos[i], Foo { bar: 1, baz: 2}); + assert_eq!(foo4s[i], Foo4C { bar: 1, baz: 2}); } - for &foo in &foos { - assert_eq!(foo, Foo { bar: 1, baz: 2 }); + for &foo in &foo4s { + assert_eq!(foo, Foo4C { bar: 1, baz: 2 }); } } diff --git a/src/test/run-pass/packed-tuple-struct-size.rs b/src/test/run-pass/packed-tuple-struct-size.rs index b0c8684cfe3..9def6ac28e5 100644 --- a/src/test/run-pass/packed-tuple-struct-size.rs +++ b/src/test/run-pass/packed-tuple-struct-size.rs @@ -8,18 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(repr_packed)] use std::mem; #[repr(packed)] -struct S4(u8,[u8; 3]); +struct P1S4(u8,[u8; 3]); + +#[repr(packed(2))] +struct P2S4(u8,[u8; 3]); #[repr(packed)] -struct S5(u8, u32); +struct P1S5(u8, u32); + +#[repr(packed(2))] +struct P2S6(u8, u32); #[repr(packed)] -struct S13(i64, f32, u8); +struct P1S13(i64, f32, u8); + +#[repr(packed(2))] +struct P2S14(i64, f32, u8); + +#[repr(packed(4))] +struct P4S16(u8, f32, i64, u16); + +#[repr(C, packed(4))] +struct P4CS20(u8, f32, i64, u16); enum Foo { Bar = 1, @@ -27,21 +42,46 @@ enum Foo { } #[repr(packed)] -struct S3_Foo(u8, u16, Foo); +struct P1S3_Foo(u8, u16, Foo); + +#[repr(packed(2))] +struct P2_Foo(Foo); + +#[repr(packed(2))] +struct P2S3_Foo(u8, u16, Foo); #[repr(packed)] -struct S7_Option(f32, u8, u16, Option<Box<f64>>); +struct P1S7_Option(f32, u8, u16, Option<Box<f64>>); -pub fn main() { - assert_eq!(mem::size_of::<S4>(), 4); +#[repr(packed(2))] +struct P2_Option(Option<Box<f64>>); + +#[repr(packed(2))] +struct P2S7_Option(f32, u8, u16, Option<Box<f64>>); - assert_eq!(mem::size_of::<S5>(), 5); +fn align_to(value: usize, align: usize) -> usize { + (value + (align - 1)) & !(align - 1) +} - assert_eq!(mem::size_of::<S13>(), 13); +macro_rules! check { + ($t:ty, $align:expr, $size:expr) => ({ + assert_eq!(mem::align_of::<$t>(), $align); + assert_eq!(mem::size_of::<$t>(), $size); + }); +} - assert_eq!(mem::size_of::<S3_Foo>(), - 3 + mem::size_of::<Foo>()); +pub fn main() { + check!(P1S4, 1, 4); + check!(P1S5, 1, 5); + check!(P1S13, 1, 13); + check!(P1S3_Foo, 1, 3 + mem::size_of::<Foo>()); + check!(P1S7_Option, 1, 7 + mem::size_of::<Option<Box<f64>>>()); - assert_eq!(mem::size_of::<S7_Option>(), - 7 + mem::size_of::<Option<Box<f64>>>()); + check!(P2S4, 1, 4); + check!(P2S6, 2, 6); + check!(P2S14, 2, 14); + check!(P4S16, 4, 16); + check!(P4CS20, 4, 20); + check!(P2S3_Foo, 2, align_to(3 + mem::size_of::<P2_Foo>(), 2)); + check!(P2S7_Option, 2, align_to(7 + mem::size_of::<P2_Option>(), 2)); } diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index eddcd5a584a..38cc23c16a9 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -13,10 +13,10 @@ // Ideally this would be revised to use no_std, but for now it serves // well enough to reproduce (and illustrate) the bug from #16687. -#![feature(heap_api, allocator_api)] +#![feature(heap_api, allocator_api, nonnull_cast)] -use std::heap::{Heap, Alloc, Layout}; -use std::ptr; +use std::alloc::{Global, Alloc, Layout}; +use std::ptr::{self, NonNull}; fn main() { unsafe { @@ -50,13 +50,13 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Heap.alloc(layout.clone()).unwrap_or_else(|e| Heap.oom(e)); + let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| Global.oom()); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); } - ret + ret.cast().as_ptr() } unsafe fn deallocate(ptr: *mut u8, layout: Layout) { @@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool { println!("deallocate({:?}, {:?}", ptr, layout); } - Heap.dealloc(ptr, layout); + Global.dealloc(NonNull::new_unchecked(ptr).as_opaque(), layout); } unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { @@ -72,14 +72,14 @@ unsafe fn test_triangle() -> bool { println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new); } - let ret = Heap.realloc(ptr, old.clone(), new.clone()) - .unwrap_or_else(|e| Heap.oom(e)); + let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old.clone(), new.size()) + .unwrap_or_else(|_| Global.oom()); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, ret); } - ret + ret.cast().as_ptr() } fn idx_to_size(i: usize) -> usize { (i+1) * 10 } diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index 8f278a315d1..3c37243c8b9 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -13,6 +13,7 @@ #![feature(allocator_api)] use std::heap::{Alloc, Heap, Layout}; +use std::ptr::NonNull; struct arena(()); @@ -32,8 +33,8 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let ptr = Heap.alloc(Layout::new::<Bcx>()) - .unwrap_or_else(|e| Heap.oom(e)); - &*(ptr as *const _) + .unwrap_or_else(|_| Heap.oom()); + &*(ptr.as_ptr() as *const _) } } @@ -45,7 +46,7 @@ fn g(fcx : &Fcx) { let bcx = Bcx { fcx: fcx }; let bcx2 = h(&bcx); unsafe { - Heap.dealloc(bcx2 as *const _ as *mut _, Layout::new::<Bcx>()); + Heap.dealloc(NonNull::new_unchecked(bcx2 as *const _ as *mut _), Layout::new::<Bcx>()); } } diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index 2f50e63153e..0bb18d8729a 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -42,6 +42,12 @@ enum ReorderedEnum { B(u8, u16, u8), } +enum NicheFilledEnumWithInhabitedVariant { + A(&'static ()), + B(&'static (), !), + C, +} + pub fn main() { assert_eq!(size_of::<u8>(), 1 as usize); assert_eq!(size_of::<u32>(), 4 as usize); @@ -67,4 +73,5 @@ pub fn main() { assert_eq!(size_of::<e3>(), 4 as usize); assert_eq!(size_of::<ReorderedStruct>(), 4); assert_eq!(size_of::<ReorderedEnum>(), 6); + assert_eq!(size_of::<NicheFilledEnumWithInhabitedVariant>(), size_of::<&'static ()>()); } diff --git a/src/test/run-pass/union/union-packed.rs b/src/test/run-pass/union/union-packed.rs index 6a61280823e..61bb04fece0 100644 --- a/src/test/run-pass/union/union-packed.rs +++ b/src/test/run-pass/union/union-packed.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(untagged_unions)] +#![feature(repr_packed)] use std::mem::{size_of, size_of_val, align_of, align_of_val}; @@ -18,7 +19,13 @@ struct S { } #[repr(packed)] -struct Sp { +struct Sp1 { + a: u16, + b: [u8; 3], +} + +#[repr(packed(2))] +struct Sp2 { a: u16, b: [u8; 3], } @@ -29,15 +36,30 @@ union U { } #[repr(packed)] -union Up { +union Up1 { + a: u16, + b: [u8; 3], +} + +#[repr(packed(2))] +union Up2 { + a: u16, + b: [u8; 3], +} + +#[repr(C, packed(4))] +union Up4c { a: u16, b: [u8; 3], } const CS: S = S { a: 0, b: [0, 0, 0] }; -const CSP: Sp = Sp { a: 0, b: [0, 0, 0] }; +const CSP1: Sp1 = Sp1 { a: 0, b: [0, 0, 0] }; +const CSP2: Sp2 = Sp2 { a: 0, b: [0, 0, 0] }; const CU: U = U { b: [0, 0, 0] }; -const CUP: Up = Up { b: [0, 0, 0] }; +const CUP1: Up1 = Up1 { b: [0, 0, 0] }; +const CUP2: Up2 = Up2 { b: [0, 0, 0] }; +const CUP4C: Up4c = Up4c { b: [0, 0, 0] }; fn main() { let s = S { a: 0, b: [0, 0, 0] }; @@ -48,13 +70,21 @@ fn main() { assert_eq!(align_of_val(&s), 2); assert_eq!(align_of_val(&CS), 2); - let sp = Sp { a: 0, b: [0, 0, 0] }; - assert_eq!(size_of::<Sp>(), 5); - assert_eq!(size_of_val(&sp), 5); - assert_eq!(size_of_val(&CSP), 5); - assert_eq!(align_of::<Sp>(), 1); - assert_eq!(align_of_val(&sp), 1); - assert_eq!(align_of_val(&CSP), 1); + let sp1 = Sp1 { a: 0, b: [0, 0, 0] }; + assert_eq!(size_of::<Sp1>(), 5); + assert_eq!(size_of_val(&sp1), 5); + assert_eq!(size_of_val(&CSP1), 5); + assert_eq!(align_of::<Sp1>(), 1); + assert_eq!(align_of_val(&sp1), 1); + assert_eq!(align_of_val(&CSP1), 1); + + let sp2 = Sp2 { a: 0, b: [0, 0, 0] }; + assert_eq!(size_of::<Sp2>(), 6); + assert_eq!(size_of_val(&sp2), 6); + assert_eq!(size_of_val(&CSP2), 6); + assert_eq!(align_of::<Sp2>(), 2); + assert_eq!(align_of_val(&sp2), 2); + assert_eq!(align_of_val(&CSP2), 2); let u = U { b: [0, 0, 0] }; assert_eq!(size_of::<U>(), 4); @@ -64,19 +94,35 @@ fn main() { assert_eq!(align_of_val(&u), 2); assert_eq!(align_of_val(&CU), 2); - let up = Up { b: [0, 0, 0] }; - assert_eq!(size_of::<Up>(), 3); - assert_eq!(size_of_val(&up), 3); - assert_eq!(size_of_val(&CUP), 3); - assert_eq!(align_of::<Up>(), 1); - assert_eq!(align_of_val(&up), 1); - assert_eq!(align_of_val(&CUP), 1); + let Up1 = Up1 { b: [0, 0, 0] }; + assert_eq!(size_of::<Up1>(), 3); + assert_eq!(size_of_val(&Up1), 3); + assert_eq!(size_of_val(&CUP1), 3); + assert_eq!(align_of::<Up1>(), 1); + assert_eq!(align_of_val(&Up1), 1); + assert_eq!(align_of_val(&CUP1), 1); + + let up2 = Up2 { b: [0, 0, 0] }; + assert_eq!(size_of::<Up2>(), 4); + assert_eq!(size_of_val(&up2), 4); + assert_eq!(size_of_val(&CUP2), 4); + assert_eq!(align_of::<Up2>(), 2); + assert_eq!(align_of_val(&up2), 2); + assert_eq!(align_of_val(&CUP2), 2); + + let up4c = Up4c { b: [0, 0, 0] }; + assert_eq!(size_of::<Up4c>(), 4); + assert_eq!(size_of_val(&up4c), 4); + assert_eq!(size_of_val(&CUP4C), 4); + assert_eq!(align_of::<Up4c>(), 2); + assert_eq!(align_of_val(&up4c), 2); + assert_eq!(align_of_val(&CUP4C), 2); hybrid::check_hybrid(); } mod hybrid { - use std::mem::size_of; + use std::mem::{size_of, align_of}; #[repr(packed)] struct S1 { @@ -96,9 +142,37 @@ mod hybrid { u: U, } + #[repr(C, packed(2))] + struct S1C { + a: u16, + b: u8, + } + + #[repr(C, packed(2))] + union UC { + s: S1, + c: u16, + } + + #[repr(C, packed(2))] + struct S2C { + d: u8, + u: UC, + } + pub fn check_hybrid() { + assert_eq!(align_of::<S1>(), 1); assert_eq!(size_of::<S1>(), 3); + assert_eq!(align_of::<U>(), 1); assert_eq!(size_of::<U>(), 3); + assert_eq!(align_of::<S2>(), 1); assert_eq!(size_of::<S2>(), 4); + + assert_eq!(align_of::<S1C>(), 2); + assert_eq!(size_of::<S1C>(), 4); + assert_eq!(align_of::<UC>(), 2); + assert_eq!(size_of::<UC>(), 4); + assert_eq!(align_of::<S2C>(), 2); + assert_eq!(size_of::<S2C>(), 6); } } diff --git a/src/test/rustdoc/all.rs b/src/test/rustdoc/all.rs new file mode 100644 index 00000000000..ec391319b18 --- /dev/null +++ b/src/test/rustdoc/all.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. + +#![crate_name = "foo"] + +// @has foo/all.html '//a[@href="struct.Struct.html"]' 'Struct' +// @has foo/all.html '//a[@href="enum.Enum.html"]' 'Enum' +// @has foo/all.html '//a[@href="union.Union.html"]' 'Union' +// @has foo/all.html '//a[@href="constant.CONST.html"]' 'CONST' +// @has foo/all.html '//a[@href="static.STATIC.html"]' 'STATIC' +// @has foo/all.html '//a[@href="fn.function.html"]' 'function' + +pub struct Struct; +pub enum Enum { + X, + Y, +} +pub union Union { + x: u32, +} +pub const CONST: u32 = 0; +pub static STATIC: &str = "baguette"; +pub fn function() {} diff --git a/src/test/ui/asm-out-assign-imm.rs b/src/test/ui/asm-out-assign-imm.rs index 49084e01a15..055a169deda 100644 --- a/src/test/ui/asm-out-assign-imm.rs +++ b/src/test/ui/asm-out-assign-imm.rs @@ -12,6 +12,7 @@ // ignore-emscripten // ignore-powerpc // ignore-sparc +// ignore-mips #![feature(asm)] diff --git a/src/test/ui/asm-out-assign-imm.stderr b/src/test/ui/asm-out-assign-imm.stderr index 4ec758b97f2..d9fd4b26c39 100644 --- a/src/test/ui/asm-out-assign-imm.stderr +++ b/src/test/ui/asm-out-assign-imm.stderr @@ -1,5 +1,5 @@ error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/asm-out-assign-imm.rs:29:9 + --> $DIR/asm-out-assign-imm.rs:30:9 | LL | x = 1; | ----- first assignment to `x` diff --git a/src/test/ui/augmented-assignments.nll.stderr b/src/test/ui/augmented-assignments.nll.stderr new file mode 100644 index 00000000000..deb2e7ed4a3 --- /dev/null +++ b/src/test/ui/augmented-assignments.nll.stderr @@ -0,0 +1,26 @@ +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/augmented-assignments.rs:26:5 + | +LL | x //~ error: use of moved value: `x` + | - + | | + | _____borrow of `x` occurs here + | | +LL | | //~^ value used here after move +LL | | += +LL | | x; //~ value moved here + | | - + | | | + | |_____move out of `x` occurs here + | borrow later used here + +error[E0596]: cannot borrow immutable item `y` as mutable + --> $DIR/augmented-assignments.rs:30:5 + | +LL | y //~ error: cannot borrow immutable local variable `y` as mutable + | ^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +Some errors occurred: E0505, E0596. +For more information about an error, try `rustc --explain E0505`. diff --git a/src/test/ui/borrowck/borrowck-box-insensitivity.nll.stderr b/src/test/ui/borrowck/borrowck-box-insensitivity.nll.stderr new file mode 100644 index 00000000000..1b370567ed1 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-box-insensitivity.nll.stderr @@ -0,0 +1,25 @@ +error[E0382]: use of moved value: `a.y` + --> $DIR/borrowck-box-insensitivity.rs:46:14 + | +LL | let _x = a.x; + | --- value moved here +LL | //~^ value moved here +LL | let _y = a.y; //~ ERROR use of moved + | ^^^ value used here after move + | + = note: move occurs because `a.y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `a.y` + --> $DIR/borrowck-box-insensitivity.rs:108:14 + | +LL | let _x = a.x.x; + | ----- value moved here +LL | //~^ value moved here +LL | let _y = a.y; //~ ERROR use of collaterally moved + | ^^^ value used here after move + | + = note: move occurs because `a.y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.nll.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut.nll.stderr new file mode 100644 index 00000000000..a21a6e36778 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-closures-two-mut.nll.stderr @@ -0,0 +1,78 @@ +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:24:24 + | +LL | let c1 = to_fn_mut(|| x = 4); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | //~| ERROR cannot borrow `x` as mutable more than once +LL | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:35:24 + | +LL | let c1 = to_fn_mut(|| set(&mut x)); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | //~| ERROR cannot borrow `x` as mutable more than once +LL | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:42:24 + | +LL | let c1 = to_fn_mut(|| x = 5); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +LL | //~| ERROR cannot borrow `x` as mutable more than once +LL | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:49:24 + | +LL | let c1 = to_fn_mut(|| x = 5); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +... +LL | } + | - first borrow ends here + +error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) + --> $DIR/borrowck-closures-two-mut.rs:61:24 + | +LL | let c1 = to_fn_mut(|| set(&mut *x.f)); + | -- - previous borrow occurs due to use of `x` in closure + | | + | first mutable borrow occurs here +LL | let c2 = to_fn_mut(|| set(&mut *x.f)); + | ^^ - borrow occurs due to use of `x` in closure + | | + | second mutable borrow occurs here +... +LL | } + | - first borrow ends here + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-escaping-closure-error-1.nll.stderr b/src/test/ui/borrowck/borrowck-escaping-closure-error-1.nll.stderr new file mode 100644 index 00000000000..b931bc45b77 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-escaping-closure-error-1.nll.stderr @@ -0,0 +1,14 @@ +error[E0597]: `books` does not live long enough + --> $DIR/borrowck-escaping-closure-error-1.rs:23:11 + | +LL | spawn(|| books.push(4)); + | ^^^^^^^^^^^^^^^^ borrowed value does not live long enough +LL | //~^ ERROR E0373 +LL | } + | - borrowed value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-escaping-closure-error-2.nll.stderr b/src/test/ui/borrowck/borrowck-escaping-closure-error-2.nll.stderr new file mode 100644 index 00000000000..2b5070977a3 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-escaping-closure-error-2.nll.stderr @@ -0,0 +1,18 @@ +error[E0597]: `books` does not live long enough + --> $DIR/borrowck-escaping-closure-error-2.rs:21:14 + | +LL | Box::new(|| books.push(4)) + | ^^^^^^^^^^^^^^^^ borrowed value does not live long enough +LL | //~^ ERROR E0373 +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 19:1... + --> $DIR/borrowck-escaping-closure-error-2.rs:19:1 + | +LL | fn foo<'a>(x: &'a i32) -> Box<FnMut()+'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/borrowck/borrowck-in-static.nll.stderr b/src/test/ui/borrowck/borrowck-in-static.nll.stderr new file mode 100644 index 00000000000..927d8c37458 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-in-static.nll.stderr @@ -0,0 +1,9 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-in-static.rs:15:17 + | +LL | Box::new(|| x) //~ ERROR cannot move out of captured outer variable + | ^ cannot move out of borrowed content + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr b/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr new file mode 100644 index 00000000000..c563a28b317 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-error-with-note.nll.stderr @@ -0,0 +1,40 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-move-error-with-note.rs:23:19 + | +LL | Foo::Foo1(num1, + | ^^^^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-move-error-with-note.rs:24:19 + | +LL | num2) => (), + | ^^^^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-move-error-with-note.rs:25:19 + | +LL | Foo::Foo2(num) => (), + | ^^^ cannot move out of borrowed content + +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-error-with-note.rs:42:16 + | +LL | f: _s, + | ^^ cannot move out of here + +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/borrowck-move-error-with-note.rs:43:16 + | +LL | g: _t + | ^^ cannot move out of here + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-move-error-with-note.rs:59:9 + | +LL | n => { + | ^ cannot move out of borrowed content + +error: aborting due to 6 previous errors + +Some errors occurred: E0507, E0509. +For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr new file mode 100644 index 00000000000..a430c97158a --- /dev/null +++ b/src/test/ui/borrowck/borrowck-move-out-of-vec-tail.nll.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-move-out-of-vec-tail.rs:30:33 + | +LL | &[Foo { string: a }, + | ^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-move-out-of-vec-tail.rs:34:33 + | +LL | Foo { string: b }] => { + | ^ cannot move out of borrowed content + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.nll.stderr b/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.nll.stderr new file mode 100644 index 00000000000..951907876b9 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/borrowck-report-with-custom-diagnostic.rs:12:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | // Original borrow ends at end of function +LL | | let mut x = 1; +LL | | let y = &mut x; +... | +LL | | //~^ immutable borrow occurs here +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.rs b/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.rs index a6553160557..cdfee2e8a70 100644 --- a/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.rs +++ b/src/test/ui/borrowck/borrowck-report-with-custom-diagnostic.rs @@ -7,9 +7,9 @@ // <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. - +#![feature(rustc_attrs)] #![allow(dead_code)] -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 // Original borrow ends at end of function let mut x = 1; let y = &mut x; diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr new file mode 100644 index 00000000000..d5a66a6c706 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.nll.stderr @@ -0,0 +1,51 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-vec-pattern-nesting.rs:42:15 + | +LL | &mut [_a, //~ ERROR cannot move out + | ^^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-vec-pattern-nesting.rs:55:13 + | +LL | let a = vec[0]; //~ ERROR cannot move out + | ^^^^^^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-vec-pattern-nesting.rs:65:10 + | +LL | _b] => {} + | ^^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-vec-pattern-nesting.rs:68:13 + | +LL | let a = vec[0]; //~ ERROR cannot move out + | ^^^^^^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-vec-pattern-nesting.rs:76:15 + | +LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out + | ^^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-vec-pattern-nesting.rs:76:19 + | +LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out + | ^^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-vec-pattern-nesting.rs:76:23 + | +LL | &mut [_a, _b, _c] => {} //~ ERROR cannot move out + | ^^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-vec-pattern-nesting.rs:80:13 + | +LL | let a = vec[0]; //~ ERROR cannot move out + | ^^^^^^ cannot move out of borrowed content + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr new file mode 100644 index 00000000000..ecd17edb079 --- /dev/null +++ b/src/test/ui/borrowck/issue-45983.nll.stderr @@ -0,0 +1,30 @@ +warning: not reporting region error due to -Znll + --> $DIR/issue-45983.rs:17:27 + | +LL | give_any(|y| x = Some(y)); + | ^ + +error: free region `` does not outlive free region `'_#2r` + --> $DIR/issue-45983.rs:17:27 + | +LL | give_any(|y| x = Some(y)); + | ^ + +error[E0594]: cannot assign to immutable item `x` + --> $DIR/issue-45983.rs:17:18 + | +LL | give_any(|y| x = Some(y)); + | ^^^^^^^^^^^ cannot mutate + | + = note: Value not mutable causing this error: `x` + +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/issue-45983.rs:17:14 + | +LL | give_any(|y| x = Some(y)); + | ^^^^^^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 3 previous errors + +Some errors occurred: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/borrowck/issue-7573.nll.stderr b/src/test/ui/borrowck/issue-7573.nll.stderr new file mode 100644 index 00000000000..c55c49604d0 --- /dev/null +++ b/src/test/ui/borrowck/issue-7573.nll.stderr @@ -0,0 +1,14 @@ +warning: not reporting region error due to -Znll + --> $DIR/issue-7573.rs:27:31 + | +LL | let mut lines_to_use: Vec<&CrateId> = Vec::new(); + | ^ + +error: free region `` does not outlive free region `'_#2r` + --> $DIR/issue-7573.rs:32:9 + | +LL | lines_to_use.push(installed_id); + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr b/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr new file mode 100644 index 00000000000..fc288e6b1d6 --- /dev/null +++ b/src/test/ui/borrowck/mut-borrow-in-loop.nll.stderr @@ -0,0 +1,21 @@ +error[E0499]: cannot borrow `*arg` as mutable more than once at a time + --> $DIR/mut-borrow-in-loop.rs:20:25 + | +LL | (self.func)(arg) //~ ERROR cannot borrow + | ^^^ mutable borrow starts here in previous iteration of loop + +error[E0499]: cannot borrow `*arg` as mutable more than once at a time + --> $DIR/mut-borrow-in-loop.rs:26:25 + | +LL | (self.func)(arg) //~ ERROR cannot borrow + | ^^^ mutable borrow starts here in previous iteration of loop + +error[E0499]: cannot borrow `*arg` as mutable more than once at a time + --> $DIR/mut-borrow-in-loop.rs:33:25 + | +LL | (self.func)(arg) //~ ERROR cannot borrow + | ^^^ mutable borrow starts here in previous iteration of loop + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr b/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr new file mode 100644 index 00000000000..dab769820a6 --- /dev/null +++ b/src/test/ui/borrowck/mut-borrow-outside-loop.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/mut-borrow-outside-loop.rs:13:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut void = (); +LL | | +LL | | let first = &mut void; +... | +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/mut-borrow-outside-loop.rs b/src/test/ui/borrowck/mut-borrow-outside-loop.rs index a1ab41bab33..edc877718ad 100644 --- a/src/test/ui/borrowck/mut-borrow-outside-loop.rs +++ b/src/test/ui/borrowck/mut-borrow-outside-loop.rs @@ -9,8 +9,8 @@ // except according to those terms. // ensure borrowck messages are correct outside special case - -fn main() { +#![feature(rustc_attrs)] +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut void = (); let first = &mut void; diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr new file mode 100644 index 00000000000..d34a716bb2b --- /dev/null +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr @@ -0,0 +1,14 @@ +warning: not reporting region error due to -Znll + --> $DIR/regions-escape-bound-fn-2.rs:18:27 + | +LL | with_int(|y| x = Some(y)); + | ^ + +error: free region `` does not outlive free region `'_#2r` + --> $DIR/regions-escape-bound-fn-2.rs:18:27 + | +LL | with_int(|y| x = Some(y)); + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr new file mode 100644 index 00000000000..b69c172bcdc --- /dev/null +++ b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr @@ -0,0 +1,14 @@ +warning: not reporting region error due to -Znll + --> $DIR/regions-escape-bound-fn.rs:18:22 + | +LL | with_int(|y| x = Some(y)); + | ^^^^^^^ + +error: free region `` does not outlive free region `'_#2r` + --> $DIR/regions-escape-bound-fn.rs:18:27 + | +LL | with_int(|y| x = Some(y)); + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr new file mode 100644 index 00000000000..788654a2ecc --- /dev/null +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr @@ -0,0 +1,14 @@ +warning: not reporting region error due to -Znll + --> $DIR/regions-escape-unboxed-closure.rs:16:27 + | +LL | with_int(&mut |y| x = Some(y)); + | ^^^^^^^ + +error: free region `` does not outlive free region `'_#2r` + --> $DIR/regions-escape-unboxed-closure.rs:16:32 + | +LL | with_int(&mut |y| x = Some(y)); + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr new file mode 100644 index 00000000000..7464e33e8c1 --- /dev/null +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.nll.stderr @@ -0,0 +1,9 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:21:9 + | +LL | y.into_iter(); + | ^ cannot move out of borrowed content + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/catch-block-type-error.rs b/src/test/ui/catch-block-type-error.rs new file mode 100644 index 00000000000..10130ef1e5d --- /dev/null +++ b/src/test/ui/catch-block-type-error.rs @@ -0,0 +1,26 @@ +// 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. + +#![feature(catch_expr)] + +fn foo() -> Option<()> { Some(()) } + +fn main() { + let _: Option<f32> = do catch { + foo()?; + 42 + //~^ ERROR type mismatch + }; + + let _: Option<i32> = do catch { + foo()?; + }; + //~^ ERROR type mismatch +} diff --git a/src/test/ui/catch-block-type-error.stderr b/src/test/ui/catch-block-type-error.stderr new file mode 100644 index 00000000000..0ae8d4862f7 --- /dev/null +++ b/src/test/ui/catch-block-type-error.stderr @@ -0,0 +1,21 @@ +error[E0271]: type mismatch resolving `<std::option::Option<f32> as std::ops::Try>::Ok == {integer}` + --> $DIR/catch-block-type-error.rs:18:9 + | +LL | 42 + | ^^ expected f32, found integral variable + | + = note: expected type `f32` + found type `{integer}` + +error[E0271]: type mismatch resolving `<std::option::Option<i32> as std::ops::Try>::Ok == ()` + --> $DIR/catch-block-type-error.rs:24:5 + | +LL | }; + | ^ expected i32, found () + | + = note: expected type `i32` + found type `()` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/chalkify/lower_trait.rs b/src/test/ui/chalkify/lower_trait.rs index 010cb77edc3..74feb0105cc 100644 --- a/src/test/ui/chalkify/lower_trait.rs +++ b/src/test/ui/chalkify/lower_trait.rs @@ -11,6 +11,9 @@ #![feature(rustc_attrs)] #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- + //~| ERROR FromEnv + //~| ERROR FromEnv + //~| ERROR FromEnv trait Foo<S, T, U> { fn s(S) -> S; fn t(T) -> T; diff --git a/src/test/ui/chalkify/lower_trait.stderr b/src/test/ui/chalkify/lower_trait.stderr index 6da1e2fd8ed..45753c3bb90 100644 --- a/src/test/ui/chalkify/lower_trait.stderr +++ b/src/test/ui/chalkify/lower_trait.stderr @@ -4,5 +4,23 @@ error: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>). LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>). + --> $DIR/lower_trait.rs:13:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>). + --> $DIR/lower_trait.rs:13:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>). + --> $DIR/lower_trait.rs:13:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.rs b/src/test/ui/chalkify/lower_trait_higher_rank.rs new file mode 100644 index 00000000000..e5eaf4591ec --- /dev/null +++ b/src/test/ui/chalkify/lower_trait_higher_rank.rs @@ -0,0 +1,24 @@ +// 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. + +#![feature(rustc_attrs)] + +#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- + //~| ERROR FromEnv + //~| ERROR FromEnv + //~| ERROR FromEnv +trait Foo<F> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8 +{ + fn s(F) -> F; +} + +fn main() { + println!("hello"); +} diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.stderr b/src/test/ui/chalkify/lower_trait_higher_rank.stderr new file mode 100644 index 00000000000..9aed0c018c9 --- /dev/null +++ b/src/test/ui/chalkify/lower_trait_higher_rank.stderr @@ -0,0 +1,26 @@ +error: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>). + --> $DIR/lower_trait_higher_rank.rs:13:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: FromEnv(F: std::marker::Sized) :- FromEnv(Self: Foo<F>). + --> $DIR/lower_trait_higher_rank.rs:13:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>). + --> $DIR/lower_trait_higher_rank.rs:13:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: FromEnv(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>). + --> $DIR/lower_trait_higher_rank.rs:13:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/chalkify/lower_trait_where_clause.rs b/src/test/ui/chalkify/lower_trait_where_clause.rs new file mode 100644 index 00000000000..b2ce3ca48b2 --- /dev/null +++ b/src/test/ui/chalkify/lower_trait_where_clause.rs @@ -0,0 +1,31 @@ +// 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. + +#![feature(rustc_attrs)] + +use std::fmt::{Debug, Display}; +use std::borrow::Borrow; + +#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- + //~| ERROR FromEnv + //~| ERROR FromEnv + //~| ERROR FromEnv + //~| ERROR FromEnv + //~| ERROR RegionOutlives + //~| ERROR TypeOutlives +trait Foo<'a, 'b, S, T, U> where S: Debug, T: Borrow<U>, U: ?Sized, 'a: 'b, U: 'b { + fn s(S) -> S; + fn t(T) -> T; + fn u(U) -> U; +} + +fn main() { + println!("hello"); +} diff --git a/src/test/ui/chalkify/lower_trait_where_clause.stderr b/src/test/ui/chalkify/lower_trait_where_clause.stderr new file mode 100644 index 00000000000..a9ecaec3aff --- /dev/null +++ b/src/test/ui/chalkify/lower_trait_where_clause.stderr @@ -0,0 +1,44 @@ +error: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + --> $DIR/lower_trait_where_clause.rs:16:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + --> $DIR/lower_trait_where_clause.rs:16:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + --> $DIR/lower_trait_where_clause.rs:16:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: FromEnv(S: std::fmt::Debug) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + --> $DIR/lower_trait_where_clause.rs:16:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + --> $DIR/lower_trait_where_clause.rs:16:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + --> $DIR/lower_trait_where_clause.rs:16:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + --> $DIR/lower_trait_where_clause.rs:16:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr b/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr new file mode 100644 index 00000000000..18edf2addc5 --- /dev/null +++ b/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr @@ -0,0 +1,44 @@ +warning: not reporting region error due to -Znll + --> $DIR/expect-region-supply-region.rs:28:13 + | +LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/expect-region-supply-region.rs:38:13 + | +LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/expect-region-supply-region.rs:47:33 + | +LL | closure_expecting_bound(|x: &'x u32| { + | ^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/expect-region-supply-region.rs:52:13 + | +LL | f = Some(x); + | ^^^^^^^ + +error: free region `` does not outlive free region `'_#2r` + --> $DIR/expect-region-supply-region.rs:28:18 + | +LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure + | ^ + +error: free region `` does not outlive free region `'_#2r` + --> $DIR/expect-region-supply-region.rs:38:18 + | +LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure + | ^ + +error: free region `` does not outlive free region `'_#2r` + --> $DIR/expect-region-supply-region.rs:52:18 + | +LL | f = Some(x); + | ^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/closure_context/issue-42065.nll.stderr b/src/test/ui/closure_context/issue-42065.nll.stderr new file mode 100644 index 00000000000..bda8a3b85f7 --- /dev/null +++ b/src/test/ui/closure_context/issue-42065.nll.stderr @@ -0,0 +1,11 @@ +error[E0382]: use of moved value: `debug_dump_dict` + --> $DIR/issue-42065.rs:21:5 + | +LL | debug_dump_dict(); + | --------------- value moved here +LL | debug_dump_dict(); + | ^^^^^^^^^^^^^^^ value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr b/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr new file mode 100644 index 00000000000..4526616e488 --- /dev/null +++ b/src/test/ui/codemap_tests/huge_multispan_highlight.nll.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/huge_multispan_highlight.rs:100:13 + | +LL | let y = &mut x; //~ ERROR cannot borrow + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/codemap_tests/issue-11715.nll.stderr b/src/test/ui/codemap_tests/issue-11715.nll.stderr new file mode 100644 index 00000000000..952ccdb98da --- /dev/null +++ b/src/test/ui/codemap_tests/issue-11715.nll.stderr @@ -0,0 +1,12 @@ +error: compilation successful + --> $DIR/issue-11715.rs:97:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut x = "foo"; +LL | | let y = &mut x; +LL | | let z = &mut x; //~ ERROR cannot borrow +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/codemap_tests/issue-11715.rs b/src/test/ui/codemap_tests/issue-11715.rs index 75581d38927..03c85fbfcd7 100644 --- a/src/test/ui/codemap_tests/issue-11715.rs +++ b/src/test/ui/codemap_tests/issue-11715.rs @@ -93,8 +93,8 @@ - -fn main() { +#![feature(rustc_attrs)] +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut x = "foo"; let y = &mut x; let z = &mut x; //~ ERROR cannot borrow diff --git a/src/test/ui/codemap_tests/one_line.nll.stderr b/src/test/ui/codemap_tests/one_line.nll.stderr new file mode 100644 index 00000000000..52ce3787f58 --- /dev/null +++ b/src/test/ui/codemap_tests/one_line.nll.stderr @@ -0,0 +1,13 @@ +error[E0499]: cannot borrow `v` as mutable more than once at a time + --> $DIR/one_line.rs:13:12 + | +LL | v.push(v.pop().unwrap()); //~ ERROR cannot borrow + | -------^---------------- + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here + | borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/codemap_tests/overlapping_spans.nll.stderr b/src/test/ui/codemap_tests/overlapping_spans.nll.stderr new file mode 100644 index 00000000000..b6630b2e666 --- /dev/null +++ b/src/test/ui/codemap_tests/overlapping_spans.nll.stderr @@ -0,0 +1,9 @@ +error[E0509]: cannot move out of type `S`, which implements the `Drop` trait + --> $DIR/overlapping_spans.rs:21:14 + | +LL | S {f:_s} => {} //~ ERROR cannot move out + | ^^ cannot move out of here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/codemap_tests/tab_3.nll.stderr b/src/test/ui/codemap_tests/tab_3.nll.stderr new file mode 100644 index 00000000000..c56cb7772c8 --- /dev/null +++ b/src/test/ui/codemap_tests/tab_3.nll.stderr @@ -0,0 +1,14 @@ +error[E0382]: borrow of moved value: `some_vec` + --> $DIR/tab_3.rs:17:20 + | +LL | some_vec.into_iter(); + | -------- value moved here +LL | { +LL | println!("{:?}", some_vec); //~ ERROR use of moved + | ^^^^^^^^ value borrowed here after move + | + = note: move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/command-line-diagnostics.nll.stderr b/src/test/ui/command-line-diagnostics.nll.stderr new file mode 100644 index 00000000000..2d5a31f0586 --- /dev/null +++ b/src/test/ui/command-line-diagnostics.nll.stderr @@ -0,0 +1,11 @@ +error[E0384]: cannot assign twice to immutable variable `x` + --> $DIR/command-line-diagnostics.rs:16:5 + | +LL | let x = 42; + | -- first assignment to `x` +LL | x = 43; + | ^^^^^^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/did_you_mean/issue-31424.nll.stderr b/src/test/ui/did_you_mean/issue-31424.nll.stderr new file mode 100644 index 00000000000..6b63f64c699 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-31424.nll.stderr @@ -0,0 +1,15 @@ +error[E0596]: cannot borrow immutable item `self` as mutable + --> $DIR/issue-31424.rs:17:9 + | +LL | (&mut self).bar(); //~ ERROR cannot borrow + | ^^^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `self` as mutable + --> $DIR/issue-31424.rs:23:9 + | +LL | (&mut self).bar(); //~ ERROR cannot borrow + | ^^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-34126.nll.stderr b/src/test/ui/did_you_mean/issue-34126.nll.stderr new file mode 100644 index 00000000000..afdc26a75c7 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34126.nll.stderr @@ -0,0 +1,13 @@ +error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable + --> $DIR/issue-34126.rs:16:18 + | +LL | self.run(&mut self); //~ ERROR cannot borrow + | ---------^^^^^^^^^- + | | | + | | mutable borrow occurs here + | immutable borrow occurs here + | borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/did_you_mean/issue-34337.nll.stderr b/src/test/ui/did_you_mean/issue-34337.nll.stderr new file mode 100644 index 00000000000..258e1bb1ad7 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-34337.nll.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow immutable item `key` as mutable + --> $DIR/issue-34337.rs:16:9 + | +LL | get(&mut key); //~ ERROR cannot borrow + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-35937.nll.stderr b/src/test/ui/did_you_mean/issue-35937.nll.stderr new file mode 100644 index 00000000000..7b5f452d322 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35937.nll.stderr @@ -0,0 +1,28 @@ +error[E0596]: cannot borrow immutable item `f.v` as mutable + --> $DIR/issue-35937.rs:17:5 + | +LL | f.v.push("cat".to_string()); //~ ERROR cannot borrow + | ^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `f` + +error[E0384]: cannot assign twice to immutable variable `s.x` + --> $DIR/issue-35937.rs:26:5 + | +LL | let s = S { x: 42 }; + | ----------- first assignment to `s.x` +LL | s.x += 1; //~ ERROR cannot assign + | ^^^^^^^^ cannot assign twice to immutable variable + +error[E0384]: cannot assign twice to immutable variable `s.x` + --> $DIR/issue-35937.rs:30:5 + | +LL | fn bar(s: S) { + | - first assignment to `s.x` +LL | s.x += 1; //~ ERROR cannot assign + | ^^^^^^^^ cannot assign twice to immutable variable + +error: aborting due to 3 previous errors + +Some errors occurred: E0384, E0596. +For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/did_you_mean/issue-37139.nll.stderr b/src/test/ui/did_you_mean/issue-37139.nll.stderr new file mode 100644 index 00000000000..29c7192a98b --- /dev/null +++ b/src/test/ui/did_you_mean/issue-37139.nll.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/issue-37139.rs:22:18 + | +LL | test(&mut x); //~ ERROR cannot borrow immutable + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-38147-1.nll.stderr b/src/test/ui/did_you_mean/issue-38147-1.nll.stderr new file mode 100644 index 00000000000..099479eaf2b --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-1.nll.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow immutable item `*self.s` as mutable + --> $DIR/issue-38147-1.rs:27:9 + | +LL | self.s.push('x'); //~ ERROR cannot borrow data mutably + | ^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*self` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-38147-2.nll.stderr b/src/test/ui/did_you_mean/issue-38147-2.nll.stderr new file mode 100644 index 00000000000..c8e231ea3b3 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-2.nll.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow immutable item `*self.s` as mutable + --> $DIR/issue-38147-2.rs:17:9 + | +LL | self.s.push('x'); + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-38147-3.nll.stderr b/src/test/ui/did_you_mean/issue-38147-3.nll.stderr new file mode 100644 index 00000000000..c5d6551b647 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-3.nll.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow immutable item `*self.s` as mutable + --> $DIR/issue-38147-3.rs:17:9 + | +LL | self.s.push('x'); + | ^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-38147-4.nll.stderr b/src/test/ui/did_you_mean/issue-38147-4.nll.stderr new file mode 100644 index 00000000000..5649fc903a0 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-38147-4.nll.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow immutable item `*f.s` as mutable + --> $DIR/issue-38147-4.rs:16:5 + | +LL | f.s.push('x'); //~ ERROR cannot borrow data mutably + | ^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*f` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-39544.nll.stderr b/src/test/ui/did_you_mean/issue-39544.nll.stderr new file mode 100644 index 00000000000..6e57796aa45 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-39544.nll.stderr @@ -0,0 +1,98 @@ +error[E0596]: cannot borrow immutable item `z.x` as mutable + --> $DIR/issue-39544.rs:21:13 + | +LL | let _ = &mut z.x; //~ ERROR cannot borrow + | ^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `z` + +error[E0596]: cannot borrow immutable item `self.x` as mutable + --> $DIR/issue-39544.rs:26:17 + | +LL | let _ = &mut self.x; //~ ERROR cannot borrow + | ^^^^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*self` + +error[E0596]: cannot borrow immutable item `self.x` as mutable + --> $DIR/issue-39544.rs:30:17 + | +LL | let _ = &mut self.x; //~ ERROR cannot borrow + | ^^^^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*self` + +error[E0596]: cannot borrow immutable item `other.x` as mutable + --> $DIR/issue-39544.rs:31:17 + | +LL | let _ = &mut other.x; //~ ERROR cannot borrow + | ^^^^^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*other` + +error[E0596]: cannot borrow immutable item `self.x` as mutable + --> $DIR/issue-39544.rs:35:17 + | +LL | let _ = &mut self.x; //~ ERROR cannot borrow + | ^^^^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*self` + +error[E0596]: cannot borrow immutable item `other.x` as mutable + --> $DIR/issue-39544.rs:36:17 + | +LL | let _ = &mut other.x; //~ ERROR cannot borrow + | ^^^^^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*other` + +error[E0596]: cannot borrow immutable item `self.x` as mutable + --> $DIR/issue-39544.rs:40:17 + | +LL | let _ = &mut self.x; //~ ERROR cannot borrow + | ^^^^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*self` + +error[E0596]: cannot borrow immutable item `other.x` as mutable + --> $DIR/issue-39544.rs:41:17 + | +LL | let _ = &mut other.x; //~ ERROR cannot borrow + | ^^^^^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*other` + +error[E0596]: cannot borrow immutable item `other.x` as mutable + --> $DIR/issue-39544.rs:45:17 + | +LL | let _ = &mut other.x; //~ ERROR cannot borrow + | ^^^^^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*other` + +error[E0596]: cannot borrow immutable item `z.x` as mutable + --> $DIR/issue-39544.rs:51:13 + | +LL | let _ = &mut z.x; //~ ERROR cannot borrow + | ^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `z` + +error[E0596]: cannot borrow immutable item `w.x` as mutable + --> $DIR/issue-39544.rs:52:13 + | +LL | let _ = &mut w.x; //~ ERROR cannot borrow + | ^^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*w` + +error[E0594]: cannot assign to immutable item `*x.0` + --> $DIR/issue-39544.rs:58:5 + | +LL | *x.0 = 1; + | ^^^^^^^^ cannot mutate + +error: aborting due to 12 previous errors + +Some errors occurred: E0594, E0596. +For more information about an error, try `rustc --explain E0594`. diff --git a/src/test/ui/did_you_mean/issue-40823.nll.stderr b/src/test/ui/did_you_mean/issue-40823.nll.stderr new file mode 100644 index 00000000000..489e1c39c46 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40823.nll.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow immutable item `*buf` as mutable + --> $DIR/issue-40823.rs:13:5 + | +LL | buf.iter_mut(); //~ ERROR cannot borrow immutable borrowed content + | ^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.rs b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.rs new file mode 100644 index 00000000000..45265173419 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.rs @@ -0,0 +1,44 @@ +// 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. + +fn gratitude() { + let for_you = false; + if not for_you { + //~^ ERROR unexpected `for_you` after identifier + println!("I couldn't"); + } +} + +fn qualification() { + let the_worst = true; + while not the_worst { + //~^ ERROR unexpected `the_worst` after identifier + println!("still pretty bad"); + } +} + +fn should_we() { + let not = true; + if not // lack of braces is [sic] + println!("Then when?"); + //~^ ERROR expected `{`, found `; + //~| ERROR unexpected `println` after identifier +} + +fn sleepy() { + let resource = not 2; + //~^ ERROR unexpected `2` after identifier +} + +fn main() { + let be_smothered_out_before = true; + let young_souls = not be_smothered_out_before; + //~^ ERROR unexpected `be_smothered_out_before` after identifier +} diff --git a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr new file mode 100644 index 00000000000..db3478116cb --- /dev/null +++ b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr @@ -0,0 +1,50 @@ +error: unexpected `for_you` after identifier + --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:13:12 + | +LL | if not for_you { + | ----^^^^^^^ + | | + | help: use `!` to perform logical negation + +error: unexpected `the_worst` after identifier + --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:21:15 + | +LL | while not the_worst { + | ----^^^^^^^^^ + | | + | help: use `!` to perform logical negation + +error: unexpected `println` after identifier + --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:30:9 + | +LL | if not // lack of braces is [sic] + | ----- help: use `!` to perform logical negation +LL | println!("Then when?"); + | ^^^^^^^ + +error: expected `{`, found `;` + --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:30:31 + | +LL | if not // lack of braces is [sic] + | -- this `if` statement has a condition, but no block +LL | println!("Then when?"); + | ^ + +error: unexpected `2` after identifier + --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:36:24 + | +LL | let resource = not 2; + | ----^ + | | + | help: use `!` to perform logical negation + +error: unexpected `be_smothered_out_before` after identifier + --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:42:27 + | +LL | let young_souls = not be_smothered_out_before; + | ----^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: use `!` to perform logical negation + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.nll.stderr b/src/test/ui/dropck/dropck-eyepatch-extern-crate.nll.stderr new file mode 100644 index 00000000000..692f697e889 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/dropck-eyepatch-extern-crate.rs:27:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | use std::cell::Cell; +LL | | let c_long; +LL | | let (c, mut dt, mut dr, mut pt, mut pr, st, sr) +... | +LL | | println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs index 4f88b0e6fcc..e06b47a8d79 100644 --- a/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.rs @@ -19,12 +19,12 @@ // // See also dropck-eyepatch.rs for more information about the general // structure of the test. - +#![feature(rustc_attrs)] extern crate dropck_eyepatch_extern_crate as other; use other::{Dt,Dr,Pt,Pr,St,Sr}; -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 use std::cell::Cell; let c_long; let (c, mut dt, mut dr, mut pt, mut pr, st, sr) diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.nll.stderr b/src/test/ui/dropck/dropck-eyepatch-reorder.nll.stderr new file mode 100644 index 00000000000..f50168fd586 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/dropck-eyepatch-reorder.rs:44:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | use std::cell::Cell; +LL | | let c_long; +LL | | let (c, mut dt, mut dr, mut pt, mut pr, st, sr) +... | +LL | | println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/dropck/dropck-eyepatch-reorder.rs b/src/test/ui/dropck/dropck-eyepatch-reorder.rs index eda8d85f6ec..832eeacbec5 100644 --- a/src/test/ui/dropck/dropck-eyepatch-reorder.rs +++ b/src/test/ui/dropck/dropck-eyepatch-reorder.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dropck_eyepatch)] +#![feature(dropck_eyepatch, rustc_attrs)] // The point of this test is to test uses of `#[may_dangle]` attribute // where the formal declaration order (in the impl generics) does not @@ -41,7 +41,7 @@ unsafe impl<'b, #[may_dangle] 'a, B: fmt::Debug> Drop for Pr<'a, 'b, B> { fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } } -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 use std::cell::Cell; let c_long; let (c, mut dt, mut dr, mut pt, mut pr, st, sr) diff --git a/src/test/ui/dropck/dropck-eyepatch.nll.stderr b/src/test/ui/dropck/dropck-eyepatch.nll.stderr new file mode 100644 index 00000000000..8c55fdbc0b8 --- /dev/null +++ b/src/test/ui/dropck/dropck-eyepatch.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/dropck-eyepatch.rs:67:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | use std::cell::Cell; +LL | | let c_long; +LL | | let (c, mut dt, mut dr, mut pt, mut pr, st, sr) +... | +LL | | println!("{:?}", (dt.0, dr.0, pt.0, pr.0, st.0, sr.0)); +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/dropck/dropck-eyepatch.rs b/src/test/ui/dropck/dropck-eyepatch.rs index af173a2e979..cfa67837485 100644 --- a/src/test/ui/dropck/dropck-eyepatch.rs +++ b/src/test/ui/dropck/dropck-eyepatch.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dropck_eyepatch)] +#![feature(dropck_eyepatch, rustc_attrs)] // The point of this test is to illustrate that the `#[may_dangle]` // attribute specifically allows, in the context of a type @@ -64,7 +64,7 @@ unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> { fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); } } -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 use std::cell::Cell; let c_long; let (c, mut dt, mut dr, mut pt, mut pr, st, sr) diff --git a/src/test/ui/error-codes/E0017.nll.stderr b/src/test/ui/error-codes/E0017.nll.stderr new file mode 100644 index 00000000000..ec31f5d05d7 --- /dev/null +++ b/src/test/ui/error-codes/E0017.nll.stderr @@ -0,0 +1,28 @@ +error[E0017]: references in constants may only refer to immutable values + --> $DIR/E0017.rs:14:30 + | +LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 + | ^^^^^^ constants require immutable values + +error[E0017]: references in statics may only refer to immutable values + --> $DIR/E0017.rs:15:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 + | ^^^^^^ statics require immutable values + +error[E0017]: references in statics may only refer to immutable values + --> $DIR/E0017.rs:17:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 + | ^^^^^^ statics require immutable values + +error[E0596]: cannot borrow immutable item `X` as mutable + --> $DIR/E0017.rs:15:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 + | ^^^^^^ cannot borrow as mutable + +error: aborting due to 4 previous errors + +Some errors occurred: E0017, E0596. +For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0161.nll.stderr b/src/test/ui/error-codes/E0161.nll.stderr new file mode 100644 index 00000000000..6aaff743383 --- /dev/null +++ b/src/test/ui/error-codes/E0161.nll.stderr @@ -0,0 +1,16 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/E0161.rs:14:28 + | +LL | let _x: Box<str> = box *"hello"; //~ ERROR E0161 + | ^^^^^^^^ cannot move out of borrowed content + +error[E0161]: cannot move a value of type str: the size of str cannot be statically determined + --> $DIR/E0161.rs:14:28 + | +LL | let _x: Box<str> = box *"hello"; //~ ERROR E0161 + | ^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors occurred: E0161, E0507. +For more information about an error, try `rustc --explain E0161`. diff --git a/src/test/ui/error-codes/E0388.nll.stderr b/src/test/ui/error-codes/E0388.nll.stderr new file mode 100644 index 00000000000..6a4bd6b31a1 --- /dev/null +++ b/src/test/ui/error-codes/E0388.nll.stderr @@ -0,0 +1,28 @@ +error[E0017]: references in constants may only refer to immutable values + --> $DIR/E0388.rs:14:30 + | +LL | const CR: &'static mut i32 = &mut C; //~ ERROR E0017 + | ^^^^^^ constants require immutable values + +error[E0017]: references in statics may only refer to immutable values + --> $DIR/E0388.rs:15:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 + | ^^^^^^ statics require immutable values + +error[E0017]: references in statics may only refer to immutable values + --> $DIR/E0388.rs:17:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017 + | ^^^^^^ statics require immutable values + +error[E0596]: cannot borrow immutable item `X` as mutable + --> $DIR/E0388.rs:15:39 + | +LL | static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0017 + | ^^^^^^ cannot borrow as mutable + +error: aborting due to 4 previous errors + +Some errors occurred: E0017, E0596. +For more information about an error, try `rustc --explain E0017`. diff --git a/src/test/ui/error-codes/E0389.nll.stderr b/src/test/ui/error-codes/E0389.nll.stderr new file mode 100644 index 00000000000..13ba653a5ca --- /dev/null +++ b/src/test/ui/error-codes/E0389.nll.stderr @@ -0,0 +1,11 @@ +error[E0594]: cannot assign to immutable item `fancy_ref.num` + --> $DIR/E0389.rs:18:5 + | +LL | fancy_ref.num = 6; //~ ERROR E0389 + | ^^^^^^^^^^^^^^^^^ cannot mutate + | + = note: Value not mutable causing this error: `*fancy_ref` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/error-codes/E0499.nll.stderr b/src/test/ui/error-codes/E0499.nll.stderr new file mode 100644 index 00000000000..27a71df147e --- /dev/null +++ b/src/test/ui/error-codes/E0499.nll.stderr @@ -0,0 +1,12 @@ +error: compilation successful + --> $DIR/E0499.rs:11:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut i = 0; +LL | | let mut x = &mut i; +LL | | let mut a = &mut i; //~ ERROR E0499 +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0499.rs b/src/test/ui/error-codes/E0499.rs index 9a64bfe2ea9..c3997236934 100644 --- a/src/test/ui/error-codes/E0499.rs +++ b/src/test/ui/error-codes/E0499.rs @@ -7,8 +7,8 @@ // <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. - -fn main() { +#![feature(rustc_attrs)] +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut i = 0; let mut x = &mut i; let mut a = &mut i; //~ ERROR E0499 diff --git a/src/test/ui/error-codes/E0502.nll.stderr b/src/test/ui/error-codes/E0502.nll.stderr new file mode 100644 index 00000000000..67a08661040 --- /dev/null +++ b/src/test/ui/error-codes/E0502.nll.stderr @@ -0,0 +1,9 @@ +error: compilation successful + --> $DIR/E0502.rs:17:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0502.rs b/src/test/ui/error-codes/E0502.rs index fce8513ca64..9c126bdcde8 100644 --- a/src/test/ui/error-codes/E0502.rs +++ b/src/test/ui/error-codes/E0502.rs @@ -7,12 +7,12 @@ // <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. - +#![feature(rustc_attrs)] fn bar(x: &mut i32) {} fn foo(a: &mut i32) { let ref y = a; bar(a); //~ ERROR E0502 } -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 } diff --git a/src/test/ui/error-codes/E0503.nll.stderr b/src/test/ui/error-codes/E0503.nll.stderr new file mode 100644 index 00000000000..6c5e99d8769 --- /dev/null +++ b/src/test/ui/error-codes/E0503.nll.stderr @@ -0,0 +1,12 @@ +error: compilation successful + --> $DIR/E0503.rs:11:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut value = 3; +LL | | let _borrow = &mut value; +LL | | let _sum = value + 1; //~ ERROR E0503 +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0503.rs b/src/test/ui/error-codes/E0503.rs index 810eb8d9b07..1822a8925d3 100644 --- a/src/test/ui/error-codes/E0503.rs +++ b/src/test/ui/error-codes/E0503.rs @@ -7,8 +7,8 @@ // <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. - -fn main() { +#![feature(rustc_attrs)] +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut value = 3; let _borrow = &mut value; let _sum = value + 1; //~ ERROR E0503 diff --git a/src/test/ui/error-codes/E0504.nll.stderr b/src/test/ui/error-codes/E0504.nll.stderr new file mode 100644 index 00000000000..ec30bb306fc --- /dev/null +++ b/src/test/ui/error-codes/E0504.nll.stderr @@ -0,0 +1,18 @@ +error[E0505]: cannot move out of `fancy_num` because it is borrowed + --> $DIR/E0504.rs:19:13 + | +LL | let fancy_ref = &fancy_num; + | ---------- borrow of `fancy_num` occurs here +LL | +LL | let x = move || { + | _____________^ +LL | | println!("child function: {}", fancy_num.num); //~ ERROR E0504 +LL | | }; + | |_____^ move out of `fancy_num` occurs here +... +LL | println!("main function: {}", fancy_ref.num); + | ------------- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/error-codes/E0505.nll.stderr b/src/test/ui/error-codes/E0505.nll.stderr new file mode 100644 index 00000000000..556e0c73d1a --- /dev/null +++ b/src/test/ui/error-codes/E0505.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/E0505.rs:15:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let x = Value{}; +LL | | { +LL | | let _ref_to_val: &Value = &x; +LL | | eat(x); //~ ERROR E0505 +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0505.rs b/src/test/ui/error-codes/E0505.rs index 2d534b8a44a..dd2980936c0 100644 --- a/src/test/ui/error-codes/E0505.rs +++ b/src/test/ui/error-codes/E0505.rs @@ -7,12 +7,12 @@ // <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. - +#![feature(rustc_attrs)] struct Value {} fn eat(val: Value) {} -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let x = Value{}; { let _ref_to_val: &Value = &x; diff --git a/src/test/ui/error-codes/E0509.nll.stderr b/src/test/ui/error-codes/E0509.nll.stderr new file mode 100644 index 00000000000..56d970494a0 --- /dev/null +++ b/src/test/ui/error-codes/E0509.nll.stderr @@ -0,0 +1,9 @@ +error[E0509]: cannot move out of type `DropStruct`, which implements the `Drop` trait + --> $DIR/E0509.rs:26:23 + | +LL | let fancy_field = drop_struct.fancy; //~ ERROR E0509 + | ^^^^^^^^^^^^^^^^^ cannot move out of here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0509`. diff --git a/src/test/ui/error-codes/E0597.nll.stderr b/src/test/ui/error-codes/E0597.nll.stderr new file mode 100644 index 00000000000..56119e4226e --- /dev/null +++ b/src/test/ui/error-codes/E0597.nll.stderr @@ -0,0 +1,13 @@ +error: compilation successful + --> $DIR/E0597.rs:15:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut x = Foo { x: None }; +LL | | let y = 0; +LL | | x.x = Some(&y); +LL | | //~^ `y` does not live long enough [E0597] +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0597.rs b/src/test/ui/error-codes/E0597.rs index 2f4a1da91d8..74178a69444 100644 --- a/src/test/ui/error-codes/E0597.rs +++ b/src/test/ui/error-codes/E0597.rs @@ -7,12 +7,12 @@ // <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. - +#![feature(rustc_attrs)] struct Foo<'a> { x: Option<&'a u32>, } -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut x = Foo { x: None }; let y = 0; x.x = Some(&y); diff --git a/src/test/ui/error-codes/E0609.stderr b/src/test/ui/error-codes/E0609.stderr index 24581889ae9..dd793b29feb 100644 --- a/src/test/ui/error-codes/E0609.stderr +++ b/src/test/ui/error-codes/E0609.stderr @@ -7,10 +7,10 @@ LL | let _ = x.foo; //~ ERROR E0609 = note: available fields are: `x` error[E0609]: no field `1` on type `Bar` - --> $DIR/E0609.rs:21:5 + --> $DIR/E0609.rs:21:7 | LL | y.1; //~ ERROR E0609 - | ^^^ + | ^ unknown field error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0611.stderr b/src/test/ui/error-codes/E0611.stderr deleted file mode 100644 index c4b86e76c14..00000000000 --- a/src/test/ui/error-codes/E0611.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0611]: field `0` of tuple-struct `a::Foo` is private - --> $DIR/E0611.rs:21:4 - | -LL | y.0; //~ ERROR E0611 - | ^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0611`. diff --git a/src/test/ui/error-codes/E0612.stderr b/src/test/ui/error-codes/E0612.stderr deleted file mode 100644 index 18013697a83..00000000000 --- a/src/test/ui/error-codes/E0612.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0612]: attempted out-of-bounds tuple index `1` on type `Foo` - --> $DIR/E0612.rs:15:4 - | -LL | y.1; //~ ERROR E0612 - | ^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0612`. diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr new file mode 100644 index 00000000000..e9f09795691 --- /dev/null +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr @@ -0,0 +1,14 @@ +warning: not reporting region error due to -Znll + --> $DIR/E0621-does-not-trigger-for-closures.rs:25:5 + | +LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 + | ^^^^^^ + +error: free region `` does not outlive free region `'_#2r` + --> $DIR/E0621-does-not-trigger-for-closures.rs:25:26 + | +LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/error-codes/E0611.rs b/src/test/ui/error-codes/ex-E0611.rs index 1e392d194b1..4e580242e64 100644 --- a/src/test/ui/error-codes/E0611.rs +++ b/src/test/ui/error-codes/ex-E0611.rs @@ -18,5 +18,5 @@ mod a { fn main() { let y = a::Foo::new(); - y.0; //~ ERROR E0611 + y.0; //~ ERROR field `0` of struct `a::Foo` is private } diff --git a/src/test/ui/error-codes/ex-E0611.stderr b/src/test/ui/error-codes/ex-E0611.stderr new file mode 100644 index 00000000000..2f5066542db --- /dev/null +++ b/src/test/ui/error-codes/ex-E0611.stderr @@ -0,0 +1,9 @@ +error[E0616]: field `0` of struct `a::Foo` is private + --> $DIR/ex-E0611.rs:21:4 + | +LL | y.0; //~ ERROR field `0` of struct `a::Foo` is private + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0616`. diff --git a/src/test/ui/error-codes/E0612.rs b/src/test/ui/error-codes/ex-E0612.rs index 429a8bb7eb7..46e26c87e5f 100644 --- a/src/test/ui/error-codes/E0612.rs +++ b/src/test/ui/error-codes/ex-E0612.rs @@ -12,5 +12,5 @@ struct Foo(u32); fn main() { let y = Foo(0); - y.1; //~ ERROR E0612 + y.1; //~ ERROR no field `1` on type `Foo` } diff --git a/src/test/ui/error-codes/ex-E0612.stderr b/src/test/ui/error-codes/ex-E0612.stderr new file mode 100644 index 00000000000..a07efc939ab --- /dev/null +++ b/src/test/ui/error-codes/ex-E0612.stderr @@ -0,0 +1,9 @@ +error[E0609]: no field `1` on type `Foo` + --> $DIR/ex-E0612.rs:15:6 + | +LL | y.1; //~ ERROR no field `1` on type `Foo` + | ^ did you mean `0`? + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/feature-gate-infer_outlives_requirements.rs b/src/test/ui/feature-gate-infer_outlives_requirements.rs new file mode 100644 index 00000000000..01ccc50a130 --- /dev/null +++ b/src/test/ui/feature-gate-infer_outlives_requirements.rs @@ -0,0 +1,18 @@ +// 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. + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + +// Type T needs to outlive lifetime 'a. +struct Foo<'a, T> { + bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309] +} + +fn main() { } diff --git a/src/test/ui/feature-gate-infer_outlives_requirements.stderr b/src/test/ui/feature-gate-infer_outlives_requirements.stderr new file mode 100644 index 00000000000..560e494b582 --- /dev/null +++ b/src/test/ui/feature-gate-infer_outlives_requirements.stderr @@ -0,0 +1,17 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/feature-gate-infer_outlives_requirements.rs:15:5 + | +LL | struct Foo<'a, T> { + | - help: consider adding an explicit lifetime bound `T: 'a`... +LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309] + | ^^^^^^^^^^^^ + | +note: ...so that the reference type `&'a [T]` does not outlive the data it points at + --> $DIR/feature-gate-infer_outlives_requirements.rs:15:5 + | +LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309] + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/feature-gate-nll.nll.stderr b/src/test/ui/feature-gate-nll.nll.stderr new file mode 100644 index 00000000000..81de0d14aa7 --- /dev/null +++ b/src/test/ui/feature-gate-nll.nll.stderr @@ -0,0 +1,13 @@ +error: compilation successful + --> $DIR/feature-gate-nll.rs:13:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut x = 33; +LL | | +LL | | let p = &x; +LL | | x = 22; //~ ERROR cannot assign to `x` because it is borrowed [E0506] +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/feature-gate-nll.rs b/src/test/ui/feature-gate-nll.rs index f34a9cddf98..752b1fa821f 100644 --- a/src/test/ui/feature-gate-nll.rs +++ b/src/test/ui/feature-gate-nll.rs @@ -7,10 +7,10 @@ // <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. - +#![feature(rustc_attrs)] #![allow(dead_code)] -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut x = 33; let p = &x; diff --git a/src/libstd_unicode/tests/lib.rs b/src/test/ui/feature-gate-repr_packed.rs index 9535ec18763..12bb152b467 100644 --- a/src/libstd_unicode/tests/lib.rs +++ b/src/test/ui/feature-gate-repr_packed.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(str_internals, unicode)] +#[repr(packed(1))] //~ error: the `#[repr(packed(n))]` attribute is experimental +struct Foo(u64); -extern crate std_unicode; - -mod lossy; +fn main() {} diff --git a/src/test/ui/feature-gate-repr_packed.stderr b/src/test/ui/feature-gate-repr_packed.stderr new file mode 100644 index 00000000000..d0faf9d90bd --- /dev/null +++ b/src/test/ui/feature-gate-repr_packed.stderr @@ -0,0 +1,11 @@ +error[E0658]: the `#[repr(packed(n))]` attribute is experimental (see issue #33158) + --> $DIR/feature-gate-repr_packed.rs:11:1 + | +LL | #[repr(packed(1))] //~ error: the `#[repr(packed(n))]` attribute is experimental + | ^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(repr_packed)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generator/borrowing.nll.stderr b/src/test/ui/generator/borrowing.nll.stderr new file mode 100644 index 00000000000..1801da6c8b2 --- /dev/null +++ b/src/test/ui/generator/borrowing.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/borrowing.rs:15:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let _b = { +LL | | let a = 3; +LL | | unsafe { (|| yield &a).resume() } +... | +LL | | }; +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/generator/borrowing.rs b/src/test/ui/generator/borrowing.rs index e56927d8182..f80aca9fb00 100644 --- a/src/test/ui/generator/borrowing.rs +++ b/src/test/ui/generator/borrowing.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators, generator_trait)] +#![feature(generators, generator_trait, rustc_attrs)] use std::ops::Generator; -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let _b = { let a = 3; unsafe { (|| yield &a).resume() } diff --git a/src/test/ui/generator/dropck.nll.stderr b/src/test/ui/generator/dropck.nll.stderr new file mode 100644 index 00000000000..72ebaab3278 --- /dev/null +++ b/src/test/ui/generator/dropck.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/dropck.rs:16:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let (cell, mut gen); +LL | | cell = Box::new(RefCell::new(0)); +LL | | let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); +... | +LL | | // drops the RefCell and then the Ref, leading to use-after-free +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/generator/dropck.rs b/src/test/ui/generator/dropck.rs index b2240fb225f..8f4ba64fd57 100644 --- a/src/test/ui/generator/dropck.rs +++ b/src/test/ui/generator/dropck.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators, generator_trait, box_leak)] +#![feature(generators, generator_trait, box_leak, rustc_attrs)] use std::cell::RefCell; use std::ops::Generator; -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let (cell, mut gen); cell = Box::new(RefCell::new(0)); let ref_ = Box::leak(Box::new(Some(cell.borrow_mut()))); diff --git a/src/test/ui/generator/pattern-borrow.nll.stderr b/src/test/ui/generator/pattern-borrow.nll.stderr new file mode 100644 index 00000000000..ec8adf9d37c --- /dev/null +++ b/src/test/ui/generator/pattern-borrow.nll.stderr @@ -0,0 +1,8 @@ +error: compilation successful + --> $DIR/pattern-borrow.rs:15:1 + | +LL | fn main() { #![rustc_error] } // rust-lang/rust#49855 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/generator/pattern-borrow.rs b/src/test/ui/generator/pattern-borrow.rs index 557a5e62f7e..dd63b9eaa5b 100644 --- a/src/test/ui/generator/pattern-borrow.rs +++ b/src/test/ui/generator/pattern-borrow.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators)] +#![feature(generators, rustc_attrs)] enum Test { A(i32), B, } -fn main() { } +fn main() { #![rustc_error] } // rust-lang/rust#49855 fn fun(test: Test) { move || { diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr new file mode 100644 index 00000000000..08839c23c37 --- /dev/null +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.nll.stderr @@ -0,0 +1,12 @@ +error[E0597]: `b` does not live long enough + --> $DIR/ref-escapes-but-not-over-yield.rs:24:13 + | +LL | a = &b; + | ^^ borrowed value does not live long enough +LL | //~^ ERROR `b` does not live long enough +LL | }; + | - borrowed value only lives until here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/generator/yield-in-args.nll.stderr b/src/test/ui/generator/yield-in-args.nll.stderr new file mode 100644 index 00000000000..6242ec0f548 --- /dev/null +++ b/src/test/ui/generator/yield-in-args.nll.stderr @@ -0,0 +1,9 @@ +error[E0626]: borrow may still be in use when generator yields + --> $DIR/yield-in-args.rs:18:13 + | +LL | foo(&b, yield); //~ ERROR + | ^^ ----- possible yield occurs here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0626`. diff --git a/src/test/ui/generator/yield-while-iterating.nll.stderr b/src/test/ui/generator/yield-while-iterating.nll.stderr new file mode 100644 index 00000000000..be4852aaf06 --- /dev/null +++ b/src/test/ui/generator/yield-while-iterating.nll.stderr @@ -0,0 +1,55 @@ +error[E0626]: borrow may still be in use when generator yields + --> $DIR/yield-while-iterating.rs:22:18 + | +LL | for p in &x { //~ ERROR + | ^^ +LL | yield(); + | ------- possible yield occurs here + +error[E0597]: borrowed value does not live long enough + --> $DIR/yield-while-iterating.rs:50:17 + | +LL | let mut b = || { + | _________________^ +LL | | for p in &mut x { +LL | | yield p; +LL | | } +LL | | }; + | | ^ + | | | + | |_____temporary value only lives until here + | temporary value does not live long enough + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/yield-while-iterating.rs:67:20 + | +LL | let mut b = || { + | _________________- +LL | | for p in &mut x { +LL | | yield p; +LL | | } +LL | | }; + | |_____- mutable borrow occurs here +LL | println!("{}", x[0]); //~ ERROR + | ^ immutable borrow occurs here +LL | b.resume(); + | - borrow later used here + +error[E0597]: borrowed value does not live long enough + --> $DIR/yield-while-iterating.rs:62:17 + | +LL | let mut b = || { + | _________________^ +LL | | for p in &mut x { +LL | | yield p; +LL | | } +LL | | }; + | | ^ + | | | + | |_____temporary value only lives until here + | temporary value does not live long enough + +error: aborting due to 4 previous errors + +Some errors occurred: E0502, E0597, E0626. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr new file mode 100644 index 00000000000..14989079527 --- /dev/null +++ b/src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr @@ -0,0 +1,18 @@ +error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access + --> $DIR/yield-while-ref-reborrowed.rs:45:20 + | +LL | let mut b = || { + | _________________- +LL | | let a = &mut *x; +LL | | yield(); +LL | | println!("{}", a); +LL | | }; + | |_____- closure construction occurs here +LL | println!("{}", x); //~ ERROR + | ^ borrow occurs here +LL | b.resume(); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0501`. diff --git a/src/test/compile-fail/hygiene/assoc_item_ctxt.rs b/src/test/ui/hygiene/assoc_item_ctxt.rs index e336b0df13f..e336b0df13f 100644 --- a/src/test/compile-fail/hygiene/assoc_item_ctxt.rs +++ b/src/test/ui/hygiene/assoc_item_ctxt.rs diff --git a/src/test/ui/hygiene/assoc_item_ctxt.stderr b/src/test/ui/hygiene/assoc_item_ctxt.stderr new file mode 100644 index 00000000000..8b410405ae5 --- /dev/null +++ b/src/test/ui/hygiene/assoc_item_ctxt.stderr @@ -0,0 +1,25 @@ +error[E0407]: method `method` is not a member of trait `Tr` + --> $DIR/assoc_item_ctxt.rs:45:13 + | +LL | fn method() {} //~ ERROR method `method` is not a member of trait `Tr` + | ^^^^^^^^^^^^^^ not a member of trait `Tr` +... +LL | mac_trait_impl!(); + | ------------------ in this macro invocation + +error[E0046]: not all trait items implemented, missing: `method` + --> $DIR/assoc_item_ctxt.rs:44:9 + | +LL | fn method(); + | ------------ `method` from trait +... +LL | impl Tr for u8 { //~ ERROR not all trait items implemented, missing: `method` + | ^^^^^^^^^^^^^^ missing `method` in implementation +... +LL | mac_trait_impl!(); + | ------------------ in this macro invocation + +error: aborting due to 2 previous errors + +Some errors occurred: E0046, E0407. +For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/compile-fail/hygiene/assoc_ty_bindings.rs b/src/test/ui/hygiene/assoc_ty_bindings.rs index 46a138749ff..46a138749ff 100644 --- a/src/test/compile-fail/hygiene/assoc_ty_bindings.rs +++ b/src/test/ui/hygiene/assoc_ty_bindings.rs diff --git a/src/test/ui/hygiene/assoc_ty_bindings.stderr b/src/test/ui/hygiene/assoc_ty_bindings.stderr new file mode 100644 index 00000000000..0adf80994f7 --- /dev/null +++ b/src/test/ui/hygiene/assoc_ty_bindings.stderr @@ -0,0 +1,8 @@ +error: compilation successful + --> $DIR/assoc_ty_bindings.rs:49:1 + | +LL | fn main() {} //~ ERROR compilation successful + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/compile-fail/hygiene/auxiliary/intercrate.rs b/src/test/ui/hygiene/auxiliary/intercrate.rs index aa67e5c5f4d..aa67e5c5f4d 100644 --- a/src/test/compile-fail/hygiene/auxiliary/intercrate.rs +++ b/src/test/ui/hygiene/auxiliary/intercrate.rs diff --git a/src/test/ui/hygiene/fields-definition.rs b/src/test/ui/hygiene/fields-definition.rs new file mode 100644 index 00000000000..c92bf55a723 --- /dev/null +++ b/src/test/ui/hygiene/fields-definition.rs @@ -0,0 +1,32 @@ +// 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. + +#![feature(decl_macro)] + +macro modern($a: ident) { + struct Modern { + a: u8, + $a: u8, // OK + } +} + +macro_rules! legacy { + ($a: ident) => { + struct Legacy { + a: u8, + $a: u8, //~ ERROR field `a` is already declared + } + } +} + +modern!(a); +legacy!(a); + +fn main() {} diff --git a/src/test/ui/hygiene/fields-definition.stderr b/src/test/ui/hygiene/fields-definition.stderr new file mode 100644 index 00000000000..73f524b7d2a --- /dev/null +++ b/src/test/ui/hygiene/fields-definition.stderr @@ -0,0 +1,14 @@ +error[E0124]: field `a` is already declared + --> $DIR/fields-definition.rs:24:17 + | +LL | a: u8, + | ----- `a` first declared here +LL | $a: u8, //~ ERROR field `a` is already declared + | ^^ field already declared +... +LL | legacy!(a); + | ----------- in this macro invocation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0124`. diff --git a/src/test/ui/hygiene/fields-move.rs b/src/test/ui/hygiene/fields-move.rs new file mode 100644 index 00000000000..a6e3b2b2d8b --- /dev/null +++ b/src/test/ui/hygiene/fields-move.rs @@ -0,0 +1,40 @@ +// 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. + +// issue #46314 + +#![feature(decl_macro)] + +#[derive(Debug)] +struct NonCopy(String); + +struct Foo { + x: NonCopy, +} + +macro copy_modern($foo: ident) { + $foo.x +} + +macro_rules! copy_legacy { + ($foo: ident) => { + $foo.x //~ ERROR use of moved value: `foo.x` + } +} + +fn assert_two_copies(a: NonCopy, b: NonCopy) { + println!("Got two copies: {:?}, {:?}", a, b); +} + +fn main() { + let foo = Foo { x: NonCopy("foo".into()) }; + assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` +} diff --git a/src/test/ui/hygiene/fields-move.stderr b/src/test/ui/hygiene/fields-move.stderr new file mode 100644 index 00000000000..ba9de09f9d2 --- /dev/null +++ b/src/test/ui/hygiene/fields-move.stderr @@ -0,0 +1,39 @@ +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:38:42 + | +LL | $foo.x + | ------ value moved here +... +LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ^^^^^ value used here after move + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:28:9 + | +LL | $foo.x + | ------ value moved here +... +LL | $foo.x //~ ERROR use of moved value: `foo.x` + | ^^^^^^ value used here after move +... +LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ----------------- in this macro invocation + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:39:42 + | +LL | $foo.x + | ------ value moved here +... +LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ^^^^^ value used here after move + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/hygiene/fields-numeric-borrowck.rs b/src/test/ui/hygiene/fields-numeric-borrowck.rs new file mode 100644 index 00000000000..50ace39e709 --- /dev/null +++ b/src/test/ui/hygiene/fields-numeric-borrowck.rs @@ -0,0 +1,18 @@ +// 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. + +struct S(u8); + +fn main() { + let mut s = S(0); + let borrow1 = &mut s.0; + let S { 0: ref mut borrow2 } = s; + //~^ ERROR cannot borrow `s.0` as mutable more than once at a time +} diff --git a/src/test/ui/hygiene/fields-numeric-borrowck.stderr b/src/test/ui/hygiene/fields-numeric-borrowck.stderr new file mode 100644 index 00000000000..ccd898fff27 --- /dev/null +++ b/src/test/ui/hygiene/fields-numeric-borrowck.stderr @@ -0,0 +1,14 @@ +error[E0499]: cannot borrow `s.0` as mutable more than once at a time + --> $DIR/fields-numeric-borrowck.rs:16:16 + | +LL | let borrow1 = &mut s.0; + | --- first mutable borrow occurs here +LL | let S { 0: ref mut borrow2 } = s; + | ^^^^^^^^^^^^^^^ second mutable borrow occurs here +LL | //~^ ERROR cannot borrow `s.0` as mutable more than once at a time +LL | } + | - first borrow ends here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/compile-fail/hygiene/fields.rs b/src/test/ui/hygiene/fields.rs index 64217770b13..64217770b13 100644 --- a/src/test/compile-fail/hygiene/fields.rs +++ b/src/test/ui/hygiene/fields.rs diff --git a/src/test/ui/hygiene/fields.stderr b/src/test/ui/hygiene/fields.stderr new file mode 100644 index 00000000000..c4be1834c04 --- /dev/null +++ b/src/test/ui/hygiene/fields.stderr @@ -0,0 +1,38 @@ +error: type `foo::S` is private + --> $DIR/fields.rs:25:17 + | +LL | let s = S { x: 0 }; //~ ERROR type `foo::S` is private + | ^^^^^^^^^^ +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + +error: type `foo::S` is private + --> $DIR/fields.rs:26:17 + | +LL | let _ = s.x; //~ ERROR type `foo::S` is private + | ^ +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + +error: type `foo::T` is private + --> $DIR/fields.rs:28:17 + | +LL | let t = T(0); //~ ERROR type `foo::T` is private + | ^^^^ +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + +error: type `foo::T` is private + --> $DIR/fields.rs:29:17 + | +LL | let _ = t.0; //~ ERROR type `foo::T` is private + | ^ +... +LL | let s = foo::m!(S, x); + | ------------- in this macro invocation + +error: aborting due to 4 previous errors + diff --git a/src/test/compile-fail/for-loop-hygiene.rs b/src/test/ui/hygiene/for-loop.rs index d9386421970..d9386421970 100644 --- a/src/test/compile-fail/for-loop-hygiene.rs +++ b/src/test/ui/hygiene/for-loop.rs diff --git a/src/test/ui/hygiene/for-loop.stderr b/src/test/ui/hygiene/for-loop.stderr new file mode 100644 index 00000000000..7e606b2358c --- /dev/null +++ b/src/test/ui/hygiene/for-loop.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `iter` in this scope + --> $DIR/for-loop.rs:16:9 + | +LL | iter.next(); //~ ERROR cannot find value `iter` in this scope + | ^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/compile-fail/hygiene/globs.rs b/src/test/ui/hygiene/globs.rs index 7ba217061c6..7ba217061c6 100644 --- a/src/test/compile-fail/hygiene/globs.rs +++ b/src/test/ui/hygiene/globs.rs diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr new file mode 100644 index 00000000000..d77242e135d --- /dev/null +++ b/src/test/ui/hygiene/globs.stderr @@ -0,0 +1,49 @@ +error[E0425]: cannot find function `f` in this scope + --> $DIR/globs.rs:32:9 + | +LL | f(); //~ ERROR cannot find function `f` in this scope + | ^ not found in this scope +help: possible candidates are found in other modules, you can import them into scope + | +LL | use foo::f; + | +LL | use foo::f; + | +LL | use foo::f; + | + +error[E0425]: cannot find function `g` in this scope + --> $DIR/globs.rs:25:5 + | +LL | g(); //~ ERROR cannot find function `g` in this scope + | ^ not found in this scope +... +LL | / m! { +LL | | use bar::*; +LL | | g(); +LL | | f(); //~ ERROR cannot find function `f` in this scope +LL | | } + | |_____- in this macro invocation +help: possible candidates are found in other modules, you can import them into scope + | +LL | use bar::g; + | +LL | use foo::test2::test::g; + | +LL | use foo::test::g; + | +LL | use foo::test::g; + | + +error[E0425]: cannot find function `f` in this scope + --> $DIR/globs.rs:64:17 + | +LL | n!(f); + | ------ in this macro invocation +... +LL | f //~ ERROR cannot find function `f` in this scope + | ^ not found in this scope + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/compile-fail/hygiene/impl_items.rs b/src/test/ui/hygiene/impl_items.rs index cdba559445d..cdba559445d 100644 --- a/src/test/compile-fail/hygiene/impl_items.rs +++ b/src/test/ui/hygiene/impl_items.rs diff --git a/src/test/ui/hygiene/impl_items.stderr b/src/test/ui/hygiene/impl_items.stderr new file mode 100644 index 00000000000..dbcf53554cf --- /dev/null +++ b/src/test/ui/hygiene/impl_items.stderr @@ -0,0 +1,11 @@ +error: type `for<'r> fn(&'r foo::S) {foo::S::f}` is private + --> $DIR/impl_items.rs:22:23 + | +LL | let _: () = S.f(); //~ ERROR type `for<'r> fn(&'r foo::S) {foo::S::f}` is private + | ^ +... +LL | foo::m!(); + | ---------- in this macro invocation + +error: aborting due to previous error + diff --git a/src/test/compile-fail/hygiene/intercrate.rs b/src/test/ui/hygiene/intercrate.rs index 50fc985ba34..50fc985ba34 100644 --- a/src/test/compile-fail/hygiene/intercrate.rs +++ b/src/test/ui/hygiene/intercrate.rs diff --git a/src/test/ui/hygiene/intercrate.stderr b/src/test/ui/hygiene/intercrate.stderr new file mode 100644 index 00000000000..ecbc6e7b147 --- /dev/null +++ b/src/test/ui/hygiene/intercrate.stderr @@ -0,0 +1,10 @@ +error: type `fn() -> u32 {intercrate::foo::bar::f}` is private + --> $DIR/intercrate.rs:22:16 + | +LL | assert_eq!(intercrate::foo::m!(), 1); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/compile-fail/hygiene/nested_macro_privacy.rs b/src/test/ui/hygiene/nested_macro_privacy.rs index 6612359649c..6612359649c 100644 --- a/src/test/compile-fail/hygiene/nested_macro_privacy.rs +++ b/src/test/ui/hygiene/nested_macro_privacy.rs diff --git a/src/test/ui/hygiene/nested_macro_privacy.stderr b/src/test/ui/hygiene/nested_macro_privacy.stderr new file mode 100644 index 00000000000..1179065b94c --- /dev/null +++ b/src/test/ui/hygiene/nested_macro_privacy.stderr @@ -0,0 +1,9 @@ +error[E0616]: field `i` of struct `foo::S` is private + --> $DIR/nested_macro_privacy.rs:25:5 + | +LL | S::default().i; //~ ERROR field `i` of struct `foo::S` is private + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0616`. diff --git a/src/test/compile-fail/hygiene/no_implicit_prelude.rs b/src/test/ui/hygiene/no_implicit_prelude.rs index c90c7b3093c..c90c7b3093c 100644 --- a/src/test/compile-fail/hygiene/no_implicit_prelude.rs +++ b/src/test/ui/hygiene/no_implicit_prelude.rs diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr new file mode 100644 index 00000000000..5753d1a32f7 --- /dev/null +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -0,0 +1,30 @@ +error[E0433]: failed to resolve. Use of undeclared type or module `Vec` + --> $DIR/no_implicit_prelude.rs:21:9 + | +LL | fn f() { ::bar::m!(); } + | ------------ in this macro invocation +... +LL | Vec::new(); //~ ERROR failed to resolve + | ^^^ Use of undeclared type or module `Vec` + +error[E0601]: `main` function not found in crate `no_implicit_prelude` + | + = note: consider adding a `main` function to `$DIR/no_implicit_prelude.rs` + +error[E0599]: no method named `clone` found for type `()` in the current scope + --> $DIR/no_implicit_prelude.rs:22:12 + | +LL | fn f() { ::bar::m!(); } + | ------------ in this macro invocation +... +LL | ().clone() //~ ERROR no method named `clone` found + | ^^^^^ + | + = help: items from traits can only be used if the trait is in scope + = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + candidate #1: `use std::clone::Clone;` + +error: aborting due to 3 previous errors + +Some errors occurred: E0433, E0599, E0601. +For more information about an error, try `rustc --explain E0433`. diff --git a/src/test/compile-fail/pattern-macro-hygiene.rs b/src/test/ui/hygiene/pattern-macro.rs index 26d411c9154..26d411c9154 100644 --- a/src/test/compile-fail/pattern-macro-hygiene.rs +++ b/src/test/ui/hygiene/pattern-macro.rs diff --git a/src/test/ui/hygiene/pattern-macro.stderr b/src/test/ui/hygiene/pattern-macro.stderr new file mode 100644 index 00000000000..b26084db02e --- /dev/null +++ b/src/test/ui/hygiene/pattern-macro.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/pattern-macro.rs:15:5 + | +LL | x + 1; //~ ERROR cannot find value `x` in this scope + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/compile-fail/hygiene/privacy.rs b/src/test/ui/hygiene/privacy.rs index 987cad187d4..987cad187d4 100644 --- a/src/test/compile-fail/hygiene/privacy.rs +++ b/src/test/ui/hygiene/privacy.rs diff --git a/src/test/ui/hygiene/privacy.stderr b/src/test/ui/hygiene/privacy.stderr new file mode 100644 index 00000000000..808d244e9cd --- /dev/null +++ b/src/test/ui/hygiene/privacy.stderr @@ -0,0 +1,9 @@ +error[E0603]: function `f` is private + --> $DIR/privacy.rs:26:9 + | +LL | foo::f() //~ ERROR `f` is private + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/compile-fail/hygiene/trait_items.rs b/src/test/ui/hygiene/trait_items.rs index 3bd19cbc0ac..3bd19cbc0ac 100644 --- a/src/test/compile-fail/hygiene/trait_items.rs +++ b/src/test/ui/hygiene/trait_items.rs diff --git a/src/test/ui/hygiene/trait_items.stderr b/src/test/ui/hygiene/trait_items.stderr new file mode 100644 index 00000000000..56d9c585d6f --- /dev/null +++ b/src/test/ui/hygiene/trait_items.stderr @@ -0,0 +1,16 @@ +error[E0599]: no method named `f` found for type `()` in the current scope + --> $DIR/trait_items.rs:27:24 + | +LL | fn f() { ::baz::m!(); } + | ------------ in this macro invocation +... +LL | pub macro m() { ().f() } //~ ERROR no method named `f` found for type `()` in the current scope + | ^ + | + = help: items from traits can only be used if the trait is in scope + = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + candidate #1: `use foo::T;` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr b/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr new file mode 100644 index 00000000000..34ee39c7164 --- /dev/null +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr @@ -0,0 +1,14 @@ +warning: not reporting region error due to -Znll + --> $DIR/dyn-trait.rs:33:16 + | +LL | static_val(x); //~ ERROR cannot infer + | ^ + +error: free region `'a` does not outlive free region `'static` + --> $DIR/dyn-trait.rs:33:5 + | +LL | static_val(x); //~ ERROR cannot infer + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/in-band-lifetimes/mismatched.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched.nll.stderr new file mode 100644 index 00000000000..0930583a7ee --- /dev/null +++ b/src/test/ui/in-band-lifetimes/mismatched.nll.stderr @@ -0,0 +1,32 @@ +warning: not reporting region error due to -Znll + --> $DIR/mismatched.rs:14:42 + | +LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } //~ ERROR explicit lifetime required + | ^ + +warning: not reporting region error due to -Znll + --> $DIR/mismatched.rs:16:46 + | +LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } //~ ERROR lifetime mismatch + | ^ + +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/mismatched.rs:14:42 + | +LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } //~ ERROR explicit lifetime required + | - ^ lifetime `'a` required + | | + | consider changing the type of `y` to `&'a u32` + +error[E0623]: lifetime mismatch + --> $DIR/mismatched.rs:16:46 + | +LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } //~ ERROR lifetime mismatch + | ------- ------- ^ ...but data from `y` is returned here + | | + | this parameter and the return type are declared with different lifetimes... + +error: aborting due to 2 previous errors + +Some errors occurred: E0621, E0623. +For more information about an error, try `rustc --explain E0621`. diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait.nll.stderr new file mode 100644 index 00000000000..5e42cab9974 --- /dev/null +++ b/src/test/ui/in-band-lifetimes/mismatched_trait.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/mismatched_trait.rs:16:9 + | +LL | y //~ ERROR explicit lifetime required + | ^ + +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/mismatched_trait.rs:16:9 + | +LL | fn baz(&self, x: &'a u32, y: &u32) -> &'a u32 { + | - consider changing the type of `y` to `&'a u32` +LL | y //~ ERROR explicit lifetime required + | ^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/in-band-lifetimes/mut_while_borrow.nll.stderr b/src/test/ui/in-band-lifetimes/mut_while_borrow.nll.stderr new file mode 100644 index 00000000000..546d7b0ed5c --- /dev/null +++ b/src/test/ui/in-band-lifetimes/mut_while_borrow.nll.stderr @@ -0,0 +1,13 @@ +error[E0506]: cannot assign to `p` because it is borrowed + --> $DIR/mut_while_borrow.rs:19:5 + | +LL | let r = foo(&p); + | -- borrow of `p` occurs here +LL | p += 1; //~ ERROR cannot assign to `p` because it is borrowed + | ^^^^^^ assignment to borrowed `p` occurs here +LL | println!("{}", r); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/src/test/ui/issue-13058.nll.stderr b/src/test/ui/issue-13058.nll.stderr new file mode 100644 index 00000000000..604ad38ad23 --- /dev/null +++ b/src/test/ui/issue-13058.nll.stderr @@ -0,0 +1,27 @@ +warning: not reporting region error due to -Znll + --> $DIR/issue-13058.rs:24:21 + | +LL | let cont_iter = cont.iter(); + | ^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/issue-13058.rs:24:26 + | +LL | let cont_iter = cont.iter(); + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-13058.rs:36:11 + | +LL | check((3, 5)); + | ^^^^^^ + | | + | expected reference, found tuple + | help: consider borrowing here: `&(3, 5)` + | + = note: expected type `&_` + found type `({integer}, {integer})` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issue-17263.nll.stderr b/src/test/ui/issue-17263.nll.stderr new file mode 100644 index 00000000000..d6009e8078d --- /dev/null +++ b/src/test/ui/issue-17263.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/issue-17263.rs:15:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut x: Box<_> = box Foo { a: 1, b: 2 }; +LL | | let (a, b) = (&mut x.a, &mut x.b); +LL | | //~^ ERROR cannot borrow `x` (via `x.b`) as mutable more than once at a time +... | +LL | | //~^ ERROR cannot borrow `foo` (via `foo.b`) as immutable +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/issue-17263.rs b/src/test/ui/issue-17263.rs index 242327e93ce..b251f9a4152 100644 --- a/src/test/ui/issue-17263.rs +++ b/src/test/ui/issue-17263.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(box_syntax)] +#![feature(box_syntax, rustc_attrs)] struct Foo { a: isize, b: isize } -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut x: Box<_> = box Foo { a: 1, b: 2 }; let (a, b) = (&mut x.a, &mut x.b); //~^ ERROR cannot borrow `x` (via `x.b`) as mutable more than once at a time diff --git a/src/test/ui/issue-21600.nll.stderr b/src/test/ui/issue-21600.nll.stderr new file mode 100644 index 00000000000..b5b9cefb706 --- /dev/null +++ b/src/test/ui/issue-21600.nll.stderr @@ -0,0 +1,15 @@ +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/issue-21600.rs:24:20 + | +LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/issue-21600.rs:24:17 + | +LL | call_it(|| x.gen_mut()); //~ ERROR cannot borrow data mutably in a captured outer + | ^^^^^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issue-25793.nll.stderr b/src/test/ui/issue-25793.nll.stderr new file mode 100644 index 00000000000..05ba186c6bb --- /dev/null +++ b/src/test/ui/issue-25793.nll.stderr @@ -0,0 +1,8 @@ +error: compilation successful + --> $DIR/issue-25793.rs:32:1 + | +LL | fn main() { #![rustc_error] } // rust-lang/rust#49855 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issue-25793.rs b/src/test/ui/issue-25793.rs index 4f3d29216e4..8624527145c 100644 --- a/src/test/ui/issue-25793.rs +++ b/src/test/ui/issue-25793.rs @@ -7,7 +7,7 @@ // <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. - +#![feature(rustc_attrs)] macro_rules! width( ($this:expr) => { $this.width.unwrap() @@ -29,4 +29,4 @@ impl HasInfo { } } -fn main() {} +fn main() { #![rustc_error] } // rust-lang/rust#49855 diff --git a/src/test/ui/issue-36400.nll.stderr b/src/test/ui/issue-36400.nll.stderr new file mode 100644 index 00000000000..040e6300af6 --- /dev/null +++ b/src/test/ui/issue-36400.nll.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/issue-36400.rs:15:7 + | +LL | f(&mut *x); //~ ERROR cannot borrow immutable + | ^^^^^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `x` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/issue-40402-ref-hints/issue-40402-1.nll.stderr b/src/test/ui/issue-40402-ref-hints/issue-40402-1.nll.stderr new file mode 100644 index 00000000000..48e27014792 --- /dev/null +++ b/src/test/ui/issue-40402-ref-hints/issue-40402-1.nll.stderr @@ -0,0 +1,9 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/issue-40402-1.rs:19:13 + | +LL | let e = f.v[0]; //~ ERROR cannot move out of indexed content + | ^^^^^^ cannot move out of borrowed content + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/issue-40402-ref-hints/issue-40402-2.nll.stderr b/src/test/ui/issue-40402-ref-hints/issue-40402-2.nll.stderr new file mode 100644 index 00000000000..0b907c5acf1 --- /dev/null +++ b/src/test/ui/issue-40402-ref-hints/issue-40402-2.nll.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/issue-40402-2.rs:15:10 + | +LL | let (a, b) = x[0]; //~ ERROR cannot move out of indexed content + | ^ cannot move out of borrowed content + +error[E0507]: cannot move out of borrowed content + --> $DIR/issue-40402-2.rs:15:13 + | +LL | let (a, b) = x[0]; //~ ERROR cannot move out of indexed content + | ^ cannot move out of borrowed content + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/issue-42106.nll.stderr b/src/test/ui/issue-42106.nll.stderr new file mode 100644 index 00000000000..cae04aaedfd --- /dev/null +++ b/src/test/ui/issue-42106.nll.stderr @@ -0,0 +1,8 @@ +error: compilation successful + --> $DIR/issue-42106.rs:16:1 + | +LL | fn main() { #![rustc_error] } // rust-lang/rust#49855 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issue-42106.rs b/src/test/ui/issue-42106.rs index f35eee186a2..96f410578ce 100644 --- a/src/test/ui/issue-42106.rs +++ b/src/test/ui/issue-42106.rs @@ -7,10 +7,10 @@ // <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. - +#![feature(rustc_attrs)] fn do_something<T>(collection: &mut Vec<T>) { let _a = &collection; collection.swap(1, 2); //~ ERROR also borrowed as immutable } -fn main() {} +fn main() { #![rustc_error] } // rust-lang/rust#49855 diff --git a/src/test/ui/issue-4335.nll.stderr b/src/test/ui/issue-4335.nll.stderr new file mode 100644 index 00000000000..7f4273bc8c7 --- /dev/null +++ b/src/test/ui/issue-4335.nll.stderr @@ -0,0 +1,25 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/issue-4335.rs:16:20 + | +LL | id(Box::new(|| *v)) + | ^^ cannot move out of borrowed content + +error[E0597]: `v` does not live long enough + --> $DIR/issue-4335.rs:16:17 + | +LL | id(Box::new(|| *v)) + | ^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'r as defined on the function body at 15:1... + --> $DIR/issue-4335.rs:15:1 + | +LL | fn f<'r, T>(v: &'r T) -> Box<FnMut() -> T + 'r> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors occurred: E0507, E0597. +For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/issue-45697-1.nll.stderr b/src/test/ui/issue-45697-1.nll.stderr new file mode 100644 index 00000000000..cf108691a0e --- /dev/null +++ b/src/test/ui/issue-45697-1.nll.stderr @@ -0,0 +1,34 @@ +error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast) + --> $DIR/issue-45697-1.rs:30:9 + | +LL | let z = copy_borrowed_ptr(&mut y); + | - borrow of `*y.pointer` occurs here +LL | *y.pointer += 1; + | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here + +error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir) + --> $DIR/issue-45697-1.rs:30:9 + | +LL | let z = copy_borrowed_ptr(&mut y); + | ------ borrow of `y` occurs here +LL | *y.pointer += 1; + | ^^^^^^^^^^^^^^^ use of borrowed `y` +... +LL | *z.pointer += 1; + | --------------- borrow later used here + +error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir) + --> $DIR/issue-45697-1.rs:30:9 + | +LL | let z = copy_borrowed_ptr(&mut y); + | ------ borrow of `*y.pointer` occurs here +LL | *y.pointer += 1; + | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here +... +LL | *z.pointer += 1; + | --------------- borrow later used here + +error: aborting due to 3 previous errors + +Some errors occurred: E0503, E0506. +For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/issue-45697.nll.stderr b/src/test/ui/issue-45697.nll.stderr new file mode 100644 index 00000000000..a85972fcd7a --- /dev/null +++ b/src/test/ui/issue-45697.nll.stderr @@ -0,0 +1,34 @@ +error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast) + --> $DIR/issue-45697.rs:30:9 + | +LL | let z = copy_borrowed_ptr(&mut y); + | - borrow of `*y.pointer` occurs here +LL | *y.pointer += 1; + | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here + +error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir) + --> $DIR/issue-45697.rs:30:9 + | +LL | let z = copy_borrowed_ptr(&mut y); + | ------ borrow of `y` occurs here +LL | *y.pointer += 1; + | ^^^^^^^^^^^^^^^ use of borrowed `y` +... +LL | *z.pointer += 1; + | --------------- borrow later used here + +error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir) + --> $DIR/issue-45697.rs:30:9 + | +LL | let z = copy_borrowed_ptr(&mut y); + | ------ borrow of `*y.pointer` occurs here +LL | *y.pointer += 1; + | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here +... +LL | *z.pointer += 1; + | --------------- borrow later used here + +error: aborting due to 3 previous errors + +Some errors occurred: E0503, E0506. +For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/issue-46471-1.nll.stderr b/src/test/ui/issue-46471-1.nll.stderr new file mode 100644 index 00000000000..0108056bc72 --- /dev/null +++ b/src/test/ui/issue-46471-1.nll.stderr @@ -0,0 +1,28 @@ +error[E0597]: `z` does not live long enough (Ast) + --> $DIR/issue-46471-1.rs:16:14 + | +LL | &mut z + | ^ borrowed value does not live long enough +LL | }; + | - `z` dropped here while still borrowed +... +LL | } + | - borrowed value needs to live until here + +error[E0597]: `z` does not live long enough (Mir) + --> $DIR/issue-46471-1.rs:16:9 + | +LL | let y = { + | _____________- +LL | | let mut z = 0; +LL | | &mut z + | | ^^^^^^ borrowed value does not live long enough +LL | | }; + | | - + | | | + | |_____borrowed value only lives until here + | borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs b/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs index e339716289c..c59a9bc4170 100644 --- a/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs +++ b/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.rs @@ -16,7 +16,7 @@ struct Verdict(Guilty, Option<FineDollars>); fn main() { let justice = Verdict(true, Some(2718)); let _condemned = justice.00; - //~^ ERROR invalid tuple or struct index + //~^ ERROR no field `00` on type `Verdict` let _punishment = justice.001; - //~^ ERROR invalid tuple or struct index + //~^ ERROR no field `001` on type `Verdict` } diff --git a/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.stderr b/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.stderr index 9603ac01fef..4a1c9b554a9 100644 --- a/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.stderr +++ b/src/test/ui/issue-47073-zero-padded-tuple-struct-indices.stderr @@ -1,14 +1,17 @@ -error: invalid tuple or struct index +error[E0609]: no field `00` on type `Verdict` --> $DIR/issue-47073-zero-padded-tuple-struct-indices.rs:18:30 | LL | let _condemned = justice.00; - | ^^ help: try simplifying the index: `0` + | ^^ did you mean `0`? -error: invalid tuple or struct index +error[E0609]: no field `001` on type `Verdict` --> $DIR/issue-47073-zero-padded-tuple-struct-indices.rs:20:31 | LL | let _punishment = justice.001; - | ^^^ help: try simplifying the index: `1` + | ^^^ unknown field + | + = note: available fields are: `0`, `1` error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/lifetime-errors/42701_one_named_and_one_anonymous.nll.stderr b/src/test/ui/lifetime-errors/42701_one_named_and_one_anonymous.nll.stderr new file mode 100644 index 00000000000..62ccea36bd3 --- /dev/null +++ b/src/test/ui/lifetime-errors/42701_one_named_and_one_anonymous.nll.stderr @@ -0,0 +1,22 @@ +warning: not reporting region error due to -Znll + --> $DIR/42701_one_named_and_one_anonymous.rs:20:9 + | +LL | &*x //~ ERROR explicit lifetime + | ^^^ + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/42701_one_named_and_one_anonymous.rs:16:5 + | +LL | fn foo2<'a>(a: &'a Foo, x: &i32) -> &'a i32 { + | - consider changing the type of `x` to `&'a i32` +LL | / if true { +LL | | let p: &i32 = &a.field; +LL | | &*p +LL | | } else { +LL | | &*x //~ ERROR explicit lifetime +LL | | } + | |_____^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.nll.stderr new file mode 100644 index 00000000000..78546594ef0 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.nll.stderr @@ -0,0 +1,23 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:21:21 + | +LL | other //~ ERROR explicit lifetime + | ^^^^^ + +error[E0621]: explicit lifetime required in the type of `other` + --> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:18:9 + | +LL | fn bar(&self, other: Foo) -> Foo<'a> { + | ----- consider changing the type of `other` to `Foo<'a>` +LL | / match *self { +LL | | Foo::Bar(s) => { +LL | | if s == "test" { +LL | | other //~ ERROR explicit lifetime +... | +LL | | } +LL | | } + | |_________^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.nll.stderr new file mode 100644 index 00000000000..11bb1df3c78 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex1-return-one-existing-name-if-else-2.rs:12:16 + | +LL | if x > y { x } else { y } //~ ERROR explicit lifetime + | ^ + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/ex1-return-one-existing-name-if-else-2.rs:12:8 + | +LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { + | - consider changing the type of `x` to `&'a i32` +LL | if x > y { x } else { y } //~ ERROR explicit lifetime + | ^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.nll.stderr new file mode 100644 index 00000000000..a619e6ca964 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.nll.stderr @@ -0,0 +1,18 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex1-return-one-existing-name-if-else-3.rs:12:27 + | +LL | if x > y { x } else { y } //~ ERROR explicit lifetime + | ^ + +error[E0621]: explicit lifetime required in parameter type + --> $DIR/ex1-return-one-existing-name-if-else-3.rs:11:13 + | +LL | fn foo<'a>((x, y): (&'a i32, &i32)) -> &'a i32 { + | -^---- + | || + | |lifetime `'a` required + | consider changing type to `(&'a i32, &'a i32)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.nll.stderr new file mode 100644 index 00000000000..92245173ce8 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:14:15 + | +LL | if x > y { x } else { y } //~ ERROR explicit lifetime + | ^ + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:14:7 + | +LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { + | - consider changing the type of `x` to `&'a i32` +LL | if x > y { x } else { y } //~ ERROR explicit lifetime + | ^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.nll.stderr new file mode 100644 index 00000000000..32ef068b8b9 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.nll.stderr @@ -0,0 +1,18 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:18:36 + | +LL | if true { &self.field } else { x } //~ ERROR explicit lifetime + | ^ + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:18:5 + | +LL | fn foo<'a>(&'a self, x: &i32) -> &i32 { + | - consider changing the type of `x` to `&'a i32` +LL | +LL | if true { &self.field } else { x } //~ ERROR explicit lifetime + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr new file mode 100644 index 00000000000..fd10b0d338c --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr @@ -0,0 +1,20 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:21:20 + | +LL | if x > y { x } else { y } //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:21:12 + | +LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { + | ---- ------- + | | + | this parameter and the return type are declared with different lifetimes... +LL | +LL | if x > y { x } else { y } //~ ERROR lifetime mismatch + | ^^^^^ ...but data from `x` is returned here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.nll.stderr new file mode 100644 index 00000000000..f17b24a0aca --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex1-return-one-existing-name-if-else.rs:12:27 + | +LL | if x > y { x } else { y } //~ ERROR explicit lifetime + | ^ + +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/ex1-return-one-existing-name-if-else.rs:12:8 + | +LL | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { + | - consider changing the type of `y` to `&'a i32` +LL | if x > y { x } else { y } //~ ERROR explicit lifetime + | ^^^^^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr new file mode 100644 index 00000000000..b1663fe5eb6 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr @@ -0,0 +1,20 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5 + | +LL | x //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5 + | +LL | fn foo<'a>(&self, x: &'a i32) -> &i32 { + | ------- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | +LL | x //~ ERROR lifetime mismatch + | ^ ...but data from `x` is returned here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr new file mode 100644 index 00000000000..19b8bd2f780 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr @@ -0,0 +1,20 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex1-return-one-existing-name-self-is-anon.rs:18:30 + | +LL | if true { x } else { self } //~ ERROR lifetime mismatch + | ^^^^ + +error[E0623]: lifetime mismatch + --> $DIR/ex1-return-one-existing-name-self-is-anon.rs:18:9 + | +LL | fn foo<'a>(&self, x: &'a Foo) -> &'a Foo { + | ----- ------- + | | + | this parameter and the return type are declared with different lifetimes... +LL | +LL | if true { x } else { self } //~ ERROR lifetime mismatch + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...but data from `self` is returned here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr new file mode 100644 index 00000000000..0b34e464b4b --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex2a-push-one-existing-name-2.rs:16:12 + | +LL | y.push(x); //~ ERROR explicit lifetime + | ^ + +error[E0621]: explicit lifetime required in the type of `x` + --> $DIR/ex2a-push-one-existing-name-2.rs:16:5 + | +LL | fn foo<'a>(x: Ref<i32>, y: &mut Vec<Ref<'a, i32>>) { + | - consider changing the type of `x` to `Ref<'a, i32>` +LL | y.push(x); //~ ERROR explicit lifetime + | ^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr new file mode 100644 index 00000000000..212b39966aa --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex2a-push-one-existing-name-early-bound.rs:17:12 + | +LL | x.push(y); //~ ERROR explicit lifetime required + | ^ + +error[E0282]: type annotations needed + --> $DIR/ex2a-push-one-existing-name-early-bound.rs:20:9 + | +LL | let x = baz; + | - ^^^ cannot infer type for `T` + | | + | consider giving `x` a type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.nll.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.nll.stderr new file mode 100644 index 00000000000..ad39028154a --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex2a-push-one-existing-name.rs:16:12 + | +LL | x.push(y); //~ ERROR explicit lifetime + | ^ + +error[E0621]: explicit lifetime required in the type of `y` + --> $DIR/ex2a-push-one-existing-name.rs:16:5 + | +LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) { + | - consider changing the type of `y` to `Ref<'a, i32>` +LL | x.push(y); //~ ERROR explicit lifetime + | ^ lifetime `'a` required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.nll.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.nll.stderr new file mode 100644 index 00000000000..34daea7c9f4 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex2b-push-no-existing-names.rs:16:12 + | +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex2b-push-no-existing-names.rs:16:5 + | +LL | fn foo(x: &mut Vec<Ref<i32>>, y: Ref<i32>) { + | -------- -------- these two types are declared with different lifetimes... +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.nll.stderr b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.nll.stderr new file mode 100644 index 00000000000..96baa5c8ad2 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex2c-push-inference-variable.rs:16:13 + | +LL | let z = Ref { data: y.data }; + | ^^^ + +error[E0623]: lifetime mismatch + --> $DIR/ex2c-push-inference-variable.rs:16:9 + | +LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) { + | ------------ ------------ these two types are declared with different lifetimes... +LL | let z = Ref { data: y.data }; + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr new file mode 100644 index 00000000000..e5d47689b49 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex2d-push-inference-variable-2.rs:17:13 + | +LL | let b = Ref { data: y.data }; + | ^^^ + +error[E0623]: lifetime mismatch + --> $DIR/ex2d-push-inference-variable-2.rs:16:9 + | +LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) { + | ------------ ------------ these two types are declared with different lifetimes... +LL | let a: &mut Vec<Ref<i32>> = x; //~ ERROR lifetime mismatch + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr new file mode 100644 index 00000000000..668752f8e02 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex2e-push-inference-variable-3.rs:17:13 + | +LL | let b = Ref { data: y.data }; + | ^^^ + +error[E0623]: lifetime mismatch + --> $DIR/ex2e-push-inference-variable-3.rs:16:9 + | +LL | fn foo<'a, 'b, 'c>(x: &'a mut Vec<Ref<'b, i32>>, y: Ref<'c, i32>) { + | ------------ ------------ these two types are declared with different lifetimes... +LL | let a: &mut Vec<Ref<i32>> = x; //~ ERROR lifetime mismatch + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.nll.stderr new file mode 100644 index 00000000000..45234249711 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-2.rs:12:9 + | +LL | v = x; //~ ERROR lifetime mismatch + | ^ + +error[E0384]: cannot assign twice to immutable variable `v` + --> $DIR/ex3-both-anon-regions-2.rs:12:5 + | +LL | fn foo((v, w): (&u8, &u8), x: &u8) { + | - first assignment to `v` +LL | v = x; //~ ERROR lifetime mismatch + | ^^^^^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.nll.stderr new file mode 100644 index 00000000000..581088a9258 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.nll.stderr @@ -0,0 +1,31 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-3.rs:12:13 + | +LL | z.push((x,y)); //~ ERROR lifetime mismatch + | ^ + +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-3.rs:12:15 + | +LL | z.push((x,y)); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-3.rs:11:33 + | +LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + | --- ^ --- these two types are declared with different lifetimes... + | | + | ...but data flows into `z` here + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-3.rs:11:33 + | +LL | fn foo(z: &mut Vec<(&u8,&u8)>, (x, y): (&u8, &u8)) { + | --- ^ --- these two types are declared with different lifetimes... + | | + | ...but data flows into `z` here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr new file mode 100644 index 00000000000..b15f5f4a0fc --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:16:11 + | +LL | x.b = y.b; //~ ERROR lifetime mismatch + | ^^^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:16:5 + | +LL | fn foo(mut x: Ref, y: Ref) { + | --- --- these two types are declared with different lifetimes... +LL | x.b = y.b; //~ ERROR lifetime mismatch + | ^^^^^^^^^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr new file mode 100644 index 00000000000..0ec73c2e778 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr @@ -0,0 +1,19 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:16:11 + | +LL | x.a = x.b; //~ ERROR lifetime mismatch + | ^^^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:16:5 + | +LL | fn foo(mut x: Ref) { + | --- + | | + | this type is declared with multiple lifetimes... +LL | x.a = x.b; //~ ERROR lifetime mismatch + | ^^^^^^^^^ ...but data with one lifetime flows into the other here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.nll.stderr new file mode 100644 index 00000000000..727a701d3f2 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.nll.stderr @@ -0,0 +1,19 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:11 + | +LL | x.a = x.b; //~ ERROR lifetime mismatch + | ^^^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:5 + | +LL | fn foo(mut x: Ref) { + | --- + | | + | this type is declared with multiple lifetimes... +LL | x.a = x.b; //~ ERROR lifetime mismatch + | ^^^^^^^^^ ...but data with one lifetime flows into the other here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr new file mode 100644 index 00000000000..f010c87377e --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr @@ -0,0 +1,18 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-both-are-structs-earlybound-regions.rs:18:12 + | +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs-earlybound-regions.rs:18:5 + | +LL | fn foo<'a, 'b>(mut x: Vec<Ref<'a>>, y: Ref<'b>) + | ------- ------- these two types are declared with different lifetimes... +... +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr new file mode 100644 index 00000000000..2b48b176ae8 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-both-are-structs-latebound-regions.rs:15:12 + | +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs-latebound-regions.rs:15:5 + | +LL | fn foo<'a, 'b>(mut x: Vec<Ref<'a>>, y: Ref<'b>) { + | ------- ------- these two types are declared with different lifetimes... +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr new file mode 100644 index 00000000000..c9ac04cb01e --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-both-are-structs.rs:15:12 + | +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-both-are-structs.rs:15:5 + | +LL | fn foo(mut x: Vec<Ref>, y: Ref) { + | --- --- these two types are declared with different lifetimes... +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr new file mode 100644 index 00000000000..9c7fc8ac458 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-latebound-regions.rs:12:12 + | +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-latebound-regions.rs:12:5 + | +LL | fn foo<'a,'b>(x: &mut Vec<&'a u8>, y: &'b u8) { + | ------ ------ these two types are declared with different lifetimes... +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr new file mode 100644 index 00000000000..85a0b7c1345 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr @@ -0,0 +1,28 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:9 + | +LL | y = x.b; //~ ERROR lifetime mismatch + | ^^^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:5 + | +LL | fn foo(mut x: Ref, y: &u32) { + | --- ---- + | | + | these two types are declared with different lifetimes... +LL | y = x.b; //~ ERROR lifetime mismatch + | ^^^^^^^ ...but data from `x` flows into `y` here + +error[E0384]: cannot assign to immutable argument `y` + --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:5 + | +LL | fn foo(mut x: Ref, y: &u32) { + | - argument not declared as `mut` +LL | y = x.b; //~ ERROR lifetime mismatch + | ^^^^^^^ cannot assign to immutable argument + +error: aborting due to 2 previous errors + +Some errors occurred: E0384, E0623. +For more information about an error, try `rustc --explain E0384`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr new file mode 100644 index 00000000000..4e160001b87 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:14:11 + | +LL | y.b = x; //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:14:5 + | +LL | fn foo(mut y: Ref, x: &u32) { + | --- ---- these two types are declared with different lifetimes... +LL | y.b = x; //~ ERROR lifetime mismatch + | ^^^^^^^ ...but data from `x` flows into `y` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr new file mode 100644 index 00000000000..7bbc3c4084f --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:14:11 + | +LL | y.b = x; //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:14:5 + | +LL | fn foo(mut y: Ref, x: &u32) { + | --- ---- these two types are declared with different lifetimes... +LL | y.b = x; //~ ERROR lifetime mismatch + | ^^^^^^^ ...but data from `x` flows into `y` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr new file mode 100644 index 00000000000..9fd7bbac247 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-one-is-struct.rs:17:11 + | +LL | x.b = y; //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-one-is-struct.rs:17:5 + | +LL | fn foo(mut x: Ref, y: &u32) { + | --- ---- these two types are declared with different lifetimes... +LL | x.b = y; //~ ERROR lifetime mismatch + | ^^^^^^^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr new file mode 100644 index 00000000000..528a846991c --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr @@ -0,0 +1,19 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:17:5 + | +LL | x //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:17:5 + | +LL | fn foo<'a>(&self, x: &i32) -> &i32 { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | x //~ ERROR lifetime mismatch + | ^ ...but data from `x` is returned here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr new file mode 100644 index 00000000000..f8c0b5940c9 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr @@ -0,0 +1,19 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-self-is-anon.rs:17:19 + | +LL | if true { x } else { self } //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-self-is-anon.rs:17:9 + | +LL | fn foo<'a>(&self, x: &Foo) -> &Foo { + | ---- ---- + | | + | this parameter and the return type are declared with different lifetimes... +LL | if true { x } else { self } //~ ERROR lifetime mismatch + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...but data from `x` is returned here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr new file mode 100644 index 00000000000..284f760435c --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr @@ -0,0 +1,24 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:10 + | +LL | y.push(z); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:3 + | +LL | fn foo(x:fn(&u8, &u8), y: Vec<&u8>, z: &u8) { + | --- --- these two types are declared with different lifetimes... +LL | y.push(z); //~ ERROR lifetime mismatch + | ^ ...but data from `z` flows into `y` here + +error[E0596]: cannot borrow immutable item `y` as mutable + --> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:3 + | +LL | y.push(z); //~ ERROR lifetime mismatch + | ^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +Some errors occurred: E0596, E0623. +For more information about an error, try `rustc --explain E0596`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr new file mode 100644 index 00000000000..389549a8464 --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-using-impl-items.rs:15:16 + | +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-using-impl-items.rs:15:9 + | +LL | fn foo(x: &mut Vec<&u8>, y: &u8) { + | --- --- these two types are declared with different lifetimes... +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr new file mode 100644 index 00000000000..185ea89275f --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr @@ -0,0 +1,24 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:10 + | +LL | y.push(z); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:3 + | +LL | fn foo(x:Box<Fn(&u8, &u8)> , y: Vec<&u8>, z: &u8) { + | --- --- these two types are declared with different lifetimes... +LL | y.push(z); //~ ERROR lifetime mismatch + | ^ ...but data from `z` flows into `y` here + +error[E0596]: cannot borrow immutable item `y` as mutable + --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:3 + | +LL | y.push(z); //~ ERROR lifetime mismatch + | ^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +Some errors occurred: E0596, E0623. +For more information about an error, try `rustc --explain E0596`. diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions.nll.stderr new file mode 100644 index 00000000000..629a97ab5ca --- /dev/null +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions.nll.stderr @@ -0,0 +1,17 @@ +warning: not reporting region error due to -Znll + --> $DIR/ex3-both-anon-regions.rs:12:12 + | +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ + +error[E0623]: lifetime mismatch + --> $DIR/ex3-both-anon-regions.rs:12:5 + | +LL | fn foo(x: &mut Vec<&u8>, y: &u8) { + | --- --- these two types are declared with different lifetimes... +LL | x.push(y); //~ ERROR lifetime mismatch + | ^ ...but data from `y` flows into `x` here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr new file mode 100644 index 00000000000..d13f9ccc37d --- /dev/null +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr @@ -0,0 +1,10 @@ +error: compilation successful + --> $DIR/borrowck-let-suggestion.rs:15:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | f(); +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.rs b/src/test/ui/lifetimes/borrowck-let-suggestion.rs index 1c904648f9e..a7a7d5c5035 100644 --- a/src/test/ui/lifetimes/borrowck-let-suggestion.rs +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.rs @@ -7,11 +7,11 @@ // <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. - +#![feature(rustc_attrs)] fn f() { let x = vec![1].iter(); } -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 f(); } diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs index 58a30e86f22..bff64ad4892 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.rs +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.rs @@ -24,7 +24,7 @@ macro_rules! fake_field_stmt { macro_rules! fake_anon_field_stmt { () => { - (1).0 //~ ERROR no field + (1).0 //~ ERROR doesn't have fields } } @@ -42,7 +42,7 @@ macro_rules! fake_field_expr { macro_rules! fake_anon_field_expr { () => { - (1).0 //~ ERROR no field + (1).0 //~ ERROR doesn't have fields } } diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index eab6cd23748..cb7d422b7f3 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -16,11 +16,11 @@ LL | 1.fake //~ ERROR doesn't have fields LL | fake_field_stmt!(); | ------------------- in this macro invocation -error[E0609]: no field `0` on type `{integer}` - --> $DIR/macro-backtrace-invalid-internals.rs:27:11 +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/macro-backtrace-invalid-internals.rs:27:15 | -LL | (1).0 //~ ERROR no field - | ^^^^^ +LL | (1).0 //~ ERROR doesn't have fields + | ^ ... LL | fake_anon_field_stmt!(); | ------------------------ in this macro invocation @@ -56,11 +56,11 @@ LL | 1.fake //~ ERROR doesn't have fields LL | let _ = fake_field_expr!(); | ------------------ in this macro invocation -error[E0609]: no field `0` on type `{integer}` - --> $DIR/macro-backtrace-invalid-internals.rs:45:11 +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/macro-backtrace-invalid-internals.rs:45:15 | -LL | (1).0 //~ ERROR no field - | ^^^^^ +LL | (1).0 //~ ERROR doesn't have fields + | ^ ... LL | let _ = fake_anon_field_expr!(); | ----------------------- in this macro invocation @@ -80,5 +80,5 @@ LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous n error: aborting due to 8 previous errors -Some errors occurred: E0599, E0609, E0610, E0689. +Some errors occurred: E0599, E0610, E0689. For more information about an error, try `rustc --explain E0599`. diff --git a/src/test/ui/macros/span-covering-argument-1.nll.stderr b/src/test/ui/macros/span-covering-argument-1.nll.stderr new file mode 100644 index 00000000000..a12baab4159 --- /dev/null +++ b/src/test/ui/macros/span-covering-argument-1.nll.stderr @@ -0,0 +1,12 @@ +error[E0596]: cannot borrow immutable item `foo` as mutable + --> $DIR/span-covering-argument-1.rs:15:14 + | +LL | *&mut $s = 0; + | ^^^^^^^ cannot borrow as mutable +... +LL | bad!(foo whatever); + | ------------------- in this macro invocation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/moves-based-on-type-block-bad.nll.stderr b/src/test/ui/moves-based-on-type-block-bad.nll.stderr new file mode 100644 index 00000000000..942d9816c4e --- /dev/null +++ b/src/test/ui/moves-based-on-type-block-bad.nll.stderr @@ -0,0 +1,9 @@ +error[E0507]: cannot move out of borrowed content + --> $DIR/moves-based-on-type-block-bad.rs:37:28 + | +LL | box E::Bar(x) => println!("{}", x.to_string()), + | ^ cannot move out of borrowed content + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/moves-based-on-type-match-bindings.nll.stderr b/src/test/ui/moves-based-on-type-match-bindings.nll.stderr new file mode 100644 index 00000000000..6ebbf670acd --- /dev/null +++ b/src/test/ui/moves-based-on-type-match-bindings.nll.stderr @@ -0,0 +1,14 @@ +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-match-bindings.rs:26:11 + | +LL | Foo {f} => {} + | - value moved here +... +LL | touch(&x); //~ ERROR use of partially moved value: `x` + | ^^ value borrowed here after move + | + = note: move occurs because `x` has type `Foo<std::string::String>`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/nll/get_default.nll.stderr b/src/test/ui/nll/get_default.nll.stderr new file mode 100644 index 00000000000..c6f021f8c36 --- /dev/null +++ b/src/test/ui/nll/get_default.nll.stderr @@ -0,0 +1,51 @@ +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) + --> $DIR/get_default.rs:33:17 + | +LL | match map.get() { + | --- immutable borrow occurs here +... +LL | map.set(String::new()); // Just AST errors here + | ^^^ mutable borrow occurs here +... +LL | } + | - immutable borrow ends here + +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) + --> $DIR/get_default.rs:44:17 + | +LL | match map.get() { + | --- immutable borrow occurs here +LL | Some(v) => { +LL | map.set(String::new()); // Both AST and MIR error here + | ^^^ mutable borrow occurs here +... +LL | } + | - immutable borrow ends here + +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) + --> $DIR/get_default.rs:50:17 + | +LL | match map.get() { + | --- immutable borrow occurs here +... +LL | map.set(String::new()); // Just AST errors here + | ^^^ mutable borrow occurs here +... +LL | } + | - immutable borrow ends here + +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) + --> $DIR/get_default.rs:44:17 + | +LL | match map.get() { + | --- immutable borrow occurs here +LL | Some(v) => { +LL | map.set(String::new()); // Both AST and MIR error here + | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +... +LL | return v; + | - borrow later used here + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/issue-16223.rs b/src/test/ui/nll/issue-16223.rs new file mode 100644 index 00000000000..64fc3df30b9 --- /dev/null +++ b/src/test/ui/nll/issue-16223.rs @@ -0,0 +1,63 @@ +// 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. + +// Regression test for #16223: without NLL the `if let` construct together with +// the nested box-structure of `Root` causes an unwanted collateral move. + +// The exact error prevented here is: +// +// error[E0382]: use of collaterally moved value: `(root.boxed.rhs as SomeVariant::B).0` +// --> src/main.rs:55:29 +// | +// 56 | lhs: SomeVariant::A(a), +// | - value moved here +// 57 | rhs: SomeVariant::B(b), +// | ^ value used here after move +// | +// = note: move occurs because the value has type `A`, which does not implement the `Copy` trait + +// must-compile-successfully + +#![feature(nll)] +#![feature(box_patterns)] + +struct Root { + boxed: Box<SetOfVariants>, +} + +struct SetOfVariants { + lhs: SomeVariant, + rhs: SomeVariant, +} + +enum SomeVariant { + A(A), + B(B), +} + +struct A(String); +struct B(String); + +fn main() { + let root = Root { + boxed: Box::new(SetOfVariants { + lhs: SomeVariant::A(A(String::from("This is A"))), + rhs: SomeVariant::B(B(String::from("This is B"))), + }), + }; + if let box SetOfVariants { + lhs: SomeVariant::A(a), + rhs: SomeVariant::B(b), + } = root.boxed + { + println!("a = {}", a.0); + println!("b = {}", b.0); + } +} diff --git a/src/test/ui/nll/issue-47388.rs b/src/test/ui/nll/issue-47388.rs new file mode 100644 index 00000000000..39feea08aa4 --- /dev/null +++ b/src/test/ui/nll/issue-47388.rs @@ -0,0 +1,20 @@ +// 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. +#![feature(nll)] +struct FancyNum { + num: u8, +} + +fn main() { + let mut fancy = FancyNum{ num: 5 }; + let fancy_ref = &(&mut fancy); + fancy_ref.num = 6; //~ ERROR E0594 + println!("{}", fancy_ref.num); +} diff --git a/src/test/ui/nll/issue-47388.stderr b/src/test/ui/nll/issue-47388.stderr new file mode 100644 index 00000000000..272cb6510aa --- /dev/null +++ b/src/test/ui/nll/issue-47388.stderr @@ -0,0 +1,11 @@ +error[E0594]: cannot assign to data in a `&` reference + --> $DIR/issue-47388.rs:18:5 + | +LL | let fancy_ref = &(&mut fancy); + | ------------- help: consider changing this to be a mutable reference: `&mut` +LL | fancy_ref.num = 6; //~ ERROR E0594 + | ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/order-dependent-cast-inference.rs b/src/test/ui/order-dependent-cast-inference.rs new file mode 100644 index 00000000000..afcd402343b --- /dev/null +++ b/src/test/ui/order-dependent-cast-inference.rs @@ -0,0 +1,18 @@ +// 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. + +fn main() { + // Tests case where inference fails due to the order in which casts are checked. + // Ideally this would compile, see #48270. + let x = &"hello"; + let mut y = 0 as *const _; + //~^ ERROR cannot cast to a pointer of an unknown kind + y = x as *const _; +} diff --git a/src/test/ui/order-dependent-cast-inference.stderr b/src/test/ui/order-dependent-cast-inference.stderr new file mode 100644 index 00000000000..556acc87cff --- /dev/null +++ b/src/test/ui/order-dependent-cast-inference.stderr @@ -0,0 +1,13 @@ +error[E0641]: cannot cast to a pointer of an unknown kind + --> $DIR/order-dependent-cast-inference.rs:15:17 + | +LL | let mut y = 0 as *const _; + | ^^^^^-------- + | | + | help: consider giving more type information + | + = note: The type information given here is insufficient to check whether the pointer cast is valid + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0641`. diff --git a/src/test/ui/print_type_sizes/packed.rs b/src/test/ui/print_type_sizes/packed.rs index a4288f67899..5d8c9326258 100644 --- a/src/test/ui/print_type_sizes/packed.rs +++ b/src/test/ui/print_type_sizes/packed.rs @@ -21,10 +21,34 @@ #![allow(dead_code)] #![feature(start)] +#![feature(repr_packed)] #[derive(Default)] #[repr(packed)] -struct Packed { +struct Packed1 { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} + +#[derive(Default)] +#[repr(packed(2))] +struct Packed2 { + a: u8, + b: u8, + g: i32, + c: u8, + h: i16, + d: u8, +} + +#[derive(Default)] +#[repr(packed(2))] +#[repr(C)] +struct Packed2C { a: u8, b: u8, g: i32, @@ -45,7 +69,9 @@ struct Padded { #[start] fn start(_: isize, _: *const *const u8) -> isize { - let _c: Packed = Default::default(); - let _d: Padded = Default::default(); + let _c: Packed1 = Default::default(); + let _d: Packed2 = Default::default(); + let _e: Packed2C = Default::default(); + let _f: Padded = Default::default(); 0 } diff --git a/src/test/ui/print_type_sizes/packed.stdout b/src/test/ui/print_type_sizes/packed.stdout index 83fd333c9c7..58e1bac9eb7 100644 --- a/src/test/ui/print_type_sizes/packed.stdout +++ b/src/test/ui/print_type_sizes/packed.stdout @@ -1,3 +1,12 @@ +print-type-size type: `Packed2C`: 12 bytes, alignment: 2 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.c`: 1 bytes +print-type-size padding: 1 bytes +print-type-size field `.h`: 2 bytes +print-type-size field `.d`: 1 bytes +print-type-size end padding: 1 bytes print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes print-type-size field `.g`: 4 bytes print-type-size field `.h`: 2 bytes @@ -6,10 +15,17 @@ print-type-size field `.b`: 1 bytes print-type-size field `.c`: 1 bytes print-type-size field `.d`: 1 bytes print-type-size end padding: 2 bytes -print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes +print-type-size type: `Packed1`: 10 bytes, alignment: 1 bytes print-type-size field `.a`: 1 bytes print-type-size field `.b`: 1 bytes print-type-size field `.g`: 4 bytes print-type-size field `.c`: 1 bytes print-type-size field `.h`: 2 bytes print-type-size field `.d`: 1 bytes +print-type-size type: `Packed2`: 10 bytes, alignment: 2 bytes +print-type-size field `.g`: 4 bytes +print-type-size field `.h`: 2 bytes +print-type-size field `.a`: 1 bytes +print-type-size field `.b`: 1 bytes +print-type-size field `.c`: 1 bytes +print-type-size field `.d`: 1 bytes diff --git a/src/test/ui/region-borrow-params-issue-29793-small.nll.stderr b/src/test/ui/region-borrow-params-issue-29793-small.nll.stderr new file mode 100644 index 00000000000..1a53c033baa --- /dev/null +++ b/src/test/ui/region-borrow-params-issue-29793-small.nll.stderr @@ -0,0 +1,279 @@ +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:19:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | }; + | - borrowed value only lives until here + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:19:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | }; + | - borrowed value only lives until here + +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:34:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | }; + | - borrowed value only lives until here + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:34:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | }; + | - borrowed value only lives until here + +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:65:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | }; + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 64:5... + --> $DIR/region-borrow-params-issue-29793-small.rs:64:5 + | +LL | fn g<'a>(x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:65:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | }; + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 64:5... + --> $DIR/region-borrow-params-issue-29793-small.rs:64:5 + | +LL | fn g<'a>(x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:76:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | }; + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 75:5... + --> $DIR/region-borrow-params-issue-29793-small.rs:75:5 + | +LL | fn g<'a>(x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:76:17 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | }; + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 75:5... + --> $DIR/region-borrow-params-issue-29793-small.rs:75:5 + | +LL | fn g<'a>(x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:100:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 99:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:99:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:100:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 99:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:99:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:114:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 113:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:113:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:114:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 113:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:113:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:142:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 141:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:141:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:142:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 141:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:141:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:157:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 156:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:156:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:157:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 156:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:156:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:185:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 184:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:184:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:185:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 184:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:184:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `x` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:199:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 198:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:198:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0597]: `y` does not live long enough + --> $DIR/region-borrow-params-issue-29793-small.rs:199:21 + | +LL | let f = |t: bool| if t { x } else { y }; // (separate errors for `x` vs `y`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here + | +note: borrowed value must be valid for the lifetime 'a as defined on the method body at 198:9... + --> $DIR/region-borrow-params-issue-29793-small.rs:198:9 + | +LL | fn g<'a>(&self, x: usize, y:usize) -> Box<Fn(bool) -> usize + 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 20 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions-nested-fns-2.nll.stderr b/src/test/ui/regions-nested-fns-2.nll.stderr new file mode 100644 index 00000000000..2c973f9bdea --- /dev/null +++ b/src/test/ui/regions-nested-fns-2.nll.stderr @@ -0,0 +1,16 @@ +error[E0597]: `y` does not live long enough + --> $DIR/regions-nested-fns-2.rs:16:9 + | +LL | / |z| { +LL | | //~^ ERROR E0373 +LL | | if false { &y } else { z } +LL | | }); + | |_________^ borrowed value does not live long enough +LL | } + | - borrowed value only lives until here + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr new file mode 100644 index 00000000000..10384e3b7ca --- /dev/null +++ b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-issue-49631.rs:30:9 + | +LL | while let Some(Ok(string)) = foo.get() { + | --- immutable borrow occurs here +LL | foo.mutate(); + | ^^^^^^^^^^^^ mutable borrow occurs here +LL | //~^ ERROR cannot borrow `foo` as mutable +LL | println!("foo={:?}", *string); + | ------- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr new file mode 100644 index 00000000000..6ae5f777a93 --- /dev/null +++ b/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr @@ -0,0 +1,21 @@ +error[E0594]: cannot assign to immutable item `*x` + --> $DIR/enum.rs:19:5 + | +LL | *x += 1; //~ ERROR cannot assign to immutable + | ^^^^^^^ cannot mutate + +error[E0594]: cannot assign to immutable item `*x` + --> $DIR/enum.rs:23:9 + | +LL | *x += 1; //~ ERROR cannot assign to immutable + | ^^^^^^^ cannot mutate + +error[E0594]: cannot assign to immutable item `*x` + --> $DIR/enum.rs:29:9 + | +LL | *x += 1; //~ ERROR cannot assign to immutable + | ^^^^^^^ cannot mutate + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr new file mode 100644 index 00000000000..7138c4ac06e --- /dev/null +++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr @@ -0,0 +1,21 @@ +error[E0594]: cannot assign to immutable item `*n` + --> $DIR/explicit-mut.rs:17:13 + | +LL | *n += 1; //~ ERROR cannot assign to immutable + | ^^^^^^^ cannot mutate + +error[E0594]: cannot assign to immutable item `*n` + --> $DIR/explicit-mut.rs:25:13 + | +LL | *n += 1; //~ ERROR cannot assign to immutable + | ^^^^^^^ cannot mutate + +error[E0594]: cannot assign to immutable item `*n` + --> $DIR/explicit-mut.rs:33:13 + | +LL | *n += 1; //~ ERROR cannot assign to immutable + | ^^^^^^^ cannot mutate + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs b/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs new file mode 100644 index 00000000000..8c7275bb1a7 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs @@ -0,0 +1,38 @@ +// 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. + +// must-compile-successfully + +#![feature(infer_outlives_requirements)] + +// Type T needs to outlive lifetime 'a. +enum Foo<'a, T> { + + One(Bar<'a, T>) +} + +// Type U needs to outlive lifetime 'b +struct Bar<'b, U> { + field2: &'b U +} + + + +// Type K needs to outlive lifetime 'c. +enum Ying<'c, K> { + One(&'c Yang<K>) +} + +struct Yang<V> { + field2: V +} + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/enum.rs b/src/test/ui/rfc-2093-infer-outlives/enum.rs new file mode 100644 index 00000000000..7d0427adb9f --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/enum.rs @@ -0,0 +1,37 @@ +// 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. + +// ignore-tidy-linelength + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + +// Type T needs to outlive lifetime 'a. +enum Foo<'a, T> { + + One(Bar<'a, T>) +} + +// Type U needs to outlive lifetime 'b +struct Bar<'b, U> { + field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309] +} + + + +// Type K needs to outlive lifetime 'c. +enum Ying<'c, K> { + One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309] +} + +struct Yang<V> { + field2: V +} + +fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/enum.stderr b/src/test/ui/rfc-2093-infer-outlives/enum.stderr new file mode 100644 index 00000000000..e6eaf9b4754 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/enum.stderr @@ -0,0 +1,31 @@ +error[E0309]: the parameter type `U` may not live long enough + --> $DIR/enum.rs:23:5 + | +LL | struct Bar<'b, U> { + | - help: consider adding an explicit lifetime bound `U: 'b`... +LL | field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309] + | ^^^^^^^^^^^^^ + | +note: ...so that the reference type `&'b U` does not outlive the data it points at + --> $DIR/enum.rs:23:5 + | +LL | field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309] + | ^^^^^^^^^^^^^ + +error[E0309]: the parameter type `K` may not live long enough + --> $DIR/enum.rs:30:9 + | +LL | enum Ying<'c, K> { + | - help: consider adding an explicit lifetime bound `K: 'c`... +LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309] + | ^^^^^^^^^^^^ + | +note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at + --> $DIR/enum.rs:30:9 + | +LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309] + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs new file mode 100644 index 00000000000..da578386adb --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs @@ -0,0 +1,30 @@ +// 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. + +// ignore-test +// must-compile-successfully + +#![feature(infer_outlives_requirements)] +// Outlives requirementes are inferred (RFC 2093) + +trait MakeRef<'a>: 'a { + type Type; +} +impl<'a, T> MakeRef<'a> for Vec<T> +where T: 'a, +{ + type Type = &'a T; +} +// explicit-impl: T: 'a +struct Foo<'a, T> { + foo: <Vec<T> as MakeRef<'a>>::Type, +} + +fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs new file mode 100644 index 00000000000..fd74fe30bb6 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs @@ -0,0 +1,30 @@ +// 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. + +// ignore-test +// must-compile-successfully + +#![feature(infer_outlives_requirements)] +// Outlives requirementes are inferred (RFC 2093) + +trait MakeRef<'a> { + type Type; +} +impl<'a, T> MakeRef<'a> for Vec<T> +where T: 'a, +{ + type Type = &'a T; +} +// explicit-impl: T: 'a +struct Foo<'a, T> { + foo: <Vec<T> as MakeRef<'a>>::Type, +} + +fn main() {} diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs new file mode 100644 index 00000000000..3a10087551c --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs @@ -0,0 +1,30 @@ +// 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. + +// ignore-tidy-linelength + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + +trait MakeRef<'a> { + type Type; +} + +impl<'a, T> MakeRef<'a> for Vec<T> + where T: 'a +{ + type Type = &'a T; +} + +// Type T needs to outlive lifetime 'a, as stated in impl. +struct Foo<'a, T> { + foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309] +} + +fn main() { } diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr new file mode 100644 index 00000000000..498d66ef9a5 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr @@ -0,0 +1,17 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/explicit-impl.rs:27:5 + | +LL | struct Foo<'a, T> { + | - help: consider adding an explicit lifetime bound `T: 'a`... +LL | foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...so that the type `T` will meet its required lifetime bounds + --> $DIR/explicit-impl.rs:27:5 + | +LL | foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs new file mode 100644 index 00000000000..e51b5a16b45 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs @@ -0,0 +1,27 @@ +// 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. + +// must-compile-successfully + +#![feature(infer_outlives_requirements)] +// Outlives requirementes are inferred (RFC 2093) + +// explicit-where: infer U: 'b +struct ExFoo<'b, U> { + bar: ExBar<'b, U> +} +struct ExBar<'a, T> where T: 'a { + x: &'a (), + y: T, +} + + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs new file mode 100644 index 00000000000..81734bf514e --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs @@ -0,0 +1,23 @@ +// 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. + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + +// Type U needs to outlive lifetime 'b. +struct Foo<'b, U> { + bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309] +} + +struct Bar<'a, T> where T: 'a { + x: &'a (), + y: T, +} + +fn main() { } diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr new file mode 100644 index 00000000000..436754c7dc1 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr @@ -0,0 +1,17 @@ +error[E0309]: the parameter type `U` may not live long enough + --> $DIR/explicit-where.rs:15:5 + | +LL | struct Foo<'b, U> { + | - help: consider adding an explicit lifetime bound `U: 'b`... +LL | bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309] + | ^^^^^^^^^^^^^^^ + | +note: ...so that the type `U` will meet its required lifetime bounds + --> $DIR/explicit-where.rs:15:5 + | +LL | bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs b/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs new file mode 100644 index 00000000000..be686a80048 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs @@ -0,0 +1,22 @@ +// 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. + +// must-compile-successfully + +#![feature(infer_outlives_requirements)] +// Outlives requirementes are inferred (RFC 2093) + +// multiple-regions: infer 'b: 'a +struct MultiFoo<'a, 'b, T> { + x: &'a &'b T +} + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs new file mode 100644 index 00000000000..7ea1ce2d3dc --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs @@ -0,0 +1,19 @@ +// 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. + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + +// Lifetime 'b needs to outlive lifetime 'a +struct Foo<'a,'b,T> { + x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491] +} + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr new file mode 100644 index 00000000000..3722abd5ad6 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr @@ -0,0 +1,20 @@ +error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references + --> $DIR/multiple-regions.rs:15:5 + | +LL | x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491] + | ^^^^^^^^^^^^ + | +note: the pointer is valid for the lifetime 'a as defined on the struct at 14:1 + --> $DIR/multiple-regions.rs:14:1 + | +LL | struct Foo<'a,'b,T> { + | ^^^^^^^^^^^^^^^^^^^ +note: but the referenced data is only valid for the lifetime 'b as defined on the struct at 14:1 + --> $DIR/multiple-regions.rs:14:1 + | +LL | struct Foo<'a,'b,T> { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0491`. diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs b/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs new file mode 100644 index 00000000000..02581457fcc --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs @@ -0,0 +1,25 @@ +// 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. + +// must-compile-successfully + +#![feature(infer_outlives_requirements)] +// Outlives requirementes are inferred (RFC 2093) + +// nested-structs: infer U: 'b and therefore T: 'a +struct NestFoo<'a, T> { + field1: NestBar<'a, T> +} +struct NestBar<'b, U> { + field2: &'b U +} + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs b/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs new file mode 100644 index 00000000000..7c444dbd3b0 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs @@ -0,0 +1,26 @@ +// 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. + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + + +// Type T needs to outlive lifetime 'a. This is not reported due to +// a compilation error in Bar. +struct Foo<'a, T> { + field1: Bar<'a, T> +} + +// Type U needs to outlive lifetime 'b +struct Bar<'b, U> { + field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309] +} + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr new file mode 100644 index 00000000000..94d6cbdb5fe --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr @@ -0,0 +1,17 @@ +error[E0309]: the parameter type `U` may not live long enough + --> $DIR/nested-structs.rs:22:5 + | +LL | struct Bar<'b, U> { + | - help: consider adding an explicit lifetime bound `U: 'b`... +LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309] + | ^^^^^^^^^^^^^ + | +note: ...so that the reference type `&'b U` does not outlive the data it points at + --> $DIR/nested-structs.rs:22:5 + | +LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309] + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs b/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs new file mode 100644 index 00000000000..1234e27b866 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs @@ -0,0 +1,23 @@ +// 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. + +// must-compile-successfully + +#![feature(infer_outlives_requirements)] +// Outlives requirementes are inferred (RFC 2093) + +// projections: infer <Iterator>::Item: 'a +struct ProjFoo<'a, T: Iterator> { + bar: &'a T::Item +} + + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.rs b/src/test/ui/rfc-2093-infer-outlives/projections.rs new file mode 100644 index 00000000000..f6a557c174c --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/projections.rs @@ -0,0 +1,20 @@ +// 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. + +// ignore-tidy-linelength + +// Needs an explicit where clause stating outlives condition. RFC 2093 + +// Associated type <Iterator>::Item needs to outlives lifetime 'a. +struct Foo<'a, T: Iterator> { + bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309] +} + +fn main() { } diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.stderr b/src/test/ui/rfc-2093-infer-outlives/projections.stderr new file mode 100644 index 00000000000..9969cf48ecd --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/projections.stderr @@ -0,0 +1,16 @@ +error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough + --> $DIR/projections.rs:17:5 + | +LL | bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309] + | ^^^^^^^^^^^^^^^^ + | + = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: 'a`... +note: ...so that the reference type `&'a <T as std::iter::Iterator>::Item` does not outlive the data it points at + --> $DIR/projections.rs:17:5 + | +LL | bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs b/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs new file mode 100644 index 00000000000..f357685e139 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs @@ -0,0 +1,23 @@ +// 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. + +// must-compile-successfully + +#![feature(infer_outlives_requirements)] +// Outlives requirementes are inferred (RFC 2093) + +// reference: infer T: 'a +struct RefFoo<'a, T> { + bar: &'a [T] +} + + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.rs b/src/test/ui/rfc-2093-infer-outlives/reference.rs new file mode 100644 index 00000000000..01ccc50a130 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/reference.rs @@ -0,0 +1,18 @@ +// 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. + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + +// Type T needs to outlive lifetime 'a. +struct Foo<'a, T> { + bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309] +} + +fn main() { } diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.stderr b/src/test/ui/rfc-2093-infer-outlives/reference.stderr new file mode 100644 index 00000000000..7236bd535c9 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/reference.stderr @@ -0,0 +1,17 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/reference.rs:15:5 + | +LL | struct Foo<'a, T> { + | - help: consider adding an explicit lifetime bound `T: 'a`... +LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309] + | ^^^^^^^^^^^^ + | +note: ...so that the reference type `&'a [T]` does not outlive the data it points at + --> $DIR/reference.rs:15:5 + | +LL | bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309] + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/rfc-2093-infer-outlives/union-pass.rs b/src/test/ui/rfc-2093-infer-outlives/union-pass.rs new file mode 100644 index 00000000000..b4a61346b01 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/union-pass.rs @@ -0,0 +1,39 @@ +// 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. + +// must-compile-successfully + +#![feature(infer_outlives_requirements)] +#![feature(untagged_unions)] +#![allow(unions_with_drop_fields)] + +// Type T needs to outlive lifetime 'a. This is not reported due to +// a compilation error in Bar. +union Foo<'a, T> { + field1: Bar<'a, T> +} + +// Type U needs to outlive lifetime 'b +union Bar<'b, U> { + field2: &'b U +} + + +// Type K needs to outlive lifetime 'c. +union Ying<'c, K> { + field1: &'c Yang<K> +} + +union Yang<V> { + field2: V +} + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/union.rs b/src/test/ui/rfc-2093-infer-outlives/union.rs new file mode 100644 index 00000000000..36b1dccb13e --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/union.rs @@ -0,0 +1,40 @@ +// 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. + +// ignore-tidy-linelength + +// Needs an explicit where clause stating outlives condition. (RFC 2093) + +#![feature(untagged_unions)] + +// Type T needs to outlive lifetime 'a. This is not reported due to +// a compilation error in Bar. +union Foo<'a, T> { + field1: Bar<'a, T> +} + +// Type U needs to outlive lifetime 'b +union Bar<'b, U> { + field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309] +} + + +// Type K needs to outlive lifetime 'c. +union Ying<'c, K> { + field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309] +} + +union Yang<V> { + field2: V +} + + +fn main() {} + diff --git a/src/test/ui/rfc-2093-infer-outlives/union.stderr b/src/test/ui/rfc-2093-infer-outlives/union.stderr new file mode 100644 index 00000000000..cd13c423293 --- /dev/null +++ b/src/test/ui/rfc-2093-infer-outlives/union.stderr @@ -0,0 +1,31 @@ +error[E0309]: the parameter type `U` may not live long enough + --> $DIR/union.rs:25:5 + | +LL | union Bar<'b, U> { + | - help: consider adding an explicit lifetime bound `U: 'b`... +LL | field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309] + | ^^^^^^^^^^^^^ + | +note: ...so that the reference type `&'b U` does not outlive the data it points at + --> $DIR/union.rs:25:5 + | +LL | field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309] + | ^^^^^^^^^^^^^ + +error[E0309]: the parameter type `K` may not live long enough + --> $DIR/union.rs:31:5 + | +LL | union Ying<'c, K> { + | - help: consider adding an explicit lifetime bound `K: 'c`... +LL | field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309] + | ^^^^^^^^^^^^^^^^^^^ + | +note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at + --> $DIR/union.rs:31:5 + | +LL | field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr new file mode 100644 index 00000000000..172828b9a40 --- /dev/null +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.nll.stderr @@ -0,0 +1,51 @@ +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24 + | +LL | let __isize = &mut x.y; //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:75:10 + | +LL | &mut x.y //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5 + | +LL | x.y = 3; //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:102:5 + | +LL | x.y = 3; //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5 + | +LL | x.set(0, 0); //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:131:5 + | +LL | x.y_mut() //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6 + | +LL | *x.y_mut() = 3; //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:143:6 + | +LL | *x.y_mut() = 3; //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr new file mode 100644 index 00000000000..24abe85de76 --- /dev/null +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.nll.stderr @@ -0,0 +1,27 @@ +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25 + | +LL | let __isize = &mut *x; //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:51:11 + | +LL | &mut **x //~ ERROR cannot borrow + | ^^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `x` as mutable + --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6 + | +LL | *x = 3; //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:63:6 + | +LL | **x = 3; //~ ERROR cannot borrow + | ^^ cannot borrow as mutable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr new file mode 100644 index 00000000000..505ee95088f --- /dev/null +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr @@ -0,0 +1,54 @@ +error[E0499]: cannot borrow `f` as mutable more than once at a time + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:22:16 + | +LL | f(Box::new(|| { + | - ^^ second mutable borrow occurs here + | | + | _____first mutable borrow occurs here + | | +LL | | //~^ ERROR: cannot borrow `f` as mutable more than once +LL | | f((Box::new(|| {}))) + | | - borrow occurs due to use of `f` in closure +LL | | })); + | |_______- borrow later used here + +error[E0596]: cannot borrow immutable item `*f` as mutable + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:35:5 + | +LL | (*f)(); + | ^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*f.f` as mutable + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5 + | +LL | f.f.call_mut(()) + | ^^^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `*f` + +error[E0507]: cannot move out of borrowed content + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13 + | +LL | foo(f); + | ^ cannot move out of borrowed content + +error[E0505]: cannot move out of `f` because it is borrowed + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:65:16 + | +LL | f(Box::new(|a| { + | _____-__________^ + | | | + | |_____borrow of `f` occurs here + | || +LL | || foo(f); +LL | || //~^ ERROR cannot move `f` into closure because it is borrowed +LL | || //~| ERROR cannot move out of captured outer variable in an `FnMut` closure +LL | || }), 3); + | ||_____^____- borrow later used here + | |_____| + | move out of `f` occurs here + +error: aborting due to 5 previous errors + +Some errors occurred: E0499, E0505, E0507, E0596. +For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr new file mode 100644 index 00000000000..43934bf4aee --- /dev/null +++ b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.nll.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-call-method-from-mut-aliasable.rs:27:5 + | +LL | x.h(); //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr b/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr new file mode 100644 index 00000000000..d3c6fd66599 --- /dev/null +++ b/src/test/ui/span/borrowck-fn-in-const-b.nll.stderr @@ -0,0 +1,9 @@ +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-fn-in-const-b.rs:17:9 + | +LL | x.push(format!("this is broken")); + | ^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr new file mode 100644 index 00000000000..d02f70ea292 --- /dev/null +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr @@ -0,0 +1,10 @@ +error: compilation successful + --> $DIR/borrowck-let-suggestion-suffixes.rs:61:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | f(); +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs index 8a27af0119a..60e6c6e2989 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.rs +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.rs @@ -7,7 +7,7 @@ // <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. - +#![feature(rustc_attrs)] fn id<T>(x: T) -> T { x } fn f() { @@ -58,6 +58,6 @@ fn f() { //~| NOTE temporary value needs to live until here //~| NOTE temporary value needs to live until here -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 f(); } diff --git a/src/test/ui/span/borrowck-object-mutability.nll.stderr b/src/test/ui/span/borrowck-object-mutability.nll.stderr new file mode 100644 index 00000000000..100b5ae150a --- /dev/null +++ b/src/test/ui/span/borrowck-object-mutability.nll.stderr @@ -0,0 +1,17 @@ +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-object-mutability.rs:19:5 + | +LL | x.borrowed_mut(); //~ ERROR cannot borrow + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*x` as mutable + --> $DIR/borrowck-object-mutability.rs:29:5 + | +LL | x.borrowed_mut(); //~ ERROR cannot borrow + | ^ cannot borrow as mutable + | + = note: Value not mutable causing this error: `x` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr b/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr new file mode 100644 index 00000000000..171bb3dda66 --- /dev/null +++ b/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr @@ -0,0 +1,14 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/borrowck-ref-into-rvalue.rs:13:11 + | +LL | match Some("Hello".to_string()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough +... +LL | } + | - temporary value only lives until here +LL | println!("{}", *msg); + | ---- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/destructor-restrictions.nll.stderr b/src/test/ui/span/destructor-restrictions.nll.stderr new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/test/ui/span/destructor-restrictions.nll.stderr diff --git a/src/test/ui/span/dropck-object-cycle.nll.stderr b/src/test/ui/span/dropck-object-cycle.nll.stderr new file mode 100644 index 00000000000..64a76399da3 --- /dev/null +++ b/src/test/ui/span/dropck-object-cycle.nll.stderr @@ -0,0 +1,15 @@ +error[E0597]: `*m` does not live long enough + --> $DIR/dropck-object-cycle.rs:37:31 + | +LL | assert_eq!(object_invoke1(&*m), (4,5)); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `m` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr b/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr new file mode 100644 index 00000000000..fee0d7feb6d --- /dev/null +++ b/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr @@ -0,0 +1,39 @@ +error[E0597]: `b1` does not live long enough + --> $DIR/dropck_arr_cycle_checked.rs:111:24 + | +LL | b3.a[0].v.set(Some(&b1)); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `b1` is dropped + +error[E0597]: `b2` does not live long enough + --> $DIR/dropck_arr_cycle_checked.rs:103:24 + | +LL | b1.a[0].v.set(Some(&b2)); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `b1` is dropped + +error[E0597]: `b3` does not live long enough + --> $DIR/dropck_arr_cycle_checked.rs:105:24 + | +LL | b1.a[1].v.set(Some(&b3)); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `b1` is dropped + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr b/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr new file mode 100644 index 00000000000..2a8ef24307d --- /dev/null +++ b/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr @@ -0,0 +1,27 @@ +error[E0597]: `d1` does not live long enough + --> $DIR/dropck_direct_cycle_with_drop.rs:48:19 + | +LL | d2.p.set(Some(&d1)); + | ^^^ borrowed value does not live long enough +LL | //~^ ERROR `d1` does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `d1` is dropped + +error[E0597]: `d2` does not live long enough + --> $DIR/dropck_direct_cycle_with_drop.rs:46:19 + | +LL | d1.p.set(Some(&d2)); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `d1` is dropped + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_misc_variants.nll.stderr b/src/test/ui/span/dropck_misc_variants.nll.stderr new file mode 100644 index 00000000000..0eeec8e51be --- /dev/null +++ b/src/test/ui/span/dropck_misc_variants.nll.stderr @@ -0,0 +1,26 @@ +error[E0597]: `bomb` does not live long enough + --> $DIR/dropck_misc_variants.rs:33:36 + | +LL | _w = Wrap::<&[&str]>(NoisyDrop(&bomb)); + | ^^^^^ borrowed value does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `_w` is dropped + +error[E0597]: `v` does not live long enough + --> $DIR/dropck_misc_variants.rs:41:27 + | +LL | let u = NoisyDrop(&v); + | ^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `_w` is dropped + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr b/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr new file mode 100644 index 00000000000..41edd04c92e --- /dev/null +++ b/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr @@ -0,0 +1,39 @@ +error[E0597]: `c1` does not live long enough + --> $DIR/dropck_vec_cycle_checked.rs:118:24 + | +LL | c3.v[0].v.set(Some(&c1)); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `c1` is dropped + +error[E0597]: `c2` does not live long enough + --> $DIR/dropck_vec_cycle_checked.rs:110:24 + | +LL | c1.v[0].v.set(Some(&c2)); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `c1` is dropped + +error[E0597]: `c3` does not live long enough + --> $DIR/dropck_vec_cycle_checked.rs:112:24 + | +LL | c1.v[1].v.set(Some(&c3)); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `c1` is dropped + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-11925.nll.stderr b/src/test/ui/span/issue-11925.nll.stderr new file mode 100644 index 00000000000..68a4d5d25f4 --- /dev/null +++ b/src/test/ui/span/issue-11925.nll.stderr @@ -0,0 +1,12 @@ +error[E0597]: `x` does not live long enough + --> $DIR/issue-11925.rs:18:35 + | +LL | let f = to_fn_once(move|| &x); //~ ERROR does not live long enough + | ^- + | || + | |borrowed value only lives until here + | borrowed value does not live long enough + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-15480.nll.stderr b/src/test/ui/span/issue-15480.nll.stderr new file mode 100644 index 00000000000..2f3f6c5efa2 --- /dev/null +++ b/src/test/ui/span/issue-15480.nll.stderr @@ -0,0 +1,14 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/issue-15480.rs:15:10 + | +LL | &id(3) + | ^^^^^ temporary value does not live long enough +LL | ]; + | - temporary value only lives until here +... +LL | for &&x in &v { + | -- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr diff --git a/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.nll.stderr b/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.nll.stderr new file mode 100644 index 00000000000..3f18f4d025a --- /dev/null +++ b/src/test/ui/span/issue-24805-dropck-child-has-items-via-parent.nll.stderr @@ -0,0 +1,15 @@ +error[E0597]: `d1` does not live long enough + --> $DIR/issue-24805-dropck-child-has-items-via-parent.rs:38:18 + | +LL | _d = D_Child(&d1); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `_d` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-24805-dropck-trait-has-items.nll.stderr b/src/test/ui/span/issue-24805-dropck-trait-has-items.nll.stderr new file mode 100644 index 00000000000..79e607bb392 --- /dev/null +++ b/src/test/ui/span/issue-24805-dropck-trait-has-items.nll.stderr @@ -0,0 +1,36 @@ +error[E0597]: `d1` does not live long enough + --> $DIR/issue-24805-dropck-trait-has-items.rs:47:26 + | +LL | _d = D_HasSelfMethod(&d1); + | ^^^ borrowed value does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `_d` is dropped + +error[E0597]: `d1` does not live long enough + --> $DIR/issue-24805-dropck-trait-has-items.rs:53:33 + | +LL | _d = D_HasMethodWithSelfArg(&d1); + | ^^^ borrowed value does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `_d` is dropped + +error[E0597]: `d1` does not live long enough + --> $DIR/issue-24805-dropck-trait-has-items.rs:59:20 + | +LL | _d = D_HasType(&d1); + | ^^^ borrowed value does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `_d` is dropped + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-24895-copy-clone-dropck.nll.stderr b/src/test/ui/span/issue-24895-copy-clone-dropck.nll.stderr new file mode 100644 index 00000000000..550f9d8b60d --- /dev/null +++ b/src/test/ui/span/issue-24895-copy-clone-dropck.nll.stderr @@ -0,0 +1,14 @@ +error[E0597]: `d1` does not live long enough + --> $DIR/issue-24895-copy-clone-dropck.rs:37:14 + | +LL | d2 = D(S(&d1, "inner"), "d2"); + | ^^^ borrowed value does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `d2` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-25199.nll.stderr b/src/test/ui/span/issue-25199.nll.stderr new file mode 100644 index 00000000000..770fed8cd9c --- /dev/null +++ b/src/test/ui/span/issue-25199.nll.stderr @@ -0,0 +1,15 @@ +error[E0597]: `container` does not live long enough + --> $DIR/issue-25199.rs:80:27 + | +LL | let test = Test{test: &container}; + | ^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `container` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-26656.nll.stderr b/src/test/ui/span/issue-26656.nll.stderr new file mode 100644 index 00000000000..64bb83fc782 --- /dev/null +++ b/src/test/ui/span/issue-26656.nll.stderr @@ -0,0 +1,14 @@ +error[E0597]: `ticking` does not live long enough + --> $DIR/issue-26656.rs:50:35 + | +LL | zook.button = B::BigRedButton(&ticking); + | ^^^^^^^^ borrowed value does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `zook` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-29106.nll.stderr b/src/test/ui/span/issue-29106.nll.stderr new file mode 100644 index 00000000000..80a7421f4bd --- /dev/null +++ b/src/test/ui/span/issue-29106.nll.stderr @@ -0,0 +1,25 @@ +error[E0597]: `x` does not live long enough + --> $DIR/issue-29106.rs:26:26 + | +LL | y = Arc::new(Foo(&x)); + | ^^ borrowed value does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `y` is dropped + +error[E0597]: `x` does not live long enough + --> $DIR/issue-29106.rs:33:25 + | +LL | y = Rc::new(Foo(&x)); + | ^^ borrowed value does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `y` is dropped + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue-36537.nll.stderr b/src/test/ui/span/issue-36537.nll.stderr new file mode 100644 index 00000000000..5802bac04b1 --- /dev/null +++ b/src/test/ui/span/issue-36537.nll.stderr @@ -0,0 +1,13 @@ +error: compilation successful + --> $DIR/issue-36537.rs:11:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let p; +LL | | let a = 42; +LL | | p = &a; +LL | | //~^ ERROR `a` does not live long enough +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/span/issue-36537.rs b/src/test/ui/span/issue-36537.rs index 3eac0106b18..ca04101cf56 100644 --- a/src/test/ui/span/issue-36537.rs +++ b/src/test/ui/span/issue-36537.rs @@ -7,8 +7,8 @@ // <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. - -fn main() { +#![feature(rustc_attrs)] +fn main() { #![rustc_error] // rust-lang/rust#49855 let p; let a = 42; p = &a; diff --git a/src/test/ui/span/issue-40157.nll.stderr b/src/test/ui/span/issue-40157.nll.stderr new file mode 100644 index 00000000000..d9608f3a896 --- /dev/null +++ b/src/test/ui/span/issue-40157.nll.stderr @@ -0,0 +1,13 @@ +error[E0597]: `foo` does not live long enough + --> $DIR/issue-40157.rs:12:53 + | +LL | {println!("{:?}", match { let foo = vec![1, 2]; foo.get(1) } { x => x });} + | ------------------------------^^^-------------------- + | | | | + | | | borrowed value only lives until here + | | borrowed value does not live long enough + | borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue28498-reject-ex1.nll.stderr b/src/test/ui/span/issue28498-reject-ex1.nll.stderr new file mode 100644 index 00000000000..c5e7a93c763 --- /dev/null +++ b/src/test/ui/span/issue28498-reject-ex1.nll.stderr @@ -0,0 +1,15 @@ +error[E0597]: `foo.data` does not live long enough + --> $DIR/issue28498-reject-ex1.rs:44:29 + | +LL | foo.data[0].1.set(Some(&foo.data[1])); + | ^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `foo` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue28498-reject-lifetime-param.nll.stderr b/src/test/ui/span/issue28498-reject-lifetime-param.nll.stderr new file mode 100644 index 00000000000..25708219bd1 --- /dev/null +++ b/src/test/ui/span/issue28498-reject-lifetime-param.nll.stderr @@ -0,0 +1,15 @@ +error[E0597]: `first_dropped` does not live long enough + --> $DIR/issue28498-reject-lifetime-param.rs:44:19 + | +LL | foo1 = Foo(1, &first_dropped); + | ^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `foo1` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue28498-reject-passed-to-fn.nll.stderr b/src/test/ui/span/issue28498-reject-passed-to-fn.nll.stderr new file mode 100644 index 00000000000..66157096394 --- /dev/null +++ b/src/test/ui/span/issue28498-reject-passed-to-fn.nll.stderr @@ -0,0 +1,15 @@ +error[E0597]: `first_dropped` does not live long enough + --> $DIR/issue28498-reject-passed-to-fn.rs:46:19 + | +LL | foo1 = Foo(1, &first_dropped, Box::new(callback)); + | ^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `foo1` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/issue28498-reject-trait-bound.nll.stderr b/src/test/ui/span/issue28498-reject-trait-bound.nll.stderr new file mode 100644 index 00000000000..bb9d67983de --- /dev/null +++ b/src/test/ui/span/issue28498-reject-trait-bound.nll.stderr @@ -0,0 +1,15 @@ +error[E0597]: `first_dropped` does not live long enough + --> $DIR/issue28498-reject-trait-bound.rs:46:19 + | +LL | foo1 = Foo(1, &first_dropped); + | ^^^^^^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `foo1` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/mut-arg-hint.nll.stderr b/src/test/ui/span/mut-arg-hint.nll.stderr new file mode 100644 index 00000000000..8e1cb9720e2 --- /dev/null +++ b/src/test/ui/span/mut-arg-hint.nll.stderr @@ -0,0 +1,21 @@ +error[E0596]: cannot borrow immutable item `*a` as mutable + --> $DIR/mut-arg-hint.rs:13:9 + | +LL | a.push_str("bar"); //~ ERROR cannot borrow immutable borrowed content + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*a` as mutable + --> $DIR/mut-arg-hint.rs:18:5 + | +LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow immutable item `*a` as mutable + --> $DIR/mut-arg-hint.rs:25:9 + | +LL | a.push_str("foo"); //~ ERROR cannot borrow immutable borrowed content + | ^ cannot borrow as mutable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/src/test/ui/span/mut-ptr-cant-outlive-ref.nll.stderr b/src/test/ui/span/mut-ptr-cant-outlive-ref.nll.stderr new file mode 100644 index 00000000000..3cad23a3c03 --- /dev/null +++ b/src/test/ui/span/mut-ptr-cant-outlive-ref.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/mut-ptr-cant-outlive-ref.rs:13:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let m = RefCell::new(0); +LL | | let p; +LL | | { +... | +LL | | //~^^ ERROR `b` does not live long enough +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/span/mut-ptr-cant-outlive-ref.rs b/src/test/ui/span/mut-ptr-cant-outlive-ref.rs index 9dc0836c5e0..9774303197c 100644 --- a/src/test/ui/span/mut-ptr-cant-outlive-ref.rs +++ b/src/test/ui/span/mut-ptr-cant-outlive-ref.rs @@ -7,10 +7,10 @@ // <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. - +#![feature(rustc_attrs)] use std::cell::RefCell; -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let m = RefCell::new(0); let p; { diff --git a/src/test/ui/span/range-2.nll.stderr b/src/test/ui/span/range-2.nll.stderr new file mode 100644 index 00000000000..afb319b57d4 --- /dev/null +++ b/src/test/ui/span/range-2.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/range-2.rs:13:1 + | +LL | / pub fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let r = { +LL | | let a = 42; +LL | | let b = 42; +... | +LL | | //~| ERROR `b` does not live long enough +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/span/range-2.rs b/src/test/ui/span/range-2.rs index d69b3ea098c..a1ed9bc6aa8 100644 --- a/src/test/ui/span/range-2.rs +++ b/src/test/ui/span/range-2.rs @@ -9,8 +9,8 @@ // except according to those terms. // Test range syntax - borrow errors. - -pub fn main() { +#![feature(rustc_attrs)] +pub fn main() { #![rustc_error] // rust-lang/rust#49855 let r = { let a = 42; let b = 42; diff --git a/src/test/ui/span/regionck-unboxed-closure-lifetimes.nll.stderr b/src/test/ui/span/regionck-unboxed-closure-lifetimes.nll.stderr new file mode 100644 index 00000000000..3c918fdb147 --- /dev/null +++ b/src/test/ui/span/regionck-unboxed-closure-lifetimes.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/regionck-unboxed-closure-lifetimes.rs:13:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut f; +LL | | { +LL | | let c = 1; +... | +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/span/regionck-unboxed-closure-lifetimes.rs b/src/test/ui/span/regionck-unboxed-closure-lifetimes.rs index 93b3d673359..c814941c811 100644 --- a/src/test/ui/span/regionck-unboxed-closure-lifetimes.rs +++ b/src/test/ui/span/regionck-unboxed-closure-lifetimes.rs @@ -7,10 +7,10 @@ // <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. - +#![feature(rustc_attrs)] use std::ops::FnMut; -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut f; { let c = 1; diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr new file mode 100644 index 00000000000..651296dbeaf --- /dev/null +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr @@ -0,0 +1,14 @@ +error[E0597]: borrowed value does not live long enough + --> $DIR/regions-close-over-borrowed-ref-in-obj.rs:22:27 + | +LL | let ss: &isize = &id(1); + | ^^^^^ temporary value does not live long enough +... +LL | } + | - temporary value only lives until here +LL | } + | - borrow later used here, when `blah` is dropped + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr new file mode 100644 index 00000000000..c8a1f801201 --- /dev/null +++ b/src/test/ui/span/regions-close-over-type-parameter-2.nll.stderr @@ -0,0 +1,18 @@ +error[E0597]: `tmp0` does not live long enough + --> $DIR/regions-close-over-type-parameter-2.rs:33:20 + | +LL | let _ = { + | _____________- +LL | | let tmp0 = 3; +LL | | let tmp1 = &tmp0; + | | ^^^^^ borrowed value does not live long enough +LL | | repeater3(tmp1) +LL | | }; + | | - + | | | + | |_____borrowed value only lives until here + | borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr b/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr new file mode 100644 index 00000000000..7fd2bfbdd8f --- /dev/null +++ b/src/test/ui/span/regions-escape-loop-via-variable.nll.stderr @@ -0,0 +1,13 @@ +error[E0597]: `x` does not live long enough + --> $DIR/regions-escape-loop-via-variable.rs:21:13 + | +LL | let x = 1 + *p; + | -- borrow later used here +LL | p = &x; + | ^^ borrowed value does not live long enough +LL | } + | - borrowed value only lives until here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr b/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr new file mode 100644 index 00000000000..c7aa40f18e3 --- /dev/null +++ b/src/test/ui/span/regions-escape-loop-via-vec.nll.stderr @@ -0,0 +1,49 @@ +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/regions-escape-loop-via-vec.rs:15:11 + | +LL | let mut _y = vec![&mut x]; + | ------ borrow of `x` occurs here +LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed + | ^ use of borrowed `x` +LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed +LL | _y.push(&mut z); + | -- borrow later used here + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/regions-escape-loop-via-vec.rs:16:21 + | +LL | let mut _y = vec![&mut x]; + | ------ borrow of `x` occurs here +LL | while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed +LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed + | ^ use of borrowed `x` +LL | _y.push(&mut z); + | -- borrow later used here + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/regions-escape-loop-via-vec.rs:19:9 + | +LL | let mut _y = vec![&mut x]; + | ------ borrow of `x` occurs here +... +LL | _y.push(&mut z); + | -- borrow later used here +LL | //~^ ERROR `z` does not live long enough +LL | x += 1; //~ ERROR cannot assign + | ^^^^^^ use of borrowed `x` + +error[E0597]: `z` does not live long enough + --> $DIR/regions-escape-loop-via-vec.rs:17:17 + | +LL | _y.push(&mut z); + | -- ^^^^^^ borrowed value does not live long enough + | | + | borrow later used here +... +LL | } + | - borrowed value only lives until here + +error: aborting due to 4 previous errors + +Some errors occurred: E0503, E0597. +For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/span/regions-infer-borrow-scope-within-loop.nll.stderr b/src/test/ui/span/regions-infer-borrow-scope-within-loop.nll.stderr new file mode 100644 index 00000000000..034f80c7d54 --- /dev/null +++ b/src/test/ui/span/regions-infer-borrow-scope-within-loop.nll.stderr @@ -0,0 +1,14 @@ +error[E0597]: `*x` does not live long enough + --> $DIR/regions-infer-borrow-scope-within-loop.rs:24:20 + | +LL | y = borrow(&*x); + | ^^^ borrowed value does not live long enough +... +LL | } + | - borrowed value only lives until here +LL | assert!(*y != 0); + | -- borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/send-is-not-static-ensures-scoping.nll.stderr b/src/test/ui/span/send-is-not-static-ensures-scoping.nll.stderr new file mode 100644 index 00000000000..710b19e1932 --- /dev/null +++ b/src/test/ui/span/send-is-not-static-ensures-scoping.nll.stderr @@ -0,0 +1,30 @@ +error[E0597]: `y` does not live long enough + --> $DIR/send-is-not-static-ensures-scoping.rs:29:16 + | +LL | scoped(|| { + | ________________^ +LL | | let _z = y; +LL | | //~^ ERROR `y` does not live long enough +LL | | }) + | |_________^ borrowed value does not live long enough +LL | }; + | - borrowed value only lives until here +LL | +LL | bad.join(); + | --- borrow later used here + +error[E0597]: `x` does not live long enough + --> $DIR/send-is-not-static-ensures-scoping.rs:26:17 + | +LL | let y = &x; + | ^^ borrowed value does not live long enough +... +LL | }; + | - borrowed value only lives until here +LL | +LL | bad.join(); + | --- borrow later used here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/send-is-not-static-std-sync-2.nll.stderr b/src/test/ui/span/send-is-not-static-std-sync-2.nll.stderr new file mode 100644 index 00000000000..e794f8c27e8 --- /dev/null +++ b/src/test/ui/span/send-is-not-static-std-sync-2.nll.stderr @@ -0,0 +1,37 @@ +error[E0597]: `x` does not live long enough + --> $DIR/send-is-not-static-std-sync-2.rs:21:20 + | +LL | Mutex::new(&x) + | ^^ borrowed value does not live long enough +LL | }; + | - borrowed value only lives until here +... +LL | let _dangling = *lock.lock().unwrap(); + | ---- borrow later used here + +error[E0597]: `x` does not live long enough + --> $DIR/send-is-not-static-std-sync-2.rs:31:21 + | +LL | RwLock::new(&x) + | ^^ borrowed value does not live long enough +LL | }; + | - borrowed value only lives until here +LL | //~^^ ERROR `x` does not live long enough +LL | let _dangling = *lock.read().unwrap(); + | ---- borrow later used here + +error[E0597]: `x` does not live long enough + --> $DIR/send-is-not-static-std-sync-2.rs:41:25 + | +LL | let (_tx, rx) = { + | --- borrow later used here +... +LL | let _ = tx.send(&x); + | ^^ borrowed value does not live long enough +LL | (tx, rx) +LL | }; + | - borrowed value only lives until here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/send-is-not-static-std-sync.nll.stderr b/src/test/ui/span/send-is-not-static-std-sync.nll.stderr new file mode 100644 index 00000000000..21143306110 --- /dev/null +++ b/src/test/ui/span/send-is-not-static-std-sync.nll.stderr @@ -0,0 +1,48 @@ +error[E0505]: cannot move out of `y` because it is borrowed + --> $DIR/send-is-not-static-std-sync.rs:23:10 + | +LL | *lock.lock().unwrap() = &*y; + | --- borrow of `*y` occurs here +LL | drop(y); //~ ERROR cannot move out + | ^ move out of `y` occurs here +... +LL | *lock.lock().unwrap() = &z; + | ---- borrow later used here + +error[E0505]: cannot move out of `y` because it is borrowed + --> $DIR/send-is-not-static-std-sync.rs:36:10 + | +LL | *lock.write().unwrap() = &*y; + | --- borrow of `*y` occurs here +LL | drop(y); //~ ERROR cannot move out + | ^ move out of `y` occurs here +... +LL | *lock.write().unwrap() = &z; + | ---- borrow later used here + +error[E0505]: cannot move out of `y` because it is borrowed + --> $DIR/send-is-not-static-std-sync.rs:51:10 + | +LL | tx.send(&*y); + | --- borrow of `*y` occurs here +LL | drop(y); //~ ERROR cannot move out + | ^ move out of `y` occurs here +... +LL | tx.send(&z).unwrap(); + | -- borrow later used here + +error[E0597]: `z` does not live long enough + --> $DIR/send-is-not-static-std-sync.rs:54:17 + | +LL | tx.send(&z).unwrap(); + | ^^ borrowed value does not live long enough +LL | } + | - borrowed value only lives until here +LL | //~^^ ERROR `z` does not live long enough +LL | } + | - borrow later used here, when `tx` is dropped + +error: aborting due to 4 previous errors + +Some errors occurred: E0505, E0597. +For more information about an error, try `rustc --explain E0505`. diff --git a/src/test/ui/span/slice-borrow.nll.stderr b/src/test/ui/span/slice-borrow.nll.stderr new file mode 100644 index 00000000000..52ca125f8b6 --- /dev/null +++ b/src/test/ui/span/slice-borrow.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/slice-borrow.rs:13:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let y; +LL | | { +LL | | let x: &[isize] = &vec![1, 2, 3, 4, 5]; +LL | | y = &x[1..]; +LL | | } +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/span/slice-borrow.rs b/src/test/ui/span/slice-borrow.rs index 1b022f23246..45dff62672b 100644 --- a/src/test/ui/span/slice-borrow.rs +++ b/src/test/ui/span/slice-borrow.rs @@ -7,10 +7,10 @@ // <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. - +#![feature(rustc_attrs)] // Test slicing expressions doesn't defeat the borrow checker. -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let y; { let x: &[isize] = &vec![1, 2, 3, 4, 5]; diff --git a/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr b/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr new file mode 100644 index 00000000000..389adb231c4 --- /dev/null +++ b/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr @@ -0,0 +1,27 @@ +error[E0597]: `c1` does not live long enough + --> $DIR/vec-must-not-hide-type-from-dropck.rs:129:24 + | +LL | c2.v[0].v.set(Some(&c1)); + | ^^^ borrowed value does not live long enough +LL | //~^ ERROR `c1` does not live long enough +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `c1` is dropped + +error[E0597]: `c2` does not live long enough + --> $DIR/vec-must-not-hide-type-from-dropck.rs:127:24 + | +LL | c1.v[0].v.set(Some(&c2)); + | ^^^ borrowed value does not live long enough +... +LL | } + | - + | | + | borrowed value only lives until here + | borrow later used here, when `c1` is dropped + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/vec_refs_data_with_early_death.nll.stderr b/src/test/ui/span/vec_refs_data_with_early_death.nll.stderr new file mode 100644 index 00000000000..09ecc666cbc --- /dev/null +++ b/src/test/ui/span/vec_refs_data_with_early_death.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/vec_refs_data_with_early_death.rs:21:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut v = Vec::new(); +LL | | +LL | | let x: i8 = 3; +... | +LL | | assert_eq!(v, [&3, &4]); +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/span/vec_refs_data_with_early_death.rs b/src/test/ui/span/vec_refs_data_with_early_death.rs index 42373a87a6c..a3532d919bc 100644 --- a/src/test/ui/span/vec_refs_data_with_early_death.rs +++ b/src/test/ui/span/vec_refs_data_with_early_death.rs @@ -17,8 +17,8 @@ // element it owns; thus, for data like this, it seems like we could // loosen the restrictions here if we wanted. But it also is not // clear whether such loosening is terribly important.) - -fn main() { +#![feature(rustc_attrs)] +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut v = Vec::new(); let x: i8 = 3; diff --git a/src/test/ui/span/wf-method-late-bound-regions.nll.stderr b/src/test/ui/span/wf-method-late-bound-regions.nll.stderr new file mode 100644 index 00000000000..a175cf1b38a --- /dev/null +++ b/src/test/ui/span/wf-method-late-bound-regions.nll.stderr @@ -0,0 +1,14 @@ +error: compilation successful + --> $DIR/wf-method-late-bound-regions.rs:25:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let f = Foo(None); +LL | | let f2 = f; +LL | | let dangling = { +... | +LL | | println!("{}", dangling); +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/span/wf-method-late-bound-regions.rs b/src/test/ui/span/wf-method-late-bound-regions.rs index d58c29d4a32..317cd395d0a 100644 --- a/src/test/ui/span/wf-method-late-bound-regions.rs +++ b/src/test/ui/span/wf-method-late-bound-regions.rs @@ -11,7 +11,7 @@ // A method's receiver must be well-formed, even if it has late-bound regions. // Because of this, a method's substs being well-formed does not imply that // the method's implied bounds are met. - +#![feature(rustc_attrs)] struct Foo<'b>(Option<&'b ()>); trait Bar<'b> { @@ -22,7 +22,7 @@ impl<'b> Bar<'b> for Foo<'b> { fn xmute<'a>(&'a self, u: &'b u32) -> &'a u32 { u } } -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let f = Foo(None); let f2 = f; let dangling = { diff --git a/src/test/ui/suggestions/closure-immutable-outer-variable.nll.stderr b/src/test/ui/suggestions/closure-immutable-outer-variable.nll.stderr new file mode 100644 index 00000000000..e4e93ecac8e --- /dev/null +++ b/src/test/ui/suggestions/closure-immutable-outer-variable.nll.stderr @@ -0,0 +1,9 @@ +error[E0594]: cannot assign to immutable item `y` + --> $DIR/closure-immutable-outer-variable.rs:19:26 + | +LL | foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable + | ^^^^^^^^^ cannot mutate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/suggestions/fn-closure-mutable-capture.nll.stderr b/src/test/ui/suggestions/fn-closure-mutable-capture.nll.stderr new file mode 100644 index 00000000000..ed691843f9b --- /dev/null +++ b/src/test/ui/suggestions/fn-closure-mutable-capture.nll.stderr @@ -0,0 +1,9 @@ +error[E0594]: cannot assign to immutable item `x` + --> $DIR/fn-closure-mutable-capture.rs:15:17 + | +LL | bar(move || x = 1); + | ^^^^^ cannot mutate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/target-feature-wrong.rs b/src/test/ui/target-feature-wrong.rs index 56acbed4721..eb83ee724c7 100644 --- a/src/test/ui/target-feature-wrong.rs +++ b/src/test/ui/target-feature-wrong.rs @@ -12,6 +12,9 @@ // ignore-aarch64 // ignore-wasm // ignore-emscripten +// ignore-mips +// ignore-powerpc +// ignore-s390x #![feature(target_feature)] diff --git a/src/test/ui/target-feature-wrong.stderr b/src/test/ui/target-feature-wrong.stderr index 8773f8504cb..b5e650eaf9a 100644 --- a/src/test/ui/target-feature-wrong.stderr +++ b/src/test/ui/target-feature-wrong.stderr @@ -1,35 +1,35 @@ warning: #[target_feature = ".."] is deprecated and will eventually be removed, use #[target_feature(enable = "..")] instead - --> $DIR/target-feature-wrong.rs:18:1 + --> $DIR/target-feature-wrong.rs:21:1 | LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the feature named `foo` is not valid for this target - --> $DIR/target-feature-wrong.rs:20:18 + --> $DIR/target-feature-wrong.rs:23:18 | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ error: #[target_feature(..)] only accepts sub-keys of `enable` currently - --> $DIR/target-feature-wrong.rs:22:18 + --> $DIR/target-feature-wrong.rs:25:18 | LL | #[target_feature(bar)] | ^^^ error: #[target_feature(..)] only accepts sub-keys of `enable` currently - --> $DIR/target-feature-wrong.rs:24:18 + --> $DIR/target-feature-wrong.rs:27:18 | LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ error: #[target_feature(..)] can only be applied to `unsafe` function - --> $DIR/target-feature-wrong.rs:28:1 + --> $DIR/target-feature-wrong.rs:31:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: attribute should be applied to a function - --> $DIR/target-feature-wrong.rs:32:1 + --> $DIR/target-feature-wrong.rs:35:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL | mod another {} | -------------- not a function error: cannot use #[inline(always)] with #[target_feature] - --> $DIR/target-feature-wrong.rs:36:1 + --> $DIR/target-feature-wrong.rs:39:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr new file mode 100644 index 00000000000..f8ea891914e --- /dev/null +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr @@ -0,0 +1,36 @@ +warning: not reporting region error due to -Znll + --> $DIR/dyn-trait-underscore.rs:20:14 + | +LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime + | ^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/dyn-trait-underscore.rs:20:20 + | +LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime + | ^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/dyn-trait-underscore.rs:20:5 + | +LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime + | ^^^^^^^^ + +warning: not reporting region error due to -Znll + --> $DIR/dyn-trait-underscore.rs:20:5 + | +LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: free region `` does not outlive free region `'static` + --> $DIR/dyn-trait-underscore.rs:18:52 + | +LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { + | ____________________________________________________^ +LL | | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` +LL | | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/tools/clippy b/src/tools/clippy -Subproject b45801ff192e6f1bd3504c05e612a1004f52a24 +Subproject 8ec61a613ad1278b18a4770332b6da128704fdd diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index e48f42705f1..94a6353ad24 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -595,7 +595,7 @@ impl Config { fn has_cfg_prefix(&self, line: &str, prefix: &str) -> bool { // returns whether this line contains this prefix or not. For prefix // "ignore", returns true if line says "ignore-x86_64", "ignore-arch", - // "ignore-andorid" etc. + // "ignore-android" etc. line.starts_with(prefix) && line.as_bytes().get(prefix.len()) == Some(&b'-') } diff --git a/src/tools/rls b/src/tools/rls -Subproject b17d799d1302fd643a3dd19280f64c8ad162a4a +Subproject faccf0d07cad4c84da20c5c0102a450fca9d0b6 diff --git a/src/tools/rustdoc/main.rs b/src/tools/rustdoc/main.rs index e726dea84f1..7aca765cead 100644 --- a/src/tools/rustdoc/main.rs +++ b/src/tools/rustdoc/main.rs @@ -9,6 +9,8 @@ // except according to those terms. #![feature(link_args)] + +#[allow(unused_attributes)] // Set the stack size at link time on Windows. See rustc_driver::in_rustc_thread // for the rationale. #[cfg_attr(all(windows, target_env = "msvc"), link_args = "/STACK:16777216")] diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 06eb055f68e..fa227436640 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -13,8 +13,6 @@ //! This library contains the tidy lints and exposes it //! to be used by tools. -#![deny(warnings)] - extern crate serde; extern crate serde_json; #[macro_use] diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index f7fec2e667a..bda58bc09f7 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -12,14 +12,41 @@ use std::path::Path; +// See rust-lang/rust#48879: In addition to the mapping from `foo.rs` +// to `foo.stderr`/`foo.stdout`, we also can optionally have +// `foo.$mode.stderr`, where $mode is one of the strings on this list, +// as an alternative to use when running under that mode. +static COMPARE_MODE_NAMES: [&'static str; 1] = ["nll"]; + pub fn check(path: &Path, bad: &mut bool) { super::walk_many(&[&path.join("test/ui"), &path.join("test/ui-fulldeps")], &mut |_| false, &mut |file_path| { if let Some(ext) = file_path.extension() { if (ext == "stderr" || ext == "stdout") && !file_path.with_extension("rs").exists() { - println!("Stray file with UI testing output: {:?}", file_path); - *bad = true; + + // rust-lang/rust#48879: this fn used to be beautful + // because Path API special-cases replacing + // extensions. That works great for ".stderr" but not + // so well for ".nll.stderr". To support the latter, + // we explicitly search backwards for mode's starting + // point and build corresponding source name. + let filename = file_path.file_name().expect("need filename") + .to_str().expect("need UTF-8 filename"); + let found_matching_prefix = COMPARE_MODE_NAMES.iter().any(|mode| { + if let Some(r_idx) = filename.rfind(&format!(".{}", mode)) { + let source_name = format!("{}.rs", &filename[0..r_idx]); + let source_path = file_path.with_file_name(source_name); + source_path.exists() + } else { + false + } + }); + + if !found_matching_prefix { + println!("Stray file with UI testing output: {:?}", file_path); + *bad = true; + } } } }); |
