From 8d2af4a5458f19fbf028b5a4012d389482327ccc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 Aug 2018 16:45:18 -0600 Subject: [PATCH 01/50] Update to new system calls and enviromental variables --- .gitmodules | 2 +- src/libstd/sys/redox/mod.rs | 23 ++++++ src/libstd/sys/redox/os.rs | 101 +++++++++++++++++-------- src/libstd/sys/redox/process.rs | 41 ++++++---- src/libstd/sys/redox/syscall/call.rs | 13 +--- src/libstd/sys/redox/syscall/flag.rs | 44 ++++++++++- src/libstd/sys/redox/syscall/number.rs | 2 +- 7 files changed, 168 insertions(+), 58 deletions(-) diff --git a/.gitmodules b/.gitmodules index 038237aa179a9..b5f60e6b6770f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,7 +10,7 @@ url = https://github.com/rust-lang/rust-installer.git [submodule "src/liblibc"] path = src/liblibc - url = https://github.com/rust-lang/libc.git + url = https://gitlab.redox-os.org/redox-os/liblibc.git [submodule "src/doc/nomicon"] path = src/doc/nomicon url = https://github.com/rust-lang-nursery/nomicon.git diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index f943257c68733..f899439c3f707 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -75,6 +75,29 @@ pub fn cvt(result: Result) -> io::Result { result.map_err(|err| io::Error::from_raw_os_error(err.errno)) } +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +pub fn cvt_libc(t: T) -> io::Result { + if t.is_minus_one() { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + /// On Redox, use an illegal instruction to abort pub unsafe fn abort_internal() -> ! { ::core::intrinsics::abort(); diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index 5822216779b6e..84eb56615b60d 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -12,10 +12,12 @@ #![allow(unused_imports)] // lots of cfg code here +use libc::{self, c_char}; + use os::unix::prelude::*; use error::Error as StdError; -use ffi::{OsString, OsStr}; +use ffi::{CStr, CString, OsStr, OsString}; use fmt; use io::{self, Read, Write}; use iter; @@ -27,7 +29,7 @@ use ptr; use slice; use str; use sys_common::mutex::Mutex; -use sys::{cvt, fd, syscall}; +use sys::{cvt, cvt_libc, fd, syscall}; use vec; extern { @@ -129,6 +131,8 @@ pub fn current_exe() -> io::Result { Ok(PathBuf::from(path)) } +pub static ENV_LOCK: Mutex = Mutex::new(); + pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, _dont_send_or_sync_me: PhantomData<*mut ()>, @@ -140,52 +144,83 @@ impl Iterator for Env { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } +pub unsafe fn environ() -> *mut *const *const c_char { + extern { static mut environ: *const *const c_char; } + &mut environ +} + /// Returns a vector of (variable, value) byte-vector pairs for all the /// environment variables of the current process. pub fn env() -> Env { - let mut variables: Vec<(OsString, OsString)> = Vec::new(); - if let Ok(mut file) = ::fs::File::open("env:") { - let mut string = String::new(); - if file.read_to_string(&mut string).is_ok() { - for line in string.lines() { - let mut parts = line.splitn(2, '='); - if let Some(name) = parts.next() { - let value = parts.next().unwrap_or(""); - variables.push((OsString::from(name.to_string()), - OsString::from(value.to_string()))); - } + unsafe { + let _guard = ENV_LOCK.lock(); + let mut environ = *environ(); + if environ == ptr::null() { + panic!("os::env() failure getting env string from OS: {}", + io::Error::last_os_error()); + } + let mut result = Vec::new(); + while *environ != ptr::null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); } + environ = environ.offset(1); + } + return Env { + iter: result.into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p+1..].to_vec()), + )) } - Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData } } -pub fn getenv(key: &OsStr) -> io::Result> { - if ! key.is_empty() { - if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) { - let mut string = String::new(); - file.read_to_string(&mut string)?; - Ok(Some(OsString::from(string))) +pub fn getenv(k: &OsStr) -> io::Result> { + // environment variables with a nul byte can't be set, so their value is + // always None as well + let k = CString::new(k.as_bytes())?; + unsafe { + let _guard = ENV_LOCK.lock(); + let s = libc::getenv(k.as_ptr()) as *const libc::c_char; + let ret = if s.is_null() { + None } else { - Ok(None) - } - } else { - Ok(None) + Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) + }; + Ok(ret) } } -pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> { - if ! key.is_empty() { - let mut file = ::fs::File::create(&("env:".to_owned() + key.to_str().unwrap()))?; - file.write_all(value.as_bytes())?; - file.set_len(value.len() as u64)?; +pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let k = CString::new(k.as_bytes())?; + let v = CString::new(v.as_bytes())?; + + unsafe { + let _guard = ENV_LOCK.lock(); + cvt_libc(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ()) } - Ok(()) } -pub fn unsetenv(key: &OsStr) -> io::Result<()> { - ::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?; - Ok(()) +pub fn unsetenv(n: &OsStr) -> io::Result<()> { + let nbuf = CString::new(n.as_bytes())?; + + unsafe { + let _guard = ENV_LOCK.lock(); + cvt_libc(libc::unsetenv(nbuf.as_ptr())).map(|_| ()) + } } pub fn page_size() -> usize { diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 2037616e6ac7c..f85834dff5d05 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -9,15 +9,17 @@ // except according to those terms. use env::{split_paths}; -use ffi::OsStr; +use ffi::{CStr, OsStr}; use os::unix::ffi::OsStrExt; use fmt; use io::{self, Error, ErrorKind}; use iter; use libc::{EXIT_SUCCESS, EXIT_FAILURE}; use path::{Path, PathBuf}; +use ptr; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; +use sys::os::{ENV_LOCK, environ}; use sys::pipe::{self, AnonPipe}; use sys::{cvt, syscall}; use sys_common::process::{CommandEnv, DefaultEnvKey}; @@ -297,12 +299,6 @@ impl Command { t!(callback()); } - let args: Vec<[usize; 2]> = iter::once( - [self.program.as_ptr() as usize, self.program.len()] - ).chain( - self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]) - ).collect(); - self.env.apply(); let program = if self.program.contains(':') || self.program.contains('/') { @@ -321,14 +317,33 @@ impl Command { None }; - if let Some(program) = program { - if let Err(err) = syscall::execve(program.as_os_str().as_bytes(), &args) { - io::Error::from_raw_os_error(err.errno as i32) - } else { - panic!("return from exec without err"); + let fd = if let Some(program) = program { + t!(cvt(syscall::open(program.as_os_str().as_bytes(), syscall::O_RDONLY))) + } else { + return io::Error::from_raw_os_error(syscall::ENOENT); + }; + + let mut args: Vec<[usize; 2]> = iter::once( + [self.program.as_ptr() as usize, self.program.len()] + ).chain( + self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]) + ).collect(); + + let mut vars: Vec<[usize; 2]> = Vec::new(); + unsafe { + let _guard = ENV_LOCK.lock(); + let mut environ = *environ(); + while *environ != ptr::null() { + let var = CStr::from_ptr(*environ).to_bytes(); + vars.push([var.as_ptr() as usize, var.len()]); + environ = environ.offset(1); } + } + + if let Err(err) = syscall::fexec(fd, &args, &vars) { + io::Error::from_raw_os_error(err.errno as i32) } else { - io::Error::from_raw_os_error(syscall::ENOENT) + panic!("return from exec without err"); } } diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs index f9a8bd61ac800..0188d684d3a2d 100644 --- a/src/libstd/sys/redox/syscall/call.rs +++ b/src/libstd/sys/redox/syscall/call.rs @@ -82,12 +82,6 @@ pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result { unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } } -/// Replace the current process with a new executable -pub fn execve>(path: T, args: &[[usize; 2]]) -> Result { - unsafe { syscall4(SYS_EXECVE, path.as_ref().as_ptr() as usize, - path.as_ref().len(), args.as_ptr() as usize, args.len()) } -} - /// Exit the current process pub fn exit(status: usize) -> Result { unsafe { syscall1(SYS_EXIT, status) } @@ -110,9 +104,10 @@ pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result { unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) } } -/// Register a file for event-based I/O -pub fn fevent(fd: usize, flags: usize) -> Result { - unsafe { syscall2(SYS_FEVENT, fd, flags) } +/// Replace the current process with a new executable +pub fn fexec>(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result { + unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(), + vars.as_ptr() as usize, vars.len()) } } /// Map a file into memory diff --git a/src/libstd/sys/redox/syscall/flag.rs b/src/libstd/sys/redox/syscall/flag.rs index 0f61b9fa77b52..0f1a2c2315973 100644 --- a/src/libstd/sys/redox/syscall/flag.rs +++ b/src/libstd/sys/redox/syscall/flag.rs @@ -113,4 +113,46 @@ pub const SA_RESTART: usize = 0x10000000; pub const SA_NODEFER: usize = 0x40000000; pub const SA_RESETHAND: usize = 0x80000000; -pub const WNOHANG: usize = 1; +pub const WNOHANG: usize = 0x01; +pub const WUNTRACED: usize = 0x02; +pub const WCONTINUED: usize = 0x08; + +/// True if status indicates the child is stopped. +pub fn wifstopped(status: usize) -> bool { + (status & 0xff) == 0x7f +} + +/// If wifstopped(status), the signal that stopped the child. +pub fn wstopsig(status: usize) -> usize { + (status >> 8) & 0xff +} + +/// True if status indicates the child continued after a stop. +pub fn wifcontinued(status: usize) -> bool { + status == 0xffff +} + +/// True if STATUS indicates termination by a signal. +pub fn wifsignaled(status: usize) -> bool { + ((status & 0x7f) + 1) as i8 >= 2 +} + +/// If wifsignaled(status), the terminating signal. +pub fn wtermsig(status: usize) -> usize { + status & 0x7f +} + +/// True if status indicates normal termination. +pub fn wifexited(status: usize) -> bool { + wtermsig(status) == 0 +} + +/// If wifexited(status), the exit status. +pub fn wexitstatus(status: usize) -> usize { + (status >> 8) & 0xff +} + +/// True if status indicates a core dump was created. +pub fn wcoredump(status: usize) -> bool { + (status & 0x80) != 0 +} diff --git a/src/libstd/sys/redox/syscall/number.rs b/src/libstd/sys/redox/syscall/number.rs index 45cb40e390840..1e187565a675c 100644 --- a/src/libstd/sys/redox/syscall/number.rs +++ b/src/libstd/sys/redox/syscall/number.rs @@ -36,6 +36,7 @@ pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94; pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207; pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55; pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927; +pub const SYS_FEXEC: usize = SYS_CLASS_FILE | 11; pub const SYS_FMAP: usize = SYS_CLASS_FILE | 90; pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91; pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928; @@ -50,7 +51,6 @@ pub const SYS_BRK: usize = 45; pub const SYS_CHDIR: usize = 12; pub const SYS_CLOCK_GETTIME: usize = 265; pub const SYS_CLONE: usize = 120; -pub const SYS_EXECVE: usize = 11; pub const SYS_EXIT: usize = 1; pub const SYS_FUTEX: usize = 240; pub const SYS_GETCWD: usize = 183; From b400005861ae54fda63e7bac48010f5782577dd1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 Aug 2018 16:48:09 -0600 Subject: [PATCH 02/50] Remove unused type parameter --- src/libstd/sys/redox/syscall/call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs index 0188d684d3a2d..61cd97d6d4385 100644 --- a/src/libstd/sys/redox/syscall/call.rs +++ b/src/libstd/sys/redox/syscall/call.rs @@ -105,7 +105,7 @@ pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result { } /// Replace the current process with a new executable -pub fn fexec>(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result { +pub fn fexec(fd: usize, args: &[[usize; 2]], vars: &[[usize; 2]]) -> Result { unsafe { syscall5(SYS_FEXEC, fd, args.as_ptr() as usize, args.len(), vars.as_ptr() as usize, vars.len()) } } From 8c277d843cbac4d89f5f2dbfdb773cb80f48977b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 16 Aug 2018 18:47:52 -0600 Subject: [PATCH 03/50] Don't forget to close executable file --- src/libstd/sys/redox/process.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index f85834dff5d05..566c3e72922e4 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -318,7 +318,7 @@ impl Command { }; let fd = if let Some(program) = program { - t!(cvt(syscall::open(program.as_os_str().as_bytes(), syscall::O_RDONLY))) + t!(cvt(syscall::open(program.as_os_str().as_bytes(), syscall::O_RDONLY | syscall::O_CLOEXEC))) } else { return io::Error::from_raw_os_error(syscall::ENOENT); }; @@ -341,6 +341,7 @@ impl Command { } if let Err(err) = syscall::fexec(fd, &args, &vars) { + let _ = syscall::close(fd); io::Error::from_raw_os_error(err.errno as i32) } else { panic!("return from exec without err"); From 9d42b1bf04a807c18da0671ecadb8f4fa2044077 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 15 Oct 2018 21:16:04 +0200 Subject: [PATCH 04/50] Interpret shebangs on redox This is no longer handled on the kernel side --- src/libstd/sys/redox/process.rs | 94 ++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 566c3e72922e4..3b2cb7c5e1363 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -10,15 +10,22 @@ use env::{split_paths}; use ffi::{CStr, OsStr}; +use fs::File; use os::unix::ffi::OsStrExt; use fmt; +<<<<<<< HEAD use io::{self, Error, ErrorKind}; use iter; +======= +use io::{self, prelude::*, BufReader, Error, ErrorKind, SeekFrom}; +>>>>>>> b7b1d416a1... Interpret shebangs on redox use libc::{EXIT_SUCCESS, EXIT_FAILURE}; use path::{Path, PathBuf}; use ptr; +use sys::ext::fs::MetadataExt; +use sys::ext::io::AsRawFd; use sys::fd::FileDesc; -use sys::fs::{File, OpenOptions}; +use sys::fs::{File as SysFile, OpenOptions}; use sys::os::{ENV_LOCK, environ}; use sys::pipe::{self, AnonPipe}; use sys::{cvt, syscall}; @@ -317,20 +324,80 @@ impl Command { None }; - let fd = if let Some(program) = program { - t!(cvt(syscall::open(program.as_os_str().as_bytes(), syscall::O_RDONLY | syscall::O_CLOEXEC))) + let mut file = if let Some(program) = program { + t!(File::open(program.as_os_str())) } else { return io::Error::from_raw_os_error(syscall::ENOENT); }; - let mut args: Vec<[usize; 2]> = iter::once( - [self.program.as_ptr() as usize, self.program.len()] - ).chain( - self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()]) - ).collect(); + // Push all the arguments + let mut args: Vec<[usize; 2]> = Vec::with_capacity(1 + self.args.len()); + let interpreter = { + let mut reader = BufReader::new(&file); + + let mut shebang = [0; 2]; + let mut read = 0; + loop { + match t!(reader.read(&mut shebang[read..])) { + 0 => break, + n => read += n, + } + } + + if &shebang == b"#!" { + // This is an interpreted script. + // First of all, since we'll be passing another file to + // fexec(), we need to manually check that we have permission + // to execute this file: + let uid = t!(cvt(syscall::getuid())); + let gid = t!(cvt(syscall::getgid())); + let meta = t!(file.metadata()); + + let mode = if uid == meta.uid() as usize { + meta.mode() >> 3*2 & 0o7 + } else if gid == meta.gid() as usize { + meta.mode() >> 3*1 & 0o7 + } else { + meta.mode() & 0o7 + }; + if mode & 1 == 0 { + return io::Error::from_raw_os_error(syscall::EPERM); + } + + // Second of all, we need to actually read which interpreter it wants + let mut interpreter = Vec::new(); + t!(reader.read_until(b'\n', &mut interpreter)); + // Pop one trailing newline, if any + if interpreter.ends_with(&[b'\n']) { + interpreter.pop().unwrap(); + } + + // TODO: Here we could just reassign `file` directly, if it + // wasn't for lexical lifetimes. Remove the whole `let + // interpreter = { ... };` hack once NLL lands. + // NOTE: Although DO REMEMBER to make sure the interpreter path + // still lives long enough to reach fexec. + Some(interpreter) + } else { + None + } + }; + if let Some(ref interpreter) = interpreter { + let path: &OsStr = OsStr::from_bytes(&interpreter); + file = t!(File::open(path)); + + args.push([interpreter.as_ptr() as usize, interpreter.len()]); + } else { + t!(file.seek(SeekFrom::Start(0))); + } + + args.push([self.program.as_ptr() as usize, self.program.len()]); + args.extend(self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()])); + + // Push all the variables let mut vars: Vec<[usize; 2]> = Vec::new(); - unsafe { + { let _guard = ENV_LOCK.lock(); let mut environ = *environ(); while *environ != ptr::null() { @@ -340,8 +407,7 @@ impl Command { } } - if let Err(err) = syscall::fexec(fd, &args, &vars) { - let _ = syscall::close(fd); + if let Err(err) = syscall::fexec(file.as_raw_fd(), &args, &vars) { io::Error::from_raw_os_error(err.errno as i32) } else { panic!("return from exec without err"); @@ -408,7 +474,7 @@ impl Stdio { let mut opts = OpenOptions::new(); opts.read(readable); opts.write(!readable); - let fd = File::open(Path::new("null:"), &opts)?; + let fd = SysFile::open(Path::new("null:"), &opts)?; Ok((ChildStdio::Owned(fd.into_fd()), None)) } } @@ -421,8 +487,8 @@ impl From for Stdio { } } -impl From for Stdio { - fn from(file: File) -> Stdio { +impl From for Stdio { + fn from(file: SysFile) -> Stdio { Stdio::Fd(file.into_fd()) } } From 91c1b7a9291ca4ea91f928b1abfe8fc8fe9a0111 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Thu, 18 Oct 2018 16:53:26 +0200 Subject: [PATCH 05/50] Revert liblibc submodule url --- .gitmodules | 2 +- src/liblibc | 2 +- src/libstd/sys/redox/process.rs | 9 ++------- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.gitmodules b/.gitmodules index b5f60e6b6770f..038237aa179a9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,7 +10,7 @@ url = https://github.com/rust-lang/rust-installer.git [submodule "src/liblibc"] path = src/liblibc - url = https://gitlab.redox-os.org/redox-os/liblibc.git + url = https://github.com/rust-lang/libc.git [submodule "src/doc/nomicon"] path = src/doc/nomicon url = https://github.com/rust-lang-nursery/nomicon.git diff --git a/src/liblibc b/src/liblibc index 1844a772b6077..c75ca6465a139 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 1844a772b60771d0124a157019f627d60fea4e73 +Subproject commit c75ca6465a139704e00295be355b1f067af2f535 diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 3b2cb7c5e1363..e7a87e3ff8855 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -10,16 +10,11 @@ use env::{split_paths}; use ffi::{CStr, OsStr}; -use fs::File; -use os::unix::ffi::OsStrExt; use fmt; -<<<<<<< HEAD -use io::{self, Error, ErrorKind}; -use iter; -======= +use fs::File; use io::{self, prelude::*, BufReader, Error, ErrorKind, SeekFrom}; ->>>>>>> b7b1d416a1... Interpret shebangs on redox use libc::{EXIT_SUCCESS, EXIT_FAILURE}; +use os::unix::ffi::OsStrExt; use path::{Path, PathBuf}; use ptr; use sys::ext::fs::MetadataExt; From 51e2a63fafba5ab38f8ebfea803daaef2ec87d02 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Thu, 18 Oct 2018 16:58:09 +0200 Subject: [PATCH 06/50] Fix tidy checks --- src/libstd/sys/redox/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index e7a87e3ff8855..4370c1e05027b 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -368,7 +368,7 @@ impl Command { interpreter.pop().unwrap(); } - // TODO: Here we could just reassign `file` directly, if it + // FIXME: Here we could just reassign `file` directly, if it // wasn't for lexical lifetimes. Remove the whole `let // interpreter = { ... };` hack once NLL lands. // NOTE: Although DO REMEMBER to make sure the interpreter path From 52deb6b45484b595613dfe7199a81706706f3fb7 Mon Sep 17 00:00:00 2001 From: Florian Hartwig Date: Tue, 30 Oct 2018 16:13:42 +0100 Subject: [PATCH 07/50] Add link to std::mem::size_of to size_of intrinsic documentation --- src/libcore/intrinsics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index cceae9249e456..fe2afc59be8f1 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -672,6 +672,10 @@ extern "rust-intrinsic" { /// /// More specifically, this is the offset in bytes between successive /// items of the same type, including alignment padding. + /// + /// The stabilized version of this intrinsic is + /// [`std::mem::size_of`](../../std/mem/fn.size_of.html). + pub fn size_of() -> usize; /// Moves a value to an uninitialized memory location. From 19aa10132cc727c8561730ab096b21d14507c81d Mon Sep 17 00:00:00 2001 From: ljedrz Date: Wed, 31 Oct 2018 10:22:22 +0100 Subject: [PATCH 08/50] Speed up String::from_utf16 --- src/liballoc/string.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index ff3587d5d8730..8690f9017c406 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -618,7 +618,15 @@ impl String { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf16(v: &[u16]) -> Result { - decode_utf16(v.iter().cloned()).collect::>().map_err(|_| FromUtf16Error(())) + let mut ret = String::with_capacity(v.len()); + for c in decode_utf16(v.iter().cloned()) { + if let Ok(c) = c { + ret.push(c); + } else { + return Err(FromUtf16Error(())); + } + } + Ok(ret) } /// Decode a UTF-16 encoded slice `v` into a `String`, replacing From 7eece4771b49c4a199b0643f355b1ec6b63d95aa Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Fri, 19 Oct 2018 15:09:08 -0400 Subject: [PATCH 09/50] Add BufWriter::buffer method --- src/libstd/io/buffered.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index e26e6d391f84d..5b19c0b81bdb2 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -525,6 +525,25 @@ impl BufWriter { #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } + /// Returns a reference to the internally buffered data. + /// + /// # Examples + /// + /// ```no_run + /// # #![feature(bufreader_buffer)] + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // See how many bytes are currently buffered + /// let bytes_buffered = buf_writer.buffer().len(); + /// ``` + #[unstable(feature = "bufreader_buffer", issue = "45323")] + pub fn buffer(&self) -> &[u8] { + &self.buf[..] + } + /// Unwraps this `BufWriter`, returning the underlying writer. /// /// The buffer is written out before returning the writer. From 07d966dbb8bee4ff193293555bd9ff2705cb1ece Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Sat, 27 Oct 2018 12:19:04 -0400 Subject: [PATCH 10/50] Add some tests --- src/libstd/io/buffered.rs | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 5b19c0b81bdb2..f7b26e5888d0c 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -541,7 +541,7 @@ impl BufWriter { /// ``` #[unstable(feature = "bufreader_buffer", issue = "45323")] pub fn buffer(&self) -> &[u8] { - &self.buf[..] + &self.buf } /// Unwraps this `BufWriter`, returning the underlying writer. @@ -984,31 +984,31 @@ mod tests { let mut buf = [0, 0, 0]; let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(buf, b); + assert_eq!(buf, [5, 6, 7]); + assert_eq!(*reader.buffer(), []); let mut buf = [0, 0]; let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 2); - let b: &[_] = &[0, 1]; - assert_eq!(buf, b); + assert_eq!(buf, [0, 1]); + assert_eq!(*reader.buffer(), []); let mut buf = [0]; let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 1); - let b: &[_] = &[2]; - assert_eq!(buf, b); + assert_eq!(buf, [2]); + assert_eq!(*reader.buffer(), [3]); let mut buf = [0, 0, 0]; let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 1); - let b: &[_] = &[3, 0, 0]; - assert_eq!(buf, b); + assert_eq!(buf, [3, 0, 0]); + assert_eq!(*reader.buffer(), []); let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 1); - let b: &[_] = &[4, 0, 0]; - assert_eq!(buf, b); + assert_eq!(buf, [4, 0, 0]); + assert_eq!(*reader.buffer(), []); assert_eq!(reader.read(&mut buf).unwrap(), 0); } @@ -1097,31 +1097,40 @@ mod tests { let mut writer = BufWriter::with_capacity(2, inner); writer.write(&[0, 1]).unwrap(); + assert_eq!(*writer.buffer(), []); assert_eq!(*writer.get_ref(), [0, 1]); writer.write(&[2]).unwrap(); + assert_eq!(*writer.buffer(), [2]); assert_eq!(*writer.get_ref(), [0, 1]); writer.write(&[3]).unwrap(); + assert_eq!(*writer.buffer(), [2, 3]); assert_eq!(*writer.get_ref(), [0, 1]); writer.flush().unwrap(); + assert_eq!(*writer.buffer(), []); assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); writer.write(&[4]).unwrap(); writer.write(&[5]).unwrap(); + assert_eq!(*writer.buffer(), [4, 5]); assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); writer.write(&[6]).unwrap(); + assert_eq!(*writer.buffer(), [6]); assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); writer.write(&[7, 8]).unwrap(); + assert_eq!(*writer.buffer(), []); assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); writer.write(&[9, 10, 11]).unwrap(); + assert_eq!(*writer.buffer(), []); assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); writer.flush().unwrap(); + assert_eq!(*writer.buffer(), []); assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); } From 40e41440e46a56b5d5fd66473c23efff6d44be3f Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Thu, 1 Nov 2018 13:29:47 -0400 Subject: [PATCH 11/50] Suggested edits --- src/libstd/io/buffered.rs | 48 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index f7b26e5888d0c..12d1afe606950 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -534,7 +534,7 @@ impl BufWriter { /// use std::io::BufWriter; /// use std::net::TcpStream; /// - /// let mut buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); /// /// // See how many bytes are currently buffered /// let bytes_buffered = buf_writer.buffer().len(); @@ -985,30 +985,30 @@ mod tests { let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 3); assert_eq!(buf, [5, 6, 7]); - assert_eq!(*reader.buffer(), []); + assert_eq!(reader.buffer(), []); let mut buf = [0, 0]; let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 2); assert_eq!(buf, [0, 1]); - assert_eq!(*reader.buffer(), []); + assert_eq!(reader.buffer(), []); let mut buf = [0]; let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 1); assert_eq!(buf, [2]); - assert_eq!(*reader.buffer(), [3]); + assert_eq!(reader.buffer(), [3]); let mut buf = [0, 0, 0]; let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 1); assert_eq!(buf, [3, 0, 0]); - assert_eq!(*reader.buffer(), []); + assert_eq!(reader.buffer(), []); let nread = reader.read(&mut buf); assert_eq!(nread.unwrap(), 1); assert_eq!(buf, [4, 0, 0]); - assert_eq!(*reader.buffer(), []); + assert_eq!(reader.buffer(), []); assert_eq!(reader.read(&mut buf).unwrap(), 0); } @@ -1097,41 +1097,41 @@ mod tests { let mut writer = BufWriter::with_capacity(2, inner); writer.write(&[0, 1]).unwrap(); - assert_eq!(*writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1]); + assert_eq!(writer.buffer(), []); + assert_eq!(writer.get_ref(), [0, 1]); writer.write(&[2]).unwrap(); - assert_eq!(*writer.buffer(), [2]); - assert_eq!(*writer.get_ref(), [0, 1]); + assert_eq!(writer.buffer(), [2]); + assert_eq!(writer.get_ref(), [0, 1]); writer.write(&[3]).unwrap(); - assert_eq!(*writer.buffer(), [2, 3]); - assert_eq!(*writer.get_ref(), [0, 1]); + assert_eq!(writer.buffer(), [2, 3]); + assert_eq!(writer.get_ref(), [0, 1]); writer.flush().unwrap(); - assert_eq!(*writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + assert_eq!(writer.buffer(), []); + assert_eq!(writer.get_ref(), [0, 1, 2, 3]); writer.write(&[4]).unwrap(); writer.write(&[5]).unwrap(); - assert_eq!(*writer.buffer(), [4, 5]); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + assert_eq!(writer.buffer(), [4, 5]); + assert_eq!(writer.get_ref(), [0, 1, 2, 3]); writer.write(&[6]).unwrap(); - assert_eq!(*writer.buffer(), [6]); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); + assert_eq!(writer.buffer(), [6]); + assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5]); writer.write(&[7, 8]).unwrap(); - assert_eq!(*writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(writer.buffer(), []); + assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); writer.write(&[9, 10, 11]).unwrap(); - assert_eq!(*writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + assert_eq!(writer.buffer(), []); + assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); writer.flush().unwrap(); - assert_eq!(*writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + assert_eq!(writer.buffer(), []); + assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); } #[test] From 59a030916b8f1173c99f874365533574fa6314a9 Mon Sep 17 00:00:00 2001 From: Jonathan Behrens Date: Thu, 1 Nov 2018 16:06:41 -0400 Subject: [PATCH 12/50] Fix compile errors in test --- src/libstd/io/buffered.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 12d1afe606950..476ee3f71caf0 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -1098,40 +1098,40 @@ mod tests { writer.write(&[0, 1]).unwrap(); assert_eq!(writer.buffer(), []); - assert_eq!(writer.get_ref(), [0, 1]); + assert_eq!(*writer.get_ref(), [0, 1]); writer.write(&[2]).unwrap(); assert_eq!(writer.buffer(), [2]); - assert_eq!(writer.get_ref(), [0, 1]); + assert_eq!(*writer.get_ref(), [0, 1]); writer.write(&[3]).unwrap(); assert_eq!(writer.buffer(), [2, 3]); - assert_eq!(writer.get_ref(), [0, 1]); + assert_eq!(*writer.get_ref(), [0, 1]); writer.flush().unwrap(); assert_eq!(writer.buffer(), []); - assert_eq!(writer.get_ref(), [0, 1, 2, 3]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); writer.write(&[4]).unwrap(); writer.write(&[5]).unwrap(); assert_eq!(writer.buffer(), [4, 5]); - assert_eq!(writer.get_ref(), [0, 1, 2, 3]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); writer.write(&[6]).unwrap(); assert_eq!(writer.buffer(), [6]); - assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); writer.write(&[7, 8]).unwrap(); assert_eq!(writer.buffer(), []); - assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); writer.write(&[9, 10, 11]).unwrap(); assert_eq!(writer.buffer(), []); - assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); writer.flush().unwrap(); assert_eq!(writer.buffer(), []); - assert_eq!(writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); } #[test] From 2d368b5de8c503718296a37912558a81267b65c0 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Kollasch" Date: Tue, 25 Sep 2018 13:03:14 +0000 Subject: [PATCH 13/50] NetBSD: link libstd with librt in addition to libpthread --- src/libstd/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libstd/build.rs b/src/libstd/build.rs index b3851d22841e8..9d6e8c4cafdcb 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -41,8 +41,11 @@ fn main() { } else if target.contains("freebsd") { println!("cargo:rustc-link-lib=execinfo"); println!("cargo:rustc-link-lib=pthread"); + } else if target.contains("netbsd") { + println!("cargo:rustc-link-lib=pthread"); + println!("cargo:rustc-link-lib=rt"); } else if target.contains("dragonfly") || target.contains("bitrig") || - target.contains("netbsd") || target.contains("openbsd") { + target.contains("openbsd") { println!("cargo:rustc-link-lib=pthread"); } else if target.contains("solaris") { println!("cargo:rustc-link-lib=socket"); From ece4f472c923d72faf50efaaba60a8f51c143bec Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 11:37:27 +0100 Subject: [PATCH 14/50] For diagnostics, set spans of drops of temps to be that of the statement's terminating semicolon. --- src/librustc_mir/build/block.rs | 4 ++-- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/expr/stmt.rs | 25 +++++++++++++++++++++--- src/librustc_mir/hair/cx/block.rs | 3 +++ src/librustc_mir/hair/mod.rs | 4 ++++ 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index aa383a123b69a..83e132054a9ab 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -90,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = this.source_info(span); for stmt in stmts { - let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt); + let Stmt { kind, opt_destruction_scope, span: stmt_span } = this.hir.mirror(stmt); match kind { StmtKind::Expr { scope, expr } => { this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let si = (scope, source_info); this.in_scope(si, LintLevel::Inherited, block, |this| { let expr = this.hir.mirror(expr); - this.stmt_expr(block, expr) + this.stmt_expr(block, expr, Some(stmt_span)) }) })); } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 8fee74390cc6b..18ce7ae490708 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -351,7 +351,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Rvalue::Aggregate(adt, fields)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { - block = unpack!(this.stmt_expr(block, expr)); + block = unpack!(this.stmt_expr(block, expr, None)); block.and(this.unit_rvalue()) } ExprKind::Yield { value } => { diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index d2913872fca45..8eb46a0483917 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -351,7 +351,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Break { .. } | ExprKind::InlineAsm { .. } | ExprKind::Return { .. } => { - unpack!(block = this.stmt_expr(block, expr)); + unpack!(block = this.stmt_expr(block, expr, None)); this.cfg.push_assign_unit(block, source_info, destination); block.unit() } diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 8f52499124ab7..3b9fb7237b0c7 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -14,7 +14,18 @@ use hair::*; use rustc::mir::*; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { - pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<()> { + /// Builds a block of MIR statements to evaluate the HAIR `expr`. + /// If the original expression was an AST statement, + /// (e.g. `some().code(&here());`) then `opt_stmt_span` is the + /// span of that statement (including its semicolon, if any). + /// Diagnostics use this span (which may be larger than that of + /// `expr`) to identify when statement temporaries are dropped. + pub fn stmt_expr(&mut self, + mut block: BasicBlock, + expr: Expr<'tcx>, + opt_stmt_span: Option) + -> BlockAnd<()> + { let this = self; let expr_span = expr.span; let source_info = this.source_info(expr.span); @@ -29,7 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } => { let value = this.hir.mirror(value); this.in_scope((region_scope, source_info), lint_level, block, |this| { - this.stmt_expr(block, value) + this.stmt_expr(block, value, opt_stmt_span) }) } ExprKind::Assign { lhs, rhs } => { @@ -192,7 +203,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let expr_ty = expr.ty; let temp = this.temp(expr.ty.clone(), expr_span); unpack!(block = this.into(&temp, block, expr)); - unpack!(block = this.build_drop(block, expr_span, temp, expr_ty)); + + // Attribute drops of the statement's temps to the + // semicolon at the statement's end. + let drop_point = this.hir.tcx().sess.source_map().end_point(match opt_stmt_span { + None => expr_span, + Some(StatementSpan(span)) => span, + }); + + unpack!(block = this.build_drop(block, drop_point, temp, expr_ty)); block.unit() } } diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 586d6d87fa0dc..d56ddcb494406 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -57,6 +57,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, for (index, stmt) in stmts.iter().enumerate() { let hir_id = cx.tcx.hir.node_to_hir_id(stmt.node.id()); let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id); + let stmt_span = StatementSpan(cx.tcx.hir.span(stmt.node.id())); match stmt.node { hir::StmtKind::Expr(ref expr, _) | hir::StmtKind::Semi(ref expr, _) => { @@ -69,6 +70,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, expr: expr.to_ref(), }, opt_destruction_scope: opt_dxn_ext, + span: stmt_span, }))) } hir::StmtKind::Decl(ref decl, _) => { @@ -111,6 +113,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, lint_level: cx.lint_level_of(local.id), }, opt_destruction_scope: opt_dxn_ext, + span: stmt_span, }))); } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 8a24851de8149..fd1ddcc1cc6ca 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -71,10 +71,14 @@ pub enum StmtRef<'tcx> { Mirror(Box>), } +#[derive(Clone, Debug)] +pub struct StatementSpan(pub Span); + #[derive(Clone, Debug)] pub struct Stmt<'tcx> { pub kind: StmtKind<'tcx>, pub opt_destruction_scope: Option, + pub span: StatementSpan, } #[derive(Clone, Debug)] From 3011ecdeac214aeb99714abbefffbf6a1fe1e0c8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 12:39:54 +0100 Subject: [PATCH 15/50] Narrow span of temp holding the value of a Block expression to the block's tail (if present). --- src/librustc_mir/build/expr/stmt.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 3b9fb7237b0c7..708ddd3842d8e 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -201,7 +201,30 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } _ => { let expr_ty = expr.ty; - let temp = this.temp(expr.ty.clone(), expr_span); + + // Issue #54382: When creating temp for the value of + // expression like: + // + // `{ side_effects(); { let l = stuff(); the_value } }` + // + // it is usually better to focus on `the_value` rather + // than the entirety of block(s) surrounding it. + let mut temp_span = expr_span; + if let ExprKind::Block { body } = expr.kind { + if let Some(tail_expr) = &body.expr { + let mut expr = tail_expr; + while let rustc::hir::ExprKind::Block(subblock, _label) = &expr.node { + if let Some(subtail_expr) = &subblock.expr { + expr = subtail_expr + } else { + break; + } + } + temp_span = expr.span; + } + } + + let temp = this.temp(expr.ty.clone(), temp_span); unpack!(block = this.into(&temp, block, expr)); // Attribute drops of the statement's temps to the From 556f583587ce87bfaa5e1fd27bc89d8fdfe84339 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 12:52:53 +0100 Subject: [PATCH 16/50] Regression test for issue #54382 (I opted to rely on compare-mode=nll rather than opt into `#![feature(nll)]`, mostly to make it easy to observe the interesting differences between the AST-borrwock diagnostic and the NLL one.) --- ...54382-use-span-of-tail-of-block.nll.stderr | 18 ++++++++++++ .../issue-54382-use-span-of-tail-of-block.rs | 28 +++++++++++++++++++ ...sue-54382-use-span-of-tail-of-block.stderr | 15 ++++++++++ 3 files changed, 61 insertions(+) create mode 100644 src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr create mode 100644 src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs create mode 100644 src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr new file mode 100644 index 0000000000000..31f49b2836e91 --- /dev/null +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr @@ -0,0 +1,18 @@ +error[E0597]: `_thing1` does not live long enough + --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:29 + | +LL | D("other").next(&_thing1) + | ----------------^^^^^^^^- + | | | + | | borrowed value does not live long enough + | a temporary with access to the borrow is created here ... +LL | } +LL | } + | - `_thing1` dropped here while still borrowed +LL | +LL | ; + | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs new file mode 100644 index 0000000000000..99eafe0e9d18f --- /dev/null +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.rs @@ -0,0 +1,28 @@ +fn main() { + { + let mut _thing1 = D(Box::new("thing1")); + { + let _thing2 = D("thing2"); + side_effects(); + D("other").next(&_thing1) + } + } + + ; +} + +#[derive(Debug)] +struct D(T); + +impl Drop for D { + fn drop(&mut self) { + println!("dropping {:?})", self); + } +} + +impl D { + fn next(&self, _other: U) -> D { D(_other) } + fn end(&self) { } +} + +fn side_effects() { } diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr new file mode 100644 index 0000000000000..eeba7d6bb445f --- /dev/null +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.stderr @@ -0,0 +1,15 @@ +error[E0597]: `_thing1` does not live long enough + --> $DIR/issue-54382-use-span-of-tail-of-block.rs:7:30 + | +LL | D("other").next(&_thing1) + | ^^^^^^^ borrowed value does not live long enough +LL | } +LL | } + | - `_thing1` dropped here while still borrowed +LL | +LL | ; + | - borrowed value needs to live until here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. From e7e1a52f63433c4e5d37836104b8080b3ad4e8c7 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 14:31:12 +0100 Subject: [PATCH 17/50] Refactor code so that block_context observations has nicely named (and documented) methods. --- src/librustc_mir/build/block.rs | 12 +----- src/librustc_mir/build/expr/as_temp.rs | 16 ++------ src/librustc_mir/build/mod.rs | 56 +++++++++++++++++++++++++- 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index 83e132054a9ab..2ef71617b7cb6 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -177,17 +177,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let destination_ty = destination.ty(&this.local_decls, tcx).to_ty(tcx); if let Some(expr) = expr { let tail_result_is_ignored = destination_ty.is_unit() || - match this.block_context.last() { - // no context: conservatively assume result is read - None => false, - - // sub-expression: block result feeds into some computation - Some(BlockFrame::SubExpr) => false, - - // otherwise: use accumualated is_ignored state. - Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) | - Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored, - }; + this.block_context.currently_ignores_tail_results(); this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored }); unpack!(block = this.into(destination, block, expr)); diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index e0bf02c6739e3..8f50a1e9a21b9 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -10,7 +10,7 @@ //! See docs in build/expr/mod.rs -use build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; +use build::{BlockAnd, BlockAndExtension, Builder}; use hair::*; use rustc::middle::region; use rustc::mir::*; @@ -68,19 +68,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context); // Find out whether this temp is being created within the // tail expression of a block whose result is ignored. - for bf in this.block_context.iter().rev() { - match bf { - BlockFrame::SubExpr => continue, - BlockFrame::Statement { .. } => break, - &BlockFrame::TailExpr { tail_result_is_ignored } => { - local_decl = local_decl.block_tail(BlockTailInfo { - tail_result_is_ignored - }); - break; - } - } + if let Some(tail_info) = this.block_context.currently_in_block_tail() { + local_decl = local_decl.block_tail(tail_info); } - this.local_decls.push(local_decl) }; if !expr_ty.is_never() { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 5b4001f0652ad..a01f8940a948a 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -336,6 +336,9 @@ impl BlockFrame { } } +#[derive(Debug)] +struct BlockContext(Vec); + struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { hir: Cx<'a, 'gcx, 'tcx>, cfg: CFG<'tcx>, @@ -359,7 +362,7 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// start just throwing new entries onto that vector in order to /// distinguish the context of EXPR1 from the context of EXPR2 in /// `{ STMTS; EXPR1 } + EXPR2` - block_context: Vec, + block_context: BlockContext, /// The current unsafe block in scope, even if it is hidden by /// a PushUnsafeBlock @@ -409,6 +412,55 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } +impl BlockContext { + fn new() -> Self { BlockContext(vec![]) } + fn push(&mut self, bf: BlockFrame) { self.0.push(bf); } + fn pop(&mut self) -> Option { self.0.pop() } + + /// Traverses the frames on the BlockContext, searching for either + /// the first block-tail expression frame with no intervening + /// statement frame. + /// + /// Notably, this skips over `SubExpr` frames; this method is + /// meant to be used in the context of understanding the + /// relationship of a temp (created within some complicated + /// expression) with its containing expression, and whether the + /// value of that *containing expression* (not the temp!) is + /// ignored. + fn currently_in_block_tail(&self) -> Option { + for bf in self.0.iter().rev() { + match bf { + BlockFrame::SubExpr => continue, + BlockFrame::Statement { .. } => break, + &BlockFrame::TailExpr { tail_result_is_ignored } => + return Some(BlockTailInfo { tail_result_is_ignored }) + } + } + + return None; + } + + /// Looks at the topmost frame on the BlockContext and reports + /// whether its one that would discard a block tail result. + /// + /// Unlike `currently_within_ignored_tail_expression`, this does + /// *not* skip over `SubExpr` frames: here, we want to know + /// whether the block result itself is discarded. + fn currently_ignores_tail_results(&self) -> bool { + match self.0.last() { + // no context: conservatively assume result is read + None => false, + + // sub-expression: block result feeds into some computation + Some(BlockFrame::SubExpr) => false, + + // otherwise: use accumulated is_ignored state. + Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) | + Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored, + } + } +} + #[derive(Debug)] enum LocalsForNode { /// In the usual case, a node-id for an identifier maps to at most @@ -764,7 +816,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn_span: span, arg_count, scopes: vec![], - block_context: vec![], + block_context: BlockContext::new(), source_scopes: IndexVec::new(), source_scope: OUTERMOST_SOURCE_SCOPE, source_scope_local_data: IndexVec::new(), From dd6398256ec0bde52722831d6b6cf604c9cdf1ed Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Nov 2018 14:32:17 +0100 Subject: [PATCH 18/50] Revise the temp creation for blocks in `stmt_expr` to setup `BlockTailInfo`. --- src/librustc_mir/build/expr/stmt.rs | 18 +++++++++++++++++- ...-54382-use-span-of-tail-of-block.nll.stderr | 2 ++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 708ddd3842d8e..45235b3153934 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -210,6 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // it is usually better to focus on `the_value` rather // than the entirety of block(s) surrounding it. let mut temp_span = expr_span; + let mut temp_in_tail_of_block = false; if let ExprKind::Block { body } = expr.kind { if let Some(tail_expr) = &body.expr { let mut expr = tail_expr; @@ -221,10 +222,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } temp_span = expr.span; + temp_in_tail_of_block = true; } } - let temp = this.temp(expr.ty.clone(), temp_span); + let temp = { + let mut local_decl = LocalDecl::new_temp(expr.ty.clone(), temp_span); + if temp_in_tail_of_block { + if this.block_context.currently_ignores_tail_results() { + local_decl = local_decl.block_tail(BlockTailInfo { + tail_result_is_ignored: true + }); + } + } + let temp = this.local_decls.push(local_decl); + let place = Place::Local(temp); + debug!("created temp {:?} for expr {:?} in block_context: {:?}", + temp, expr, this.block_context); + place + }; unpack!(block = this.into(&temp, block, expr)); // Attribute drops of the statement's temps to the diff --git a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr index 31f49b2836e91..c308562c0cc76 100644 --- a/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr +++ b/src/test/ui/nll/issue-54382-use-span-of-tail-of-block.nll.stderr @@ -12,6 +12,8 @@ LL | } LL | LL | ; | - ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D` + | + = note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped. error: aborting due to previous error From 39771339fd4f62d4c35676bd7cd1ddb4c5d9b84c Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 8 Nov 2018 15:28:06 +0100 Subject: [PATCH 19/50] Allow unsized types in mem::drop and mem::forget --- src/libcore/intrinsics.rs | 4 + src/libcore/lib.rs | 1 + src/libcore/mem.rs | 120 ++++++++++++++++++++++++- src/librustc_codegen_llvm/intrinsic.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 1 + 5 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index cceae9249e456..4fcce7096b4b6 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -714,6 +714,10 @@ extern "rust-intrinsic" { /// initialize memory previous set to the result of `uninit`. pub fn uninit() -> T; + /// Moves a value out of scope without running drop glue. + #[cfg(not(stage0))] + pub fn forget(_: T); + /// Reinterprets the bits of a value of one type as another type. /// /// Both types must have the same size. Neither the original, nor the result, diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1bbc7892c6bef..b7d0742877ee5 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -107,6 +107,7 @@ #![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(unboxed_closures)] +#![feature(unsized_locals)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_alias)] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 1d0b194487e68..cff605489ed3e 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -139,6 +139,124 @@ pub use intrinsics::transmute; /// [ub]: ../../reference/behavior-considered-undefined.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(stage0))] +pub fn forget(t: T) { + unsafe { intrinsics::forget(t) } +} + +/// Takes ownership and "forgets" about the value **without running its destructor**. +/// +/// Any resources the value manages, such as heap memory or a file handle, will linger +/// forever in an unreachable state. However, it does not guarantee that pointers +/// to this memory will remain valid. +/// +/// * If you want to leak memory, see [`Box::leak`][leak]. +/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. +/// * If you want to dispose of a value properly, running its destructor, see +/// [`mem::drop`][drop]. +/// +/// # Safety +/// +/// `forget` is not marked as `unsafe`, because Rust's safety guarantees +/// do not include a guarantee that destructors will always run. For example, +/// a program can create a reference cycle using [`Rc`][rc], or call +/// [`process::exit`][exit] to exit without running destructors. Thus, allowing +/// `mem::forget` from safe code does not fundamentally change Rust's safety +/// guarantees. +/// +/// That said, leaking resources such as memory or I/O objects is usually undesirable, +/// so `forget` is only recommended for specialized use cases like those shown below. +/// +/// Because forgetting a value is allowed, any `unsafe` code you write must +/// allow for this possibility. You cannot return a value and expect that the +/// caller will necessarily run the value's destructor. +/// +/// [rc]: ../../std/rc/struct.Rc.html +/// [exit]: ../../std/process/fn.exit.html +/// +/// # Examples +/// +/// Leak an I/O object, never closing the file: +/// +/// ```no_run +/// use std::mem; +/// use std::fs::File; +/// +/// let file = File::open("foo.txt").unwrap(); +/// mem::forget(file); +/// ``` +/// +/// The practical use cases for `forget` are rather specialized and mainly come +/// up in unsafe or FFI code. +/// +/// ## Use case 1 +/// +/// You have created an uninitialized value using [`mem::uninitialized`][uninit]. +/// You must either initialize or `forget` it on every computation path before +/// Rust drops it automatically, like at the end of a scope or after a panic. +/// Running the destructor on an uninitialized value would be [undefined behavior][ub]. +/// +/// ``` +/// use std::mem; +/// use std::ptr; +/// +/// # let some_condition = false; +/// unsafe { +/// let mut uninit_vec: Vec = mem::uninitialized(); +/// +/// if some_condition { +/// // Initialize the variable. +/// ptr::write(&mut uninit_vec, Vec::new()); +/// } else { +/// // Forget the uninitialized value so its destructor doesn't run. +/// mem::forget(uninit_vec); +/// } +/// } +/// ``` +/// +/// ## Use case 2 +/// +/// You have duplicated the bytes making up a value, without doing a proper +/// [`Clone`][clone]. You need the value's destructor to run only once, +/// because a double `free` is undefined behavior. +/// +/// An example is a possible implementation of [`mem::swap`][swap]: +/// +/// ``` +/// use std::mem; +/// use std::ptr; +/// +/// # #[allow(dead_code)] +/// fn swap(x: &mut T, y: &mut T) { +/// unsafe { +/// // Give ourselves some scratch space to work with +/// let mut t: T = mem::uninitialized(); +/// +/// // Perform the swap, `&mut` pointers never alias +/// ptr::copy_nonoverlapping(&*x, &mut t, 1); +/// ptr::copy_nonoverlapping(&*y, x, 1); +/// ptr::copy_nonoverlapping(&t, y, 1); +/// +/// // y and t now point to the same thing, but we need to completely +/// // forget `t` because we do not want to run the destructor for `T` +/// // on its value, which is still owned somewhere outside this function. +/// mem::forget(t); +/// } +/// } +/// ``` +/// +/// [drop]: fn.drop.html +/// [uninit]: fn.uninitialized.html +/// [clone]: ../clone/trait.Clone.html +/// [swap]: fn.swap.html +/// [FFI]: ../../book/first-edition/ffi.html +/// [box]: ../../std/boxed/struct.Box.html +/// [leak]: ../../std/boxed/struct.Box.html#method.leak +/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [ub]: ../../reference/behavior-considered-undefined.html +#[inline] +#[cfg(stage0)] +#[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { ManuallyDrop::new(t); } @@ -763,7 +881,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// [`Copy`]: ../../std/marker/trait.Copy.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn drop(_x: T) { } +pub fn drop(_x: T) { } /// Interprets `src` as having type `&U`, and then reads `src` without moving /// the contained value. diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 03244c18ac3e4..1681e0137bd68 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -193,7 +193,7 @@ pub fn codegen_intrinsic_call( return; } // Effectively no-ops - "uninit" => { + "uninit" | "forget" => { return; } "needs_drop" => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3156458b4aa4a..0279105473f2a 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -134,6 +134,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "rustc_peek" => (1, vec![param(0)], param(0)), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), + "forget" => (1, vec![param(0)], param(0)), "transmute" => (2, vec![ param(0) ], param(1)), "move_val_init" => { (1, From 06cf9ae7f98f06cde8424ce569efe72c0728c252 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 8 Nov 2018 17:12:14 +0100 Subject: [PATCH 20/50] Fix return type of forget intrinsic --- src/librustc_typeck/check/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 0279105473f2a..f34cd53e4c9f3 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -134,7 +134,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "rustc_peek" => (1, vec![param(0)], param(0)), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), - "forget" => (1, vec![param(0)], param(0)), + "forget" => (1, vec![param(0)], tcx.mk_unit()), "transmute" => (2, vec![ param(0) ], param(1)), "move_val_init" => { (1, From f211581330399945802a227c4405fd92f983a2b8 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Thu, 8 Nov 2018 17:58:12 +0100 Subject: [PATCH 21/50] Use T: ?Sized in intrinsics::forget --- src/libcore/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 4fcce7096b4b6..f795e41f7c5f0 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -716,7 +716,7 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. #[cfg(not(stage0))] - pub fn forget(_: T); + pub fn forget(_: T); /// Reinterprets the bits of a value of one type as another type. /// From c1487145493c54b41df16eb7ffe6fdd3b82e6a78 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 10 Nov 2018 18:08:50 +0000 Subject: [PATCH 22/50] Rewrite `...` as `..=` as a MachineApplicable 2018 idiom lint --- src/librustc/lint/context.rs | 7 ++- src/librustc/lint/mod.rs | 2 +- src/librustc_lint/builtin.rs | 44 ++++++++++++++----- src/librustc_lint/unused.rs | 4 +- .../lint/inclusive-range-pattern-syntax.fixed | 6 +++ .../ui/lint/inclusive-range-pattern-syntax.rs | 6 +++ .../inclusive-range-pattern-syntax.stderr | 6 +++ .../range-inclusive-pattern-precedence.stderr | 4 +- 8 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 5470aff77f8a4..8acbaaa844d74 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1020,9 +1020,12 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { } fn visit_pat(&mut self, p: &'a ast::Pat) { - run_lints!(self, check_pat, p); + let mut visit_subpats = true; + run_lints!(self, check_pat, p, &mut visit_subpats); self.check_id(p.id); - ast_visit::walk_pat(self, p); + if visit_subpats { + ast_visit::walk_pat(self, p); + } } fn visit_expr(&mut self, e: &'a ast::Expr) { diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index afd7800810982..18922ec5d1739 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -341,7 +341,7 @@ pub trait EarlyLintPass: LintPass { fn check_block_post(&mut self, _: &EarlyContext<'_>, _: &ast::Block) { } fn check_stmt(&mut self, _: &EarlyContext<'_>, _: &ast::Stmt) { } fn check_arm(&mut self, _: &EarlyContext<'_>, _: &ast::Arm) { } - fn check_pat(&mut self, _: &EarlyContext<'_>, _: &ast::Pat) { } + fn check_pat(&mut self, _: &EarlyContext<'_>, _: &ast::Pat, _: &mut bool) { } fn check_expr(&mut self, _: &EarlyContext<'_>, _: &ast::Expr) { } fn check_expr_post(&mut self, _: &EarlyContext<'_>, _: &ast::Expr) { } fn check_ty(&mut self, _: &EarlyContext<'_>, _: &ast::Ty) { } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2a9b58200e5d6..652de5dd1205c 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -40,6 +40,8 @@ use rustc::util::nodemap::FxHashSet; use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast; +use syntax::ptr::P; +use syntax::ast::Expr; use syntax::attr; use syntax::source_map::Spanned; use syntax::edition::Edition; @@ -47,6 +49,7 @@ use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_a use syntax_pos::{BytePos, Span, SyntaxContext}; use syntax::symbol::keywords; use syntax::errors::{Applicability, DiagnosticBuilder}; +use syntax::print::pprust::expr_to_string; use rustc::hir::{self, GenericParamKind, PatKind}; use rustc::hir::intravisit::FnKind; @@ -1407,21 +1410,42 @@ impl LintPass for EllipsisInclusiveRangePatterns { } impl EarlyLintPass for EllipsisInclusiveRangePatterns { - fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat) { - use self::ast::{PatKind, RangeEnd, RangeSyntax}; + fn check_pat(&mut self, cx: &EarlyContext, pat: &ast::Pat, visit_subpats: &mut bool) { + use self::ast::{PatKind, RangeEnd, RangeSyntax::DotDotDot}; + + /// If `pat` is a `...` pattern, return the start and end of the range, as well as the span + /// corresponding to the ellipsis. + fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(&P, &P, Span)> { + match &pat.node { + PatKind::Range(a, b, Spanned { span, node: RangeEnd::Included(DotDotDot), .. }) => { + Some((a, b, *span)) + } + _ => None, + } + } + + let (parenthesise, endpoints) = match &pat.node { + PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)), + _ => (false, matches_ellipsis_pat(pat)), + }; - if let PatKind::Range( - _, _, Spanned { span, node: RangeEnd::Included(RangeSyntax::DotDotDot) } - ) = pat.node { + if let Some((start, end, join)) = endpoints { let msg = "`...` range patterns are deprecated"; + let suggestion = "use `..=` for an inclusive range"; + let (span, replacement) = if parenthesise { + *visit_subpats = false; + (pat.span, format!("&({}..={})", expr_to_string(&start), expr_to_string(&end))) + } else { + (join, "..=".to_owned()) + }; let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, span, msg); err.span_suggestion_short_with_applicability( - span, "use `..=` for an inclusive range", "..=".to_owned(), - // FIXME: outstanding problem with precedence in ref patterns: - // https://github.com/rust-lang/rust/issues/51043#issuecomment-392252285 - Applicability::MaybeIncorrect + span, + suggestion, + replacement, + Applicability::MachineApplicable, ); - err.emit() + err.emit(); } } } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 6d365e6d1ecbf..7eab7d2100290 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -396,12 +396,12 @@ impl EarlyLintPass for UnusedParens { self.check_unused_parens_expr(cx, &value, msg, followed_by_block); } - fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat) { + fn check_pat(&mut self, cx: &EarlyContext, p: &ast::Pat, _: &mut bool) { use ast::PatKind::{Paren, Range}; // The lint visitor will visit each subpattern of `p`. We do not want to lint any range // pattern no matter where it occurs in the pattern. For something like `&(a..=b)`, there // is a recursive `check_pat` on `a` and `b`, but we will assume that if there are - // unnecessry parens they serve a purpose of readability. + // unnecessary parens they serve a purpose of readability. if let Paren(ref pat) = p.node { match pat.node { Range(..) => {} diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.fixed b/src/test/ui/lint/inclusive-range-pattern-syntax.fixed index d16859df79e25..f0aee8a51f18b 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.fixed +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.fixed @@ -20,4 +20,10 @@ fn main() { //~^ WARN `...` range patterns are deprecated _ => {} } + + match &despondency { + &(1..=2) => {} + //~^ WARN `...` range patterns are deprecated + _ => {} + } } diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.rs b/src/test/ui/lint/inclusive-range-pattern-syntax.rs index 9d418aec0858f..97bc04faa774b 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.rs +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.rs @@ -20,4 +20,10 @@ fn main() { //~^ WARN `...` range patterns are deprecated _ => {} } + + match &despondency { + &1...2 => {} + //~^ WARN `...` range patterns are deprecated + _ => {} + } } diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr index de04fed589b23..9226137f1152f 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr @@ -10,3 +10,9 @@ note: lint level defined here LL | #![warn(ellipsis_inclusive_range_patterns)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: `...` range patterns are deprecated + --> $DIR/inclusive-range-pattern-syntax.rs:25:9 + | +LL | &1...2 => {} + | ^^^^^^ help: use `..=` for an inclusive range + diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.stderr b/src/test/ui/range/range-inclusive-pattern-precedence.stderr index cd5ce3035c683..3ac6be2b8ea6a 100644 --- a/src/test/ui/range/range-inclusive-pattern-precedence.stderr +++ b/src/test/ui/range/range-inclusive-pattern-precedence.stderr @@ -11,10 +11,10 @@ LL | box 10..=15 => {} | ^^^^^^^ help: add parentheses to clarify the precedence: `(10 ..=15)` warning: `...` range patterns are deprecated - --> $DIR/range-inclusive-pattern-precedence.rs:24:11 + --> $DIR/range-inclusive-pattern-precedence.rs:24:9 | LL | &0...9 => {} - | ^^^ help: use `..=` for an inclusive range + | ^^^^^^ help: use `..=` for an inclusive range | note: lint level defined here --> $DIR/range-inclusive-pattern-precedence.rs:19:9 From c63df7c64fbb1cd010e24ac4eb66b87aab8e650f Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 10 Nov 2018 21:27:40 +0000 Subject: [PATCH 23/50] Use non-short suggestion for parenthesised ..= --- src/librustc_lint/builtin.rs | 28 +++++++++++-------- .../inclusive-range-pattern-syntax.stderr | 2 +- .../range-inclusive-pattern-precedence.stderr | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 652de5dd1205c..696fee04273fd 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1432,20 +1432,26 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { if let Some((start, end, join)) = endpoints { let msg = "`...` range patterns are deprecated"; let suggestion = "use `..=` for an inclusive range"; - let (span, replacement) = if parenthesise { + if parenthesise { *visit_subpats = false; - (pat.span, format!("&({}..={})", expr_to_string(&start), expr_to_string(&end))) + let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg); + err.span_suggestion_with_applicability( + pat.span, + suggestion, + format!("&({}..={})", expr_to_string(&start), expr_to_string(&end)), + Applicability::MachineApplicable, + ); + err.emit(); } else { - (join, "..=".to_owned()) + let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg); + err.span_suggestion_short_with_applicability( + join, + suggestion, + "..=".to_owned(), + Applicability::MachineApplicable, + ); + err.emit(); }; - let mut err = cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, span, msg); - err.span_suggestion_short_with_applicability( - span, - suggestion, - replacement, - Applicability::MachineApplicable, - ); - err.emit(); } } } diff --git a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr index 9226137f1152f..b13afdbc023d4 100644 --- a/src/test/ui/lint/inclusive-range-pattern-syntax.stderr +++ b/src/test/ui/lint/inclusive-range-pattern-syntax.stderr @@ -14,5 +14,5 @@ warning: `...` range patterns are deprecated --> $DIR/inclusive-range-pattern-syntax.rs:25:9 | LL | &1...2 => {} - | ^^^^^^ help: use `..=` for an inclusive range + | ^^^^^^ help: use `..=` for an inclusive range: `&(1..=2)` diff --git a/src/test/ui/range/range-inclusive-pattern-precedence.stderr b/src/test/ui/range/range-inclusive-pattern-precedence.stderr index 3ac6be2b8ea6a..6fa67a5d4fa30 100644 --- a/src/test/ui/range/range-inclusive-pattern-precedence.stderr +++ b/src/test/ui/range/range-inclusive-pattern-precedence.stderr @@ -14,7 +14,7 @@ warning: `...` range patterns are deprecated --> $DIR/range-inclusive-pattern-precedence.rs:24:9 | LL | &0...9 => {} - | ^^^^^^ help: use `..=` for an inclusive range + | ^^^^^^ help: use `..=` for an inclusive range: `&(0..=9)` | note: lint level defined here --> $DIR/range-inclusive-pattern-precedence.rs:19:9 From 0c6a093afa7cd6943551b4855b3cc2588befdf3f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Nov 2018 10:06:41 +0100 Subject: [PATCH 24/50] Unix RwLock: avoid racy access to write_locked --- src/libstd/sys/unix/rwlock.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index c754d5b8359a9..8c385ae7760af 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -14,7 +14,7 @@ use sync::atomic::{AtomicUsize, Ordering}; pub struct RWLock { inner: UnsafeCell, - write_locked: UnsafeCell, + write_locked: UnsafeCell, // guarded by the `inner` RwLock num_readers: AtomicUsize, } @@ -52,7 +52,7 @@ impl RWLock { // allow that because it could lead to aliasing issues. if r == libc::EAGAIN { panic!("rwlock maximum reader count exceeded"); - } else if r == libc::EDEADLK || *self.write_locked.get() { + } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) { if r == 0 { self.raw_unlock(); } From db133901042f7ccc8194b240c8381281bc4be575 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Nov 2018 10:54:13 +0100 Subject: [PATCH 25/50] do not skip return code check in release builds --- src/libstd/sys/unix/rwlock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index 8c385ae7760af..fcd6f7a27b6e3 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -58,7 +58,7 @@ impl RWLock { } panic!("rwlock read lock would result in deadlock"); } else { - debug_assert_eq!(r, 0); + assert_eq!(r, 0); self.num_readers.fetch_add(1, Ordering::Relaxed); } } From 39a0969e64c06e7c6e5447b5633b02e4e4e931df Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 7 Nov 2018 10:08:41 +0100 Subject: [PATCH 26/50] Make `NodeId` a `newtype_index` to enable niche optimizations --- src/librustc/hir/intravisit.rs | 5 +-- src/librustc/hir/map/hir_id_validator.rs | 2 +- src/librustc/session/mod.rs | 4 +- src/librustc_driver/pretty.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 2 +- src/libsyntax/ast.rs | 54 ++++++++---------------- src/libsyntax/lib.rs | 3 +- 7 files changed, 26 insertions(+), 46 deletions(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index dcc0f8545e5d7..d9963f23a1593 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -49,7 +49,6 @@ use hir::map::{self, Map}; use super::itemlikevisit::DeepVisitor; use std::cmp; -use std::u32; #[derive(Copy, Clone)] pub enum FnKind<'a> { @@ -1152,8 +1151,8 @@ pub struct IdRange { impl IdRange { pub fn max() -> IdRange { IdRange { - min: NodeId::from_u32(u32::MAX), - max: NodeId::from_u32(u32::MIN), + min: NodeId::MAX, + max: NodeId::from_u32(0), } } diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs index 896a6163eba64..501c17867f039 100644 --- a/src/librustc/hir/map/hir_id_validator.rs +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -124,7 +124,7 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> { .enumerate() .find(|&(_, &entry)| hir_id == entry) .expect("no node_to_hir_id entry"); - let node_id = NodeId::new(node_id); + let node_id = NodeId::from_usize(node_id); missing_items.push(format!("[local_id: {}, node:{}]", local_id, self.hir_map.node_to_string(node_id))); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 8cfbd27fc6163..8582900b72c83 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -393,7 +393,7 @@ impl Session { match id.as_usize().checked_add(count) { Some(next) => { - self.next_node_id.set(ast::NodeId::new(next)); + self.next_node_id.set(ast::NodeId::from_usize(next)); } None => bug!("Input too large, ran out of node ids!"), } @@ -1160,7 +1160,7 @@ pub fn build_session_( recursion_limit: Once::new(), type_length_limit: Once::new(), const_eval_stack_frame_limit: 100, - next_node_id: OneThread::new(Cell::new(NodeId::new(1))), + next_node_id: OneThread::new(Cell::new(NodeId::from_u32(1))), allocator_kind: Once::new(), injected_panic_runtime: Once::new(), imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())), diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index b4f6d10b1f829..b26d4fd09e90b 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -566,7 +566,7 @@ impl FromStr for UserIdentifiedItem { type Err = (); fn from_str(s: &str) -> Result { Ok(s.parse() - .map(ast::NodeId::new) + .map(ast::NodeId::from_u32) .map(ItemViaNode) .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect()))) } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a3694cd73ad53..5a91b50f6bcc9 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -663,7 +663,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { let mut errors = false; let mut seen_spans = FxHashSet::default(); let mut error_vec = Vec::new(); - let mut prev_root_id: NodeId = NodeId::new(0); + let mut prev_root_id: NodeId = NodeId::from_u32(0); for i in 0 .. self.determined_imports.len() { let import = self.determined_imports[i]; let error = self.finalize_import(import); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2f17bc0548cad..b5ef14689f93a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -18,7 +18,6 @@ pub use util::parser::ExprPrecedence; use ext::hygiene::{Mark, SyntaxContext}; use print::pprust; use ptr::P; -use rustc_data_structures::indexed_vec; use rustc_data_structures::indexed_vec::Idx; use rustc_target::spec::abi::Abi; use source_map::{dummy_spanned, respan, Spanned}; @@ -31,7 +30,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use serialize::{self, Decoder, Encoder}; use std::fmt; -use std::u32; pub use rustc_target::abi::FloatTy; @@ -213,71 +211,53 @@ pub struct ParenthesisedArgs { pub output: Option>, } -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct NodeId(u32); - -impl NodeId { - pub fn new(x: usize) -> NodeId { - assert!(x < (u32::MAX as usize)); - NodeId(x as u32) - } - - pub fn from_u32(x: u32) -> NodeId { - NodeId(x) - } - - pub fn as_usize(&self) -> usize { - self.0 as usize +// hack to ensure that we don't try to access the private parts of `NodeId` in this module +mod node_id_inner { + use rustc_data_structures::indexed_vec::Idx; + newtype_index! { + pub struct NodeId { + ENCODABLE = custom + } } +} - pub fn as_u32(&self) -> u32 { - self.0 - } +pub use self::node_id_inner::NodeId; +impl NodeId { pub fn placeholder_from_mark(mark: Mark) -> Self { - NodeId(mark.as_u32()) + NodeId::from_u32(mark.as_u32()) } pub fn placeholder_to_mark(self) -> Mark { - Mark::from_u32(self.0) + Mark::from_u32(self.as_u32()) } } impl fmt::Display for NodeId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) + fmt::Display::fmt(&self.as_u32(), f) } } impl serialize::UseSpecializedEncodable for NodeId { fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_u32(self.0) + s.emit_u32(self.as_u32()) } } impl serialize::UseSpecializedDecodable for NodeId { fn default_decode(d: &mut D) -> Result { - d.read_u32().map(NodeId) - } -} - -impl indexed_vec::Idx for NodeId { - fn new(idx: usize) -> Self { - NodeId::new(idx) - } - - fn index(self) -> usize { - self.as_usize() + d.read_u32().map(NodeId::from_u32) } } /// Node id used to represent the root of the crate. -pub const CRATE_NODE_ID: NodeId = NodeId(0); +pub const CRATE_NODE_ID: NodeId = NodeId::from_u32_const(0); /// When parsing and doing expansions, we initially give all AST nodes this AST /// node value. Then later, in the renumber pass, we renumber them to have /// small, positive ids. -pub const DUMMY_NODE_ID: NodeId = NodeId(!0); +pub const DUMMY_NODE_ID: NodeId = NodeId::MAX; /// A modifier on a bound, currently this is only used for `?Sized`, where the /// modifier is `Maybe`. Negative bounds should also be handled here. diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index e9a6535cba1d2..9bbd59e09be15 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -26,6 +26,7 @@ #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] #![feature(str_escape)] +#![feature(step_trait)] #![feature(try_trait)] #![feature(unicode_internals)] @@ -37,7 +38,7 @@ extern crate serialize; #[macro_use] extern crate log; pub extern crate rustc_errors as errors; extern crate syntax_pos; -extern crate rustc_data_structures; +#[macro_use] extern crate rustc_data_structures; extern crate rustc_target; #[macro_use] extern crate scoped_tls; #[macro_use] From a1d89266e5f96a2232c7202bf812dee1f845ae02 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 7 Nov 2018 11:01:18 +0100 Subject: [PATCH 27/50] Turn `HirLocalId` into a `newtype_index` --- src/librustc/dep_graph/dep_node.rs | 6 ++-- src/librustc/hir/lowering.rs | 4 +-- src/librustc/hir/map/hir_id_validator.rs | 4 +-- src/librustc/hir/mod.rs | 45 +++++++++--------------- src/librustc/ich/impls_hir.rs | 11 ++++-- src/librustc_driver/pretty.rs | 8 ++--- 6 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 61996b5a8a75c..3ff2545f78dfa 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -63,7 +63,7 @@ use mir::interpret::GlobalId; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; -use hir::{HirId, ItemLocalId}; +use hir::HirId; use ich::{Fingerprint, StableHashingContext}; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; @@ -790,11 +790,11 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for HirId { fn to_fingerprint(&self, tcx: TyCtxt<'_, '_, '_>) -> Fingerprint { let HirId { owner, - local_id: ItemLocalId(local_id), + local_id, } = *self; let def_path_hash = tcx.def_path_hash(DefId::local(owner)); - let local_id = Fingerprint::from_smaller_hash(local_id as u64); + let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into()); def_path_hash.0.combine(local_id) } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index dd5d4b8f6afff..e532b50a28b6b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -588,7 +588,7 @@ impl<'a> LoweringContext<'a> { *local_id_counter += 1; hir::HirId { owner: def_index, - local_id: hir::ItemLocalId(local_id), + local_id: hir::ItemLocalId::from_u32(local_id), } }) } @@ -616,7 +616,7 @@ impl<'a> LoweringContext<'a> { hir::HirId { owner: def_index, - local_id: hir::ItemLocalId(local_id), + local_id: hir::ItemLocalId::from_u32(local_id), } }) } diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs index 501c17867f039..ac4119dc372d3 100644 --- a/src/librustc/hir/map/hir_id_validator.rs +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -101,7 +101,7 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> { if max != self.hir_ids_seen.len() - 1 { // Collect the missing ItemLocalIds let missing: Vec<_> = (0 .. max as u32 + 1) - .filter(|&i| !self.hir_ids_seen.contains_key(&ItemLocalId(i))) + .filter(|&i| !self.hir_ids_seen.contains_key(&ItemLocalId::from_u32(i))) .collect(); // Try to map those to something more useful @@ -110,7 +110,7 @@ impl<'a, 'hir: 'a> HirIdValidator<'a, 'hir> { for local_id in missing { let hir_id = HirId { owner: owner_def_index, - local_id: ItemLocalId(local_id as u32), + local_id: ItemLocalId::from_u32(local_id), }; trace!("missing hir id {:#?}", hir_id); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f57e3ff913b38..bfe1649380581 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -37,7 +37,6 @@ use syntax::util::parser::ExprPrecedence; use ty::AdtKind; use ty::query::Providers; -use rustc_data_structures::indexed_vec; use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope}; use rustc_data_structures::thin_vec::ThinVec; @@ -121,40 +120,28 @@ impl serialize::UseSpecializedDecodable for HirId { } } - -/// An `ItemLocalId` uniquely identifies something within a given "item-like", -/// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no -/// guarantee that the numerical value of a given `ItemLocalId` corresponds to -/// the node's position within the owning item in any way, but there is a -/// guarantee that the `LocalItemId`s within an owner occupy a dense range of -/// integers starting at zero, so a mapping that maps all or most nodes within -/// an "item-like" to something else can be implement by a `Vec` instead of a -/// tree or hash map. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, - RustcEncodable, RustcDecodable)] -pub struct ItemLocalId(pub u32); - -impl ItemLocalId { - pub fn as_usize(&self) -> usize { - self.0 as usize +// hack to ensure that we don't try to access the private parts of `NodeId` in this module +mod item_local_id_inner { + use rustc_data_structures::indexed_vec::Idx; + /// An `ItemLocalId` uniquely identifies something within a given "item-like", + /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no + /// guarantee that the numerical value of a given `ItemLocalId` corresponds to + /// the node's position within the owning item in any way, but there is a + /// guarantee that the `LocalItemId`s within an owner occupy a dense range of + /// integers starting at zero, so a mapping that maps all or most nodes within + /// an "item-like" to something else can be implement by a `Vec` instead of a + /// tree or hash map. + newtype_index! { + pub struct ItemLocalId { .. } } } -impl indexed_vec::Idx for ItemLocalId { - fn new(idx: usize) -> Self { - debug_assert!((idx as u32) as usize == idx); - ItemLocalId(idx as u32) - } - - fn index(self) -> usize { - self.0 as usize - } -} +pub use self::item_local_id_inner::ItemLocalId; /// The `HirId` corresponding to CRATE_NODE_ID and CRATE_DEF_INDEX pub const CRATE_HIR_ID: HirId = HirId { owner: CRATE_DEF_INDEX, - local_id: ItemLocalId(0) + local_id: ItemLocalId::from_u32_const(0) }; pub const DUMMY_HIR_ID: HirId = HirId { @@ -162,7 +149,7 @@ pub const DUMMY_HIR_ID: HirId = HirId { local_id: DUMMY_ITEM_LOCAL_ID, }; -pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId(!0); +pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX; #[derive(Clone, RustcEncodable, RustcDecodable, Copy)] pub struct Label { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index b220634d0d903..ae0d78d2958ad 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -79,7 +79,14 @@ impl<'a> ToStableHashKey> for CrateNum { } } -impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); +impl<'a> HashStable> for hir::ItemLocalId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + self.as_u32().hash_stable(hcx, hasher); + } +} impl<'a> ToStableHashKey> for hir::ItemLocalId { @@ -800,7 +807,7 @@ impl<'a> HashStable> for hir::Mod { .iter() .map(|id| { let (def_path_hash, local_id) = id.id.to_stable_hash_key(hcx); - debug_assert_eq!(local_id, hir::ItemLocalId(0)); + debug_assert_eq!(local_id, hir::ItemLocalId::from_u32(0)); def_path_hash.0 }).fold(Fingerprint::ZERO, |a, b| { a.combine_commutative(b) diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index b26d4fd09e90b..c7ba31e339570 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -425,7 +425,7 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { pprust_hir::AnnNode::Item(item) => { s.s.space()?; s.synth_comment(format!("node_id: {} hir local_id: {}", - item.id, item.hir_id.local_id.0)) + item.id, item.hir_id.local_id.as_u32())) } pprust_hir::AnnNode::SubItem(id) => { s.s.space()?; @@ -434,18 +434,18 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { pprust_hir::AnnNode::Block(blk) => { s.s.space()?; s.synth_comment(format!("block node_id: {} hir local_id: {}", - blk.id, blk.hir_id.local_id.0)) + blk.id, blk.hir_id.local_id.as_u32())) } pprust_hir::AnnNode::Expr(expr) => { s.s.space()?; s.synth_comment(format!("node_id: {} hir local_id: {}", - expr.id, expr.hir_id.local_id.0))?; + expr.id, expr.hir_id.local_id.as_u32()))?; s.pclose() } pprust_hir::AnnNode::Pat(pat) => { s.s.space()?; s.synth_comment(format!("pat node_id: {} hir local_id: {}", - pat.id, pat.hir_id.local_id.0)) + pat.id, pat.hir_id.local_id.as_u32())) } } } From 4bf7c33b79405f4cd6c2b6dd05a2bc270e3658a2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 8 Nov 2018 10:44:40 +0100 Subject: [PATCH 28/50] Fix rustdoc --- src/librustdoc/passes/collect_intra_doc_links.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a780322e85e86..471ba6345e248 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -243,7 +243,7 @@ fn look_for_tests<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx>( if tests.found_tests == 0 { let mut diag = cx.tcx.struct_span_lint_node( lint::builtin::MISSING_DOC_CODE_EXAMPLES, - NodeId::new(0), + NodeId::from_u32(0), span_of_attrs(&item.attrs), "Missing code example in this documentation"); diag.emit(); @@ -281,14 +281,14 @@ impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for LinkCollector<'a, 'tcx, 'rcx, 'cstor let current_item = match item.inner { ModuleItem(..) => { if item.attrs.inner_docs { - if item_node_id.unwrap() != NodeId::new(0) { + if item_node_id.unwrap() != NodeId::from_u32(0) { item.name.clone() } else { None } } else { match parent_node.or(self.mod_ids.last().cloned()) { - Some(parent) if parent != NodeId::new(0) => { + Some(parent) if parent != NodeId::from_u32(0) => { //FIXME: can we pull the parent module's name from elsewhere? Some(self.cx.tcx.hir.name(parent).to_string()) } @@ -538,13 +538,13 @@ fn resolution_failure( ); diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - NodeId::new(0), + NodeId::from_u32(0), sp, &msg); diag.span_label(sp, "cannot be resolved, ignoring"); } else { diag = cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - NodeId::new(0), + NodeId::from_u32(0), sp, &msg); @@ -564,7 +564,7 @@ fn resolution_failure( diag } else { cx.tcx.struct_span_lint_node(lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - NodeId::new(0), + NodeId::from_u32(0), sp, &msg) }; From 4c9ee595841375ab94a8f1b18c524809addaf3fa Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 8 Nov 2018 15:00:55 +0100 Subject: [PATCH 29/50] Reintroduce the original debug formatting for NodeIds --- src/libsyntax/ast.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index b5ef14689f93a..4d56acabf1bba 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -217,6 +217,7 @@ mod node_id_inner { newtype_index! { pub struct NodeId { ENCODABLE = custom + DEBUG_FORMAT = "NodeId({})" } } } From e5fd34c1aec57b60a96fa96568fe878209e052f3 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 8 Nov 2018 18:23:52 +0100 Subject: [PATCH 30/50] Fix fulldeps test with NodeId --- src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs index f2f14f84923c0..2c5de33232754 100644 --- a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs +++ b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs @@ -43,7 +43,7 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree]) &[], Edition::Edition2015, // not used... - NodeId::new(0)); + NodeId::from_u32(0)); let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) { Success(map) => map, Failure(_, tok) => { From 3e5dfdd6f6bb8164a5924c65811bce353fbf4bf7 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 9 Nov 2018 11:00:39 +0100 Subject: [PATCH 31/50] Typo nit --- src/librustc/hir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index bfe1649380581..a2b15f00265ab 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -120,7 +120,7 @@ impl serialize::UseSpecializedDecodable for HirId { } } -// hack to ensure that we don't try to access the private parts of `NodeId` in this module +// hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module mod item_local_id_inner { use rustc_data_structures::indexed_vec::Idx; /// An `ItemLocalId` uniquely identifies something within a given "item-like", From 22039597e103a44b058755e2cc60736cf1fa5392 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 9 Nov 2018 11:00:51 +0100 Subject: [PATCH 32/50] Fix fallout it rustc_driver tests --- src/librustc_driver/test.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 28b7c610a91c0..8865c7e438e5e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -232,20 +232,20 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { // children of 1, etc let dscope = region::Scope { - id: hir::ItemLocalId(1), + id: hir::ItemLocalId::from_u32(1), data: region::ScopeData::Destruction, }; self.region_scope_tree.record_scope_parent(dscope, None); self.create_region_hierarchy( &RH { - id: hir::ItemLocalId(1), + id: hir::ItemLocalId::from_u32(1), sub: &[ RH { - id: hir::ItemLocalId(10), + id: hir::ItemLocalId::from_u32(10), sub: &[], }, RH { - id: hir::ItemLocalId(11), + id: hir::ItemLocalId::from_u32(11), sub: &[], }, ], @@ -400,7 +400,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> { let r = ty::ReScope(region::Scope { - id: hir::ItemLocalId(id), + id: hir::ItemLocalId::from_u32(id), data: region::ScopeData::Node, }); self.infcx From 4d2934e803d1c948c5e4681a84f33b91c0a0fc64 Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 12 Nov 2018 17:19:55 +0100 Subject: [PATCH 33/50] Add forget_unsized only --- src/libcore/mem.rs | 122 ++++++--------------------------------------- 1 file changed, 15 insertions(+), 107 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index cff605489ed3e..f612f89e0826f 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -139,126 +139,34 @@ pub use intrinsics::transmute; /// [ub]: ../../reference/behavior-considered-undefined.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg(not(stage0))] -pub fn forget(t: T) { - unsafe { intrinsics::forget(t) } +pub fn forget(t: T) { + ManuallyDrop::new(t); } /// Takes ownership and "forgets" about the value **without running its destructor**. /// -/// Any resources the value manages, such as heap memory or a file handle, will linger -/// forever in an unreachable state. However, it does not guarantee that pointers -/// to this memory will remain valid. -/// -/// * If you want to leak memory, see [`Box::leak`][leak]. -/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. -/// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`][drop]. -/// -/// # Safety -/// -/// `forget` is not marked as `unsafe`, because Rust's safety guarantees -/// do not include a guarantee that destructors will always run. For example, -/// a program can create a reference cycle using [`Rc`][rc], or call -/// [`process::exit`][exit] to exit without running destructors. Thus, allowing -/// `mem::forget` from safe code does not fundamentally change Rust's safety -/// guarantees. -/// -/// That said, leaking resources such as memory or I/O objects is usually undesirable, -/// so `forget` is only recommended for specialized use cases like those shown below. -/// -/// Because forgetting a value is allowed, any `unsafe` code you write must -/// allow for this possibility. You cannot return a value and expect that the -/// caller will necessarily run the value's destructor. +/// This function works exactly the same as [`forget`], except it also accepts unsized values. It +/// will never be stabilized and is only available because we haven't decided to relax the bounds +/// on [`forget`] just yet. /// -/// [rc]: ../../std/rc/struct.Rc.html -/// [exit]: ../../std/process/fn.exit.html +/// [`forget`]: fn.forget.html /// /// # Examples /// -/// Leak an I/O object, never closing the file: -/// -/// ```no_run -/// use std::mem; -/// use std::fs::File; -/// -/// let file = File::open("foo.txt").unwrap(); -/// mem::forget(file); -/// ``` -/// -/// The practical use cases for `forget` are rather specialized and mainly come -/// up in unsafe or FFI code. -/// -/// ## Use case 1 -/// -/// You have created an uninitialized value using [`mem::uninitialized`][uninit]. -/// You must either initialize or `forget` it on every computation path before -/// Rust drops it automatically, like at the end of a scope or after a panic. -/// Running the destructor on an uninitialized value would be [undefined behavior][ub]. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// # let some_condition = false; -/// unsafe { -/// let mut uninit_vec: Vec = mem::uninitialized(); -/// -/// if some_condition { -/// // Initialize the variable. -/// ptr::write(&mut uninit_vec, Vec::new()); -/// } else { -/// // Forget the uninitialized value so its destructor doesn't run. -/// mem::forget(uninit_vec); -/// } -/// } /// ``` +/// #![feature(forget_unsized)] /// -/// ## Use case 2 -/// -/// You have duplicated the bytes making up a value, without doing a proper -/// [`Clone`][clone]. You need the value's destructor to run only once, -/// because a double `free` is undefined behavior. -/// -/// An example is a possible implementation of [`mem::swap`][swap]: -/// -/// ``` /// use std::mem; -/// use std::ptr; -/// -/// # #[allow(dead_code)] -/// fn swap(x: &mut T, y: &mut T) { -/// unsafe { -/// // Give ourselves some scratch space to work with -/// let mut t: T = mem::uninitialized(); /// -/// // Perform the swap, `&mut` pointers never alias -/// ptr::copy_nonoverlapping(&*x, &mut t, 1); -/// ptr::copy_nonoverlapping(&*y, x, 1); -/// ptr::copy_nonoverlapping(&t, y, 1); -/// -/// // y and t now point to the same thing, but we need to completely -/// // forget `t` because we do not want to run the destructor for `T` -/// // on its value, which is still owned somewhere outside this function. -/// mem::forget(t); -/// } -/// } +/// let f: Box = Box::new(|| ()); +/// let f = *f; +/// mem::forget_unsized(f); /// ``` -/// -/// [drop]: fn.drop.html -/// [uninit]: fn.uninitialized.html -/// [clone]: ../clone/trait.Clone.html -/// [swap]: fn.swap.html -/// [FFI]: ../../book/first-edition/ffi.html -/// [box]: ../../std/boxed/struct.Box.html -/// [leak]: ../../std/boxed/struct.Box.html#method.leak -/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw -/// [ub]: ../../reference/behavior-considered-undefined.html #[inline] -#[cfg(stage0)] -#[stable(feature = "rust1", since = "1.0.0")] -pub fn forget(t: T) { - ManuallyDrop::new(t); +#[cfg(not(stage0))] +#[unstable(feature = "forget_unsized", issue = "0")] +pub fn forget_unsized(t: T) { + unsafe { intrinsics::forget(t) } } /// Returns the size of a type in bytes. @@ -881,7 +789,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// [`Copy`]: ../../std/marker/trait.Copy.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub fn drop(_x: T) { } +pub fn drop(_x: T) { } /// Interprets `src` as having type `&U`, and then reads `src` without moving /// the contained value. From 56d3a824e46ce9976a017ef41c318a66444da99c Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Mon, 12 Nov 2018 18:36:49 +0100 Subject: [PATCH 34/50] Update docs --- src/libcore/mem.rs | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f612f89e0826f..7fe195d63be7a 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -143,25 +143,12 @@ pub fn forget(t: T) { ManuallyDrop::new(t); } -/// Takes ownership and "forgets" about the value **without running its destructor**. +/// Like [`forget`], but also accepts unsized values. /// -/// This function works exactly the same as [`forget`], except it also accepts unsized values. It -/// will never be stabilized and is only available because we haven't decided to relax the bounds -/// on [`forget`] just yet. +/// This function is just a shim intended to be removed when the `unsized_locals` feature gets +/// stabilized. /// /// [`forget`]: fn.forget.html -/// -/// # Examples -/// -/// ``` -/// #![feature(forget_unsized)] -/// -/// use std::mem; -/// -/// let f: Box = Box::new(|| ()); -/// let f = *f; -/// mem::forget_unsized(f); -/// ``` #[inline] #[cfg(not(stage0))] #[unstable(feature = "forget_unsized", issue = "0")] From 2f7b95d932f9bac550e076920b7fab1e1021bd16 Mon Sep 17 00:00:00 2001 From: cynecx Date: Tue, 13 Nov 2018 17:23:30 +0100 Subject: [PATCH 35/50] Change sidebar selector to fix compatibility with docs.rs --- src/librustdoc/html/static/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 1ae3b0b88c6dd..fb599c8518957 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -956,7 +956,7 @@ span.since { padding-top: 0px; } - body > .sidebar { + .rustdoc > .sidebar { height: 45px; min-height: 40px; margin: 0; From 58a2267c15d7214e8ef9548ce95f2aad4502fbd2 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 13 Nov 2018 15:50:31 +0100 Subject: [PATCH 36/50] hir: remove an unused hir_vec macro pattern --- src/librustc/hir/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f57e3ff913b38..dda94bd26bed1 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -58,7 +58,6 @@ macro_rules! hir_vec { ($($x:expr),*) => ( $crate::hir::HirVec::from(vec![$($x),*]) ); - ($($x:expr,)*) => (hir_vec![$($x),*]) } pub mod check_attr; From 5ea0e0d1aa47924ba60d21164b3612fb79716eb3 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 13 Nov 2018 16:15:16 +0100 Subject: [PATCH 37/50] hir: simplify fmt::Debug for hir::Path --- src/librustc/hir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index dda94bd26bed1..2dd2deee26165 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -330,7 +330,7 @@ impl Path { impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "path({})", print::to_string(print::NO_ANN, |s| s.print_path(self, false))) + write!(f, "path({})", self) } } From 3d919297b9febda29b649d1862d39a96a4448812 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 13 Nov 2018 16:24:14 +0100 Subject: [PATCH 38/50] hir: remove an unused type alias --- src/librustc/hir/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 2dd2deee26165..595655589639d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -27,7 +27,7 @@ use syntax_pos::{Span, DUMMY_SP, symbol::InternedString}; use syntax::source_map::{self, Spanned}; use rustc_target::spec::abi::Abi; use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; -use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; +use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy}; use syntax::attr::InlineAttr; use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; @@ -697,8 +697,6 @@ pub struct WhereEqPredicate { pub rhs_ty: P, } -pub type CrateConfig = HirVec>; - /// The top-level data structure that stores the entire contents of /// the crate currently being compiled. /// From cf4f5c3b349d994bb2024c700956f043fc913fe6 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Tue, 13 Nov 2018 17:23:18 +0100 Subject: [PATCH 39/50] hir: simplify a match expression --- src/librustc/hir/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 595655589639d..af67f8cec8ca8 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1193,8 +1193,8 @@ impl StmtKind { pub fn id(&self) -> NodeId { match *self { - StmtKind::Decl(_, id) => id, - StmtKind::Expr(_, id) => id, + StmtKind::Decl(_, id) | + StmtKind::Expr(_, id) | StmtKind::Semi(_, id) => id, } } From 4e35cbb22eceac145a6f794cde869b3684e0b1d5 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 12 Nov 2018 13:05:20 -0500 Subject: [PATCH 40/50] fix various typos in doc comments --- src/liballoc/collections/btree/node.rs | 2 +- src/liballoc/raw_vec.rs | 2 +- src/libcore/num/f32.rs | 2 +- src/libcore/task/wake.rs | 2 +- src/libproc_macro/lib.rs | 12 ++++++------ src/librustc/dep_graph/cgu_reuse_tracker.rs | 2 +- src/librustc/hir/def.rs | 2 +- src/librustc/infer/canonical/canonicalizer.rs | 2 +- src/librustc/infer/canonical/query_response.rs | 2 +- src/librustc/infer/canonical/substitute.rs | 2 +- .../nice_region_error/outlives_closure.rs | 2 +- src/librustc/infer/higher_ranked/mod.rs | 2 +- src/librustc/infer/mod.rs | 6 +++--- src/librustc/infer/type_variable.rs | 2 +- src/librustc/lint/levels.rs | 2 +- src/librustc/session/config.rs | 12 ++++++------ src/librustc/traits/query/dropck_outlives.rs | 2 +- src/librustc/ty/fold.rs | 4 ++-- src/librustc/ty/layout.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc_codegen_llvm/base.rs | 2 +- src/librustc_codegen_llvm/llvm_util.rs | 2 +- src/librustc_codegen_utils/symbol_names.rs | 2 +- src/librustc_data_structures/graph/scc/mod.rs | 2 +- src/librustc_data_structures/owning_ref/mod.rs | 4 ++-- src/librustc_data_structures/sorted_map.rs | 2 +- src/librustc_driver/lib.rs | 4 ++-- src/librustc_incremental/persist/dirty_clean.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_mir/borrow_check/nll/type_check/mod.rs | 2 +- src/librustc_mir/borrow_check/places_conflict.rs | 2 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/hair/mod.rs | 2 +- src/librustc_mir/hair/pattern/_match.rs | 6 +++--- src/librustc_mir/interpret/validity.rs | 2 +- src/librustc_passes/rvalue_promotion.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustdoc/config.rs | 2 +- src/libstd/alloc.rs | 2 +- src/libstd/collections/hash/map.rs | 2 +- src/libstd/keyword_docs.rs | 2 +- src/libstd/net/ip.rs | 2 +- src/libstd/process.rs | 4 ++-- src/libstd/sys/redox/fd.rs | 2 +- src/libstd/sys/redox/syscall/call.rs | 4 ++-- src/libstd/sys/unix/fd.rs | 2 +- src/libstd/thread/mod.rs | 2 +- src/libsyntax/tokenstream.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- 49 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index deca9591fbd5c..f9b455fe796d1 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -69,7 +69,7 @@ struct LeafNode { /// This node's index into the parent node's `edges` array. /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`. - /// This is only guaranteed to be initialized when `parent` is nonnull. + /// This is only guaranteed to be initialized when `parent` is non-null. parent_idx: MaybeUninit, /// The number of keys and values this node stores. diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 837770feecef5..e87bf78561c61 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -44,7 +44,7 @@ use boxed::Box; /// This enables you to use capacity growing logic catch the overflows in your length /// that might occur with zero-sized types. /// -/// However this means that you need to be careful when roundtripping this type +/// However this means that you need to be careful when round-tripping this type /// with a `Box<[T]>`: `cap()` won't yield the len. However `with_capacity`, /// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity /// field. This allows zero-sized types to not be special-cased by consumers of diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 577c823f9a060..d6c3996971a58 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -445,7 +445,7 @@ impl f32 { /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. /// /// Rather than trying to preserve signaling-ness cross-platform, this - /// implementation favours preserving the exact bits. This means that + /// implementation favors preserving the exact bits. This means that /// any payloads encoded in NaNs will be preserved even if the result of /// this method is sent over the network from an x86 machine to a MIPS one. /// diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index c9fb22e0080dd..c0ce7255d6287 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -108,7 +108,7 @@ impl Drop for Waker { /// is ready to be run. /// /// This is similar to the `Waker` type, but cannot be sent across threads. -/// Task executors can use this type to implement more optimized singlethreaded wakeup +/// Task executors can use this type to implement more optimized single-threaded wakeup /// behavior. #[repr(transparent)] #[derive(Clone)] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 1a2b16a4fed06..60b6a8bac41d3 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -535,7 +535,7 @@ impl TokenTree { } } -/// Prints token treee in a form convenient for debugging. +/// Prints token tree in a form convenient for debugging. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Debug for TokenTree { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -730,7 +730,7 @@ impl fmt::Debug for Group { /// An `Punct` is an single punctuation character like `+`, `-` or `#`. /// -/// Multicharacter operators like `+=` are represented as two instances of `Punct` with different +/// Multi-character operators like `+=` are represented as two instances of `Punct` with different /// forms of `Spacing` returned. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Clone)] @@ -788,7 +788,7 @@ impl Punct { /// Returns the spacing of this punctuation character, indicating whether it's immediately /// followed by another `Punct` in the token stream, so they can potentially be combined into - /// a multicharacter operator (`Joint`), or it's followed by some other token or whitespace + /// a multi-character operator (`Joint`), or it's followed by some other token or whitespace /// (`Alone`) so the operator has certainly ended. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn spacing(&self) -> Spacing { @@ -947,7 +947,7 @@ macro_rules! suffixed_int_literals { /// This function will create an integer like `1u32` where the integer /// value specified is the first part of the token and the integral is /// also suffixed at the end. - /// Literals created from negative numbers may not survive rountrips through + /// Literals created from negative numbers may not survive round-trips through /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// Literals created through this method have the `Span::call_site()` @@ -1047,7 +1047,7 @@ impl Literal { /// Creates a new suffixed floating-point literal. /// - /// This consturctor will create a literal like `1.0f32` where the value + /// This constructor will create a literal like `1.0f32` where the value /// specified is the preceding part of the token and `f32` is the suffix of /// the token. This token will always be inferred to be an `f32` in the /// compiler. @@ -1096,7 +1096,7 @@ impl Literal { /// Creates a new suffixed floating-point literal. /// - /// This consturctor will create a literal like `1.0f64` where the value + /// This constructor will create a literal like `1.0f64` where the value /// specified is the preceding part of the token and `f64` is the suffix of /// the token. This token will always be inferred to be an `f64` in the /// compiler. diff --git a/src/librustc/dep_graph/cgu_reuse_tracker.rs b/src/librustc/dep_graph/cgu_reuse_tracker.rs index 99fc020bbe44f..0392d32989697 100644 --- a/src/librustc/dep_graph/cgu_reuse_tracker.rs +++ b/src/librustc/dep_graph/cgu_reuse_tracker.rs @@ -9,7 +9,7 @@ // except according to those terms. //! Some facilities for tracking how codegen-units are reused during incremental -//! compilition. This is used for incremental compiliation tests and debug +//! compilation. This is used for incremental compilation tests and debug //! output. use session::Session; diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 5d9d4deb0abc9..e4c434b562ddc 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -36,7 +36,7 @@ pub enum NonMacroAttrKind { Tool, /// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`). DeriveHelper, - /// Single-segment custom attriubte registered by a legacy plugin (`register_attribute`). + /// Single-segment custom attribute registered by a legacy plugin (`register_attribute`). LegacyPluginHelper, /// Single-segment custom attribute not registered in any way (`#[my_attr]`). Custom, diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 61a861a8a1cd8..a787eeae663fd 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -10,7 +10,7 @@ //! This module contains the "canonicalizer" itself. //! -//! For an overview of what canonicaliation is and how it fits into +//! For an overview of what canonicalization is and how it fits into //! rustc, check out the [chapter in the rustc guide][c]. //! //! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index f4607f7a9092f..6f3d10268351a 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -556,7 +556,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { } /// Given two sets of values for the same set of canonical variables, unify them. - /// The second set is produced lazilly by supplying indices from the first set. + /// The second set is produced lazily by supplying indices from the first set. fn unify_canonical_vars( &self, cause: &ObligationCause<'tcx>, diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc/infer/canonical/substitute.rs index b8c1ed236c0ba..0b4d863bf4d1a 100644 --- a/src/librustc/infer/canonical/substitute.rs +++ b/src/librustc/infer/canonical/substitute.rs @@ -11,7 +11,7 @@ //! This module contains code to substitute new values into a //! `Canonical<'tcx, T>`. //! -//! For an overview of what canonicaliation is and how it fits into +//! For an overview of what canonicalization is and how it fits into //! rustc, check out the [chapter in the rustc guide][c]. //! //! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs index 009a823568131..7a92b3084ba9f 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs @@ -20,7 +20,7 @@ use util::common::ErrorReported; use infer::lexical_region_resolve::RegionResolutionError::SubSupConflict; impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { - /// Print the error message for lifetime errors when binding excapes a closure. + /// Print the error message for lifetime errors when binding escapes a closure. /// /// Consider a case where we have /// diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 3e08a4e021aed..877ca0d067be7 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -428,7 +428,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// /// This routine is only intended to be used when the leak-check has /// passed; currently, it's used in the trait matching code to create - /// a set of nested obligations frmo an impl that matches against + /// a set of nested obligations from an impl that matches against /// something higher-ranked. More details can be found in /// `librustc/middle/traits/README.md`. /// diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index f5513acecf9e7..0453615f1646a 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1160,10 +1160,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } /// Takes ownership of the list of variable regions. This implies - /// that all the region constriants have already been taken, and + /// that all the region constraints have already been taken, and /// hence that `resolve_regions_and_report_errors` can never be /// called. This is used only during NLL processing to "hand off" ownership - /// of the set of region vairables into the NLL region context. + /// of the set of region variables into the NLL region context. pub fn take_region_var_origins(&self) -> VarInfos { let (var_infos, data) = self.region_constraints .borrow_mut() @@ -1478,7 +1478,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } /// Clears the selection, evaluation, and projection caches. This is useful when - /// repeatedly attemping to select an Obligation while changing only + /// repeatedly attempting to select an Obligation while changing only /// its ParamEnv, since FulfillmentContext doesn't use 'probe' pub fn clear_caches(&self) { self.selection_cache.clear(); diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 39bf59a7a4ec5..bec19ba9099dc 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -320,7 +320,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// but which have only been unified since `s` started, and /// return the types with which they were unified. So if we had /// a type variable `V0`, then we started the snapshot, then we - /// created a type variable `V1`, unifed `V0` with `T0`, and + /// created a type variable `V1`, unified `V0` with `T0`, and /// unified `V1` with `T1`, this function would return `{T0}`. pub fn types_escaping_snapshot(&mut self, s: &Snapshot<'tcx>) -> Vec> { let mut new_elem_threshold = u32::MAX; diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 732b32cc35d68..cfb9f04c4c6d1 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -189,7 +189,7 @@ impl<'a> LintLevelsBuilder<'a> { /// This function will perform a number of tasks: /// /// * It'll validate all lint-related attributes in `attrs` - /// * It'll mark all lint-related attriutes as used + /// * It'll mark all lint-related attributes as used /// * Lint levels will be updated based on the attributes provided /// * Lint attributes are validated, e.g. a #[forbid] can't be switched to /// #[allow] diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 78aabf86e300d..ee6d970750adf 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -224,7 +224,7 @@ impl Default for ErrorOutputType { // Use tree-based collections to cheaply get a deterministic Hash implementation. // DO NOT switch BTreeMap out for an unsorted container type! That would break -// dependency tracking for commandline arguments. +// dependency tracking for command-line arguments. #[derive(Clone, Hash)] pub struct OutputTypes(BTreeMap>); @@ -273,7 +273,7 @@ impl OutputTypes { // Use tree-based collections to cheaply get a deterministic Hash implementation. // DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That -// would break dependency tracking for commandline arguments. +// would break dependency tracking for command-line arguments. #[derive(Clone, Hash)] pub struct Externs(BTreeMap>>); @@ -339,7 +339,7 @@ macro_rules! top_level_options { ); } -// The top-level commandline options struct +// The top-level command-line options struct // // For each option, one has to specify how it behaves with regard to the // dependency tracking system of incremental compilation. This is done via the @@ -2377,11 +2377,11 @@ impl fmt::Display for CrateType { } } -/// Commandline arguments passed to the compiler have to be incorporated with +/// Command-line arguments passed to the compiler have to be incorporated with /// the dependency tracking system for incremental compilation. This module /// provides some utilities to make this more convenient. /// -/// The values of all commandline arguments that are relevant for dependency +/// The values of all command-line arguments that are relevant for dependency /// tracking are hashed into a single value that determines whether the /// incremental compilation cache can be re-used or not. This hashing is done /// via the DepTrackingHash trait defined below, since the standard Hash @@ -2394,7 +2394,7 @@ impl fmt::Display for CrateType { /// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the /// Hash implementation for DepTrackingHash. It's important though that /// we have an opt-in scheme here, so one is hopefully forced to think about -/// how the hash should be calculated when adding a new commandline argument. +/// how the hash should be calculated when adding a new command-line argument. mod dep_tracking { use lint; use middle::cstore; diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index 62317f074764f..99dc099d57738 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -200,7 +200,7 @@ impl_stable_hash_for!(struct DtorckConstraint<'tcx> { /// trivial for dropck-outlives. /// /// Note also that `needs_drop` requires a "global" type (i.e., one -/// with erased regions), but this funtcion does not. +/// with erased regions), but this function does not. pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { // None of these types have a destructor and hence they do not diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index ffa4380a5d63c..ad1bf63c1d5cf 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -783,7 +783,7 @@ pub fn shift_vars<'a, 'gcx, 'tcx, T>( /// /// Note that what I'm calling an "escaping var" is often just called a "free var". However, /// we already use the term "free var". It refers to the regions or types that we use to represent -/// bound regions or type params on a fn definition while we are typechecking its body. +/// bound regions or type params on a fn definition while we are type checking its body. /// /// To clarify, conceptually there is no particular difference between /// an "escaping" var and a "free" var. However, there is a big @@ -859,7 +859,7 @@ struct LateBoundRegionsCollector { /// If true, we only want regions that are known to be /// "constrained" when you equate this type with another type. In - /// partcular, if you have e.g. `&'a u32` and `&'b u32`, equating + /// particular, if you have e.g. `&'a u32` and `&'b u32`, equating /// them constraints `'a == 'b`. But if you have `<&'a u32 as /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those /// types may mean that `'a` and `'b` don't appear in the results, diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5aeba652f3228..fde208b3faf3f 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1279,7 +1279,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { /// Type size "skeleton", i.e. the only information determining a type's size. /// While this is conservative, (aside from constant sizes, only pointers, /// newtypes thereof and null pointer optimized enums are allowed), it is -/// enough to statically check common usecases of transmute. +/// enough to statically check common use cases of transmute. #[derive(Copy, Clone, Debug)] pub enum SizeSkeleton<'tcx> { /// Any statically computable Layout. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 9a63bb374c66d..a6197150f25f6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2394,7 +2394,7 @@ impl<'a, 'gcx, 'tcx> FieldDef { /// Represents the various closure traits in the Rust language. This /// will determine the type of the environment (`self`, in the -/// desuaring) argument that the closure expects. +/// desugaring) argument that the closure expects. /// /// You can get the environment type of a closure using /// `tcx.closure_env_ty()`. diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 806025937cb11..aedc14cd85c1a 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -941,7 +941,7 @@ pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// /// In the process of working on rust-lang/rust#55238 a mysterious segfault was /// stumbled upon. The segfault was never reproduced locally, but it was -/// suspected to be releated to the fact that codegen worker threads were +/// suspected to be related to the fact that codegen worker threads were /// sticking around by the time the main thread was exiting, causing issues. /// /// This structure is an attempt to fix that issue where the `codegen_aborted` diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index eaa599e0cd0fa..267d7e0d54b63 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -184,7 +184,7 @@ const WASM_WHITELIST: &[(&str, Option<&str>)] = &[ ]; /// When rustdoc is running, provide a list of all known features so that all their respective -/// primtives may be documented. +/// primitives may be documented. /// /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this /// iterator! diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 0d95b0c7bbc0c..f8593363bb16a 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -79,7 +79,7 @@ //! - In order to be able to also use symbols from two versions of the same //! crate (which naturally also have the same name), a stronger measure is //! required: The compiler accepts an arbitrary "disambiguator" value via the -//! `-C metadata` commandline argument. This disambiguator is then fed into +//! `-C metadata` command-line argument. This disambiguator is then fed into //! the symbol hash of every exported item. Consequently, the symbols in two //! identical crates but with different disambiguators are not in conflict //! with each other. This facility is mainly intended to be used by build diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index a989a54010222..64de0c2f565a1 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -38,7 +38,7 @@ struct SccData { /// successors can be found. ranges: IndexVec>, - /// Contains the succcessors for all the Sccs, concatenated. The + /// Contains the successors for all the Sccs, concatenated. The /// range of indices corresponding to a given SCC is found in its /// SccData. all_successors: Vec, diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index 02640a71010e2..27c2f8b718ab8 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -452,7 +452,7 @@ impl OwningRef { /// use owning_ref::{OwningRef, Erased}; /// /// fn main() { - /// // NB: Using the concrete types here for explicitnes. + /// // NB: Using the concrete types here for explicitness. /// // For less verbose code type aliases like `BoxRef` are provided. /// /// let owning_ref_a: OwningRef, [i32; 4]> @@ -722,7 +722,7 @@ impl OwningRefMut { /// use owning_ref::{OwningRefMut, Erased}; /// /// fn main() { - /// // NB: Using the concrete types here for explicitnes. + /// // NB: Using the concrete types here for explicitness. /// // For less verbose code type aliases like `BoxRef` are provided. /// /// let owning_ref_mut_a: OwningRefMut, [i32; 4]> diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index 730b13a0584fc..29d99a6aef3f2 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -15,7 +15,7 @@ use std::mem; use std::ops::{RangeBounds, Bound, Index, IndexMut}; /// `SortedMap` is a data structure with similar characteristics as BTreeMap but -/// slightly different trade-offs: lookup, inseration, and removal are O(log(N)) +/// slightly different trade-offs: lookup, insertion, and removal are O(log(N)) /// and elements can be iterated in order cheaply. /// /// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6c7982242bfad..ec3cb95db88f8 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -643,8 +643,8 @@ impl Compilation { } } -/// A trait for customising the compilation process. Offers a number of hooks for -/// executing custom code or customising input. +/// A trait for customizing the compilation process. Offers a number of hooks for +/// executing custom code or customizing input. pub trait CompilerCalls<'a> { /// Hook for a callback early in the process of handling arguments. This will /// be called straight after options have been parsed but before anything diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 58a799bb45f2d..f76086139ed7e 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -160,7 +160,7 @@ const LABELS_FN_IN_TRAIT: &[&[&str]] = &[ EXTRA_TRAIT, ]; -/// For generic cases like inline-assemply/mod/etc +/// For generic cases like inline-assembly/mod/etc const LABELS_HIR_ONLY: &[&[&str]] = &[ BASE_HIR, ]; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 2a9b58200e5d6..a327efc512bac 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1486,7 +1486,7 @@ declare_lint! { "detects edition keywords being used as an identifier" } -/// Checks for uses of edtion keywords used as an identifier +/// Checks for uses of edition keywords used as an identifier #[derive(Clone)] pub struct KeywordIdents; diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index a057f2f45c010..b318e73e26fa1 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -111,7 +111,7 @@ mod relate_tys; /// - `liveness` -- results of a liveness computation on the MIR; used to create liveness /// constraints for the regions in the types of variables /// - `flow_inits` -- results of a maybe-init dataflow analysis -/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysiss +/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis pub(crate) fn type_check<'gcx, 'tcx>( infcx: &InferCtxt<'_, 'gcx, 'tcx>, param_env: ty::ParamEnv<'gcx>, diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index c0f059619a497..715d6e0c0d1b3 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -262,7 +262,7 @@ struct PlaceComponents<'p, 'tcx: 'p> { impl<'p, 'tcx> PlaceComponents<'p, 'tcx> { /// Converts a list of `Place` components into an iterator; this /// iterator yields up a never-ending stream of `Option<&Place>`. - /// These begin with the "innermst" place and then with each + /// These begin with the "innermost" place and then with each /// projection therefrom. So given a place like `a.b.c` it would /// yield up: /// diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 9e6f32909bdea..1f510a17df220 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -30,7 +30,7 @@ use std::cmp::Ordering; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. /// - /// It is a bug to call this with a simplifyable pattern. + /// It is a bug to call this with a simplifiable pattern. pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { match *match_pair.pattern.kind { PatternKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => { diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 8a24851de8149..d768601a33acd 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -115,7 +115,7 @@ pub enum StmtKind<'tcx> { /// reference to an expression in this enum is an `ExprRef<'tcx>`, which /// may in turn be another instance of this enum (boxed), or else an /// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very -/// shortlived. They are created by `Hair::to_expr`, analyzed and +/// short-lived. They are created by `Hair::to_expr`, analyzed and /// converted into MIR, and then discarded. /// /// If you compare `Expr` to the full compiler AST, you will see it is diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 69ca21c56242f..bf2058dcd27aa 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -55,11 +55,11 @@ /// all the values it covers are already covered by row 2. /// /// To compute `U`, we must have two other concepts. -/// 1. `S(c, P)` is a "specialised matrix", where `c` is a constructor (like `Some` or +/// 1. `S(c, P)` is a "specialized matrix", where `c` is a constructor (like `Some` or /// `None`). You can think of it as filtering `P` to just the rows whose *first* pattern /// can cover `c` (and expanding OR-patterns into distinct patterns), and then expanding /// the constructor into all of its components. -/// The specialisation of a row vector is computed by `specialize`. +/// The specialization of a row vector is computed by `specialize`. /// /// It is computed as follows. For each row `p_i` of P, we have four cases: /// 1.1. `p_(i,1) = c(r_1, .., r_a)`. Then `S(c, P)` has a corresponding row: @@ -1453,7 +1453,7 @@ fn should_treat_range_exhaustively(tcx: TyCtxt<'_, 'tcx, 'tcx>, ctor: &Construct /// mean creating a separate constructor for every single value in the range, which is clearly /// impractical. However, observe that for some ranges of integers, the specialisation will be /// identical across all values in that range (i.e. there are equivalence classes of ranges of -/// constructors based on their `is_useful_specialised` outcome). These classes are grouped by +/// constructors based on their `is_useful_specialized` outcome). These classes are grouped by /// the patterns that apply to them (in the matrix `P`). We can split the range whenever the /// patterns that apply to that range (specifically: the patterns that *intersect* with that range) /// change. diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 84aa5b6756660..8f267af654b07 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -67,7 +67,7 @@ macro_rules! try_validation { }} } -/// We want to show a nice path to the invalid field for diagnotsics, +/// We want to show a nice path to the invalid field for diagnostics, /// but avoid string operations in the happy case where no error happens. /// So we track a `Vec` where `PathElem` contains all the data we /// need to later print something for the user. diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index ca58239df8eac..a90cccfa7a774 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -172,7 +172,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { /// While the `ExprUseVisitor` walks, we will identify which /// expressions are borrowed, and insert their ids into this /// table. Actually, we insert the "borrow-id", which is normally - /// the id of the expession being borrowed: but in the case of + /// the id of the expression being borrowed: but in the case of /// `ref mut` borrows, the `id` of the pattern is /// inserted. Therefore later we remove that entry from the table /// and transfer it over to the value being matched. This will diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 305efd0d75af6..2f9f29adcc1a3 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1437,7 +1437,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// /// 1. Because the numbers of the region variables would otherwise be fairly unique to this /// particular method call, it winds up creating fewer types overall, which helps for memory - /// usage. (Admittedly, this is a rather small effect, though measureable.) + /// usage. (Admittedly, this is a rather small effect, though measurable.) /// /// 2. It makes it easier to deal with higher-ranked trait bounds, because we can replace any /// late-bound regions with 'static. Otherwise, if we were going to replace late-bound diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 7dafe67485a6e..f4d05c6dbd65c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -187,7 +187,7 @@ pub struct RenderOptions { /// Whether to generate a table of contents on the output file when reading a standalone /// Markdown file. pub markdown_no_toc: bool, - /// Additional CSS files to link in pages generated from standlone Markdown files. + /// Additional CSS files to link in pages generated from standalone Markdown files. pub markdown_css: Vec, /// If present, playground URL to use in the "Run" button added to code samples generated from /// standalone Markdown files. If not present, `playground_url` is used. diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 485b2ffe1975e..100ec8535c841 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -85,7 +85,7 @@ pub use alloc_crate::alloc::*; /// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows, /// plus related functions. /// -/// This type implements the `GlobalAlloc` trait and Rust programs by deafult +/// This type implements the `GlobalAlloc` trait and Rust programs by default /// work as if they had this definition: /// /// ```rust diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 8de415e8aed5c..bb2f152edc63d 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1569,7 +1569,7 @@ impl HashMap /// where the key should go, meaning the keys may become "lost" if their /// location does not reflect their state. For instance, if you change a key /// so that the map now contains keys which compare equal, search may start - /// acting eratically, with two keys randomly masking eachother. Implementations + /// acting erratically, with two keys randomly masking each other. Implementations /// are free to assume this doesn't happen (within the limits of memory-safety). #[unstable(feature = "hash_raw_entry", issue = "54043")] pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut { diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 6c95854c66cbf..13cf3133dcd12 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -615,7 +615,7 @@ mod loop_keyword { } // /// The keyword used to define structs. /// -/// Structs in Rust come in three flavours: Structs with named fields, tuple structs, and unit +/// Structs in Rust come in three flavors: Structs with named fields, tuple structs, and unit /// structs. /// /// ```rust diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index d45a66ef66532..e5838b954ed49 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -852,7 +852,7 @@ impl From<[u8; 4]> for IpAddr { impl Ipv6Addr { /// Creates a new IPv6 address from eight 16-bit segments. /// - /// The result will represent the IP address a:b:c:d:e:f:g:h. + /// The result will represent the IP address `a:b:c:d:e:f:g:h`. /// /// # Examples /// diff --git a/src/libstd/process.rs b/src/libstd/process.rs index a9219f75362db..437153b56e49b 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1119,7 +1119,7 @@ impl From for Stdio { /// let file = File::open("foo.txt").unwrap(); /// /// let reverse = Command::new("rev") - /// .stdin(file) // Implicit File convertion into a Stdio + /// .stdin(file) // Implicit File conversion into a Stdio /// .output() /// .expect("failed reverse command"); /// @@ -1337,7 +1337,7 @@ impl Child { /// Attempts to collect the exit status of the child if it has already /// exited. /// - /// This function will not block the calling thread and will only advisorily + /// This function will not block the calling thread and will only /// check to see if the child process has exited or not. If the child has /// exited then on Unix the process id is reaped. This function is /// guaranteed to repeatedly return a successful exit status so long as the diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index d61103a872f9e..d62b09134bbf1 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -26,7 +26,7 @@ impl FileDesc { pub fn raw(&self) -> usize { self.fd } - /// Extracts the actual filedescriptor without closing it. + /// Extracts the actual file descriptor without closing it. pub fn into_raw(self) -> usize { let fd = self.fd; mem::forget(self); diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs index f9a8bd61ac800..246a86c29ece4 100644 --- a/src/libstd/sys/redox/syscall/call.rs +++ b/src/libstd/sys/redox/syscall/call.rs @@ -45,7 +45,7 @@ pub unsafe fn brk(addr: usize) -> Result { /// # Errors /// /// * `EACCES` - permission is denied for one of the components of `path`, or `path` -/// * `EFAULT` - `path` does not point to the process's addressible memory +/// * `EFAULT` - `path` does not point to the process's addressable memory /// * `EIO` - an I/O error occurred /// * `ENOENT` - `path` does not exit /// * `ENOTDIR` - `path` is not a directory @@ -347,7 +347,7 @@ pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result /// /// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block /// * `EBADF` - the file descriptor is not valid or is not open for writing -/// * `EFAULT` - `buf` does not point to the process's addressible memory +/// * `EFAULT` - `buf` does not point to the process's addressable memory /// * `EIO` - an I/O error occurred /// * `ENOSPC` - the device containing the file descriptor has no room for data /// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index af33d2636fb1f..5a81d6dfb672e 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -46,7 +46,7 @@ impl FileDesc { pub fn raw(&self) -> c_int { self.fd } - /// Extracts the actual filedescriptor without closing it. + /// Extracts the actual file descriptor without closing it. pub fn into_raw(self) -> c_int { let fd = self.fd; mem::forget(self); diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index a57b8dc723767..8a845efd41362 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -233,7 +233,7 @@ pub use self::local::{LocalKey, AccessError}; /// /// You may want to use [`spawn`] instead of [`thread::spawn`], when you want /// to recover from a failure to launch a thread, indeed the free function will -/// panick where the `Builder` method will return a [`io::Result`]. +/// panic where the `Builder` method will return a [`io::Result`]. /// /// # Examples /// diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 29bd63d28c5ec..cfdd4340a19fe 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -150,7 +150,7 @@ impl TokenTree { } } - /// Modify the `TokenTree`'s span inplace. + /// Modify the `TokenTree`'s span in-place. pub fn set_span(&mut self, span: Span) { match *self { TokenTree::Token(ref mut sp, _) => *sp = span, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index dd90ef06c3929..2f6b306e8f8ba 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -68,7 +68,7 @@ //! The `i32`s in `B` and `C0` don't have an identifier, so the //! `Option`s would be `None` for them. //! -//! In the static cases, the structure is summarised, either into the just +//! In the static cases, the structure is summarized, either into the just //! spans of the fields or a list of spans and the field idents (for tuple //! structs and record structs, respectively), or a list of these, for //! enums (one for each variant). For empty struct and empty enum From 98f61a3195663465bc2f65287fbcbe14761fe6a8 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 13 Nov 2018 18:03:06 +0100 Subject: [PATCH 41/50] core/benches: Add `char::to_digit()` benchmarks --- src/libcore/benches/char/methods.rs | 42 +++++++++++++++++++++++++++++ src/libcore/benches/char/mod.rs | 11 ++++++++ src/libcore/benches/lib.rs | 1 + 3 files changed, 54 insertions(+) create mode 100644 src/libcore/benches/char/methods.rs create mode 100644 src/libcore/benches/char/mod.rs diff --git a/src/libcore/benches/char/methods.rs b/src/libcore/benches/char/methods.rs new file mode 100644 index 0000000000000..faf820d871cfa --- /dev/null +++ b/src/libcore/benches/char/methods.rs @@ -0,0 +1,42 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use test::Bencher; + +const CHARS: [char; 9] = ['0', 'x', '2', '5', 'A', 'f', '7', '8', '9']; +const RADIX: [u32; 5] = [2, 8, 10, 16, 32]; + +#[bench] +fn bench_to_digit_radix_2(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(2)).min()) +} + +#[bench] +fn bench_to_digit_radix_10(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(10)).min()) +} + +#[bench] +fn bench_to_digit_radix_16(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(16)).min()) +} + +#[bench] +fn bench_to_digit_radix_36(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(36)).min()) +} + +#[bench] +fn bench_to_digit_radix_var(b: &mut Bencher) { + b.iter(|| CHARS.iter().cycle() + .zip(RADIX.iter().cycle()) + .take(10_000) + .map(|(c, radix)| c.to_digit(*radix)).min()) +} diff --git a/src/libcore/benches/char/mod.rs b/src/libcore/benches/char/mod.rs new file mode 100644 index 0000000000000..a656e82cb61e6 --- /dev/null +++ b/src/libcore/benches/char/mod.rs @@ -0,0 +1,11 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod methods; diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index ced77d779182a..d44f1577d56b0 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -15,6 +15,7 @@ extern crate core; extern crate test; mod any; +mod char; mod hash; mod iter; mod num; From 04aade83f2785d6ca43049ff89026ed930f792f1 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 13 Nov 2018 17:49:38 +0100 Subject: [PATCH 42/50] core/char: Replace condition + `panic!()` with `assert!()` --- src/libcore/char/methods.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 35181afea3da6..fc212aa4f2086 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -121,9 +121,7 @@ impl char { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn to_digit(self, radix: u32) -> Option { - if radix > 36 { - panic!("to_digit: radix is too high (maximum 36)"); - } + assert!(radix <= 36, "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, From 17f08fecfd81479e04fc5ea7590cecdb429c7ce3 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 13 Nov 2018 18:05:46 +0100 Subject: [PATCH 43/50] core/char: Speed up `to_digit()` for `radix <= 10` ### Before ``` # Run 1 test char::methods::bench_to_digit_radix_10 ... bench: 16,265 ns/iter (+/- 1,774) test char::methods::bench_to_digit_radix_16 ... bench: 13,938 ns/iter (+/- 2,479) test char::methods::bench_to_digit_radix_2 ... bench: 13,090 ns/iter (+/- 524) test char::methods::bench_to_digit_radix_36 ... bench: 14,236 ns/iter (+/- 1,949) # Run 2 test char::methods::bench_to_digit_radix_10 ... bench: 16,176 ns/iter (+/- 1,589) test char::methods::bench_to_digit_radix_16 ... bench: 13,896 ns/iter (+/- 3,140) test char::methods::bench_to_digit_radix_2 ... bench: 13,158 ns/iter (+/- 1,112) test char::methods::bench_to_digit_radix_36 ... bench: 14,206 ns/iter (+/- 1,312) # Run 3 test char::methods::bench_to_digit_radix_10 ... bench: 16,221 ns/iter (+/- 2,423) test char::methods::bench_to_digit_radix_16 ... bench: 14,361 ns/iter (+/- 3,926) test char::methods::bench_to_digit_radix_2 ... bench: 13,097 ns/iter (+/- 671) test char::methods::bench_to_digit_radix_36 ... bench: 14,388 ns/iter (+/- 1,068) ``` ### After ``` # Run 1 test char::methods::bench_to_digit_radix_10 ... bench: 11,521 ns/iter (+/- 552) test char::methods::bench_to_digit_radix_16 ... bench: 12,926 ns/iter (+/- 684) test char::methods::bench_to_digit_radix_2 ... bench: 11,266 ns/iter (+/- 1,085) test char::methods::bench_to_digit_radix_36 ... bench: 14,213 ns/iter (+/- 614) # Run 2 test char::methods::bench_to_digit_radix_10 ... bench: 11,424 ns/iter (+/- 1,042) test char::methods::bench_to_digit_radix_16 ... bench: 12,854 ns/iter (+/- 1,193) test char::methods::bench_to_digit_radix_2 ... bench: 11,193 ns/iter (+/- 716) test char::methods::bench_to_digit_radix_36 ... bench: 14,249 ns/iter (+/- 3,514) # Run 3 test char::methods::bench_to_digit_radix_10 ... bench: 11,469 ns/iter (+/- 685) test char::methods::bench_to_digit_radix_16 ... bench: 12,852 ns/iter (+/- 568) test char::methods::bench_to_digit_radix_2 ... bench: 11,275 ns/iter (+/- 1,356) test char::methods::bench_to_digit_radix_36 ... bench: 14,188 ns/iter (+/- 1,501) ``` --- src/libcore/char/methods.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index fc212aa4f2086..46b201f7bbf2c 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -122,12 +122,27 @@ impl char { #[inline] pub fn to_digit(self, radix: u32) -> Option { assert!(radix <= 36, "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 radix == 10 { + return match self { + '0' ..= '9' => Some(self as u32 - '0' as u32), + _ => None, + }; + } + + let val = if radix < 10 { + match self { + '0' ..= '9' => self as u32 - '0' as u32, + _ => return None, + } + } else { + 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 } } From 98dab3335f8355f8a313d09e0dfe0b8ef9412b35 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 8 Nov 2018 17:14:13 +1100 Subject: [PATCH 44/50] Wrap some query results in `Lrc`. So that the frequent clones in `try_get` are cheaper. Fixes #54274. --- src/librustc/infer/outlives/verify.rs | 4 +- src/librustc/traits/object_safety.rs | 5 +- src/librustc/traits/specialize/mod.rs | 2 +- src/librustc/ty/mod.rs | 6 +-- src/librustc/ty/query/mod.rs | 11 ++-- src/librustc_metadata/cstore_impl.rs | 6 +-- src/librustc_traits/lowering/mod.rs | 12 +++-- src/librustc_typeck/astconv.rs | 7 +-- src/librustc_typeck/check/mod.rs | 6 +-- src/librustc_typeck/check/wfcheck.rs | 4 +- src/librustc_typeck/collect.rs | 67 ++++++++++++------------ src/librustc_typeck/outlives/explicit.rs | 6 +-- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/simplify.rs | 4 +- 14 files changed, 73 insertions(+), 69 deletions(-) diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs index a7a79dd2e6560..5fee04341b676 100644 --- a/src/librustc/infer/outlives/verify.rs +++ b/src/librustc/infer/outlives/verify.rs @@ -299,8 +299,8 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> { let assoc_item = tcx.associated_item(assoc_item_def_id); let trait_def_id = assoc_item.container.assert_trait(); let trait_predicates = tcx.predicates_of(trait_def_id).predicates - .into_iter() - .map(|(p, _)| p) + .iter() + .map(|(p, _)| *p) .collect(); let identity_substs = Substs::identity_for_item(tcx, assoc_item_def_id); let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs); diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 1d76ccdca3161..715ce0d7e805b 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { }; predicates .predicates - .into_iter() + .iter() .map(|(predicate, _)| predicate.subst_supertrait(self, &trait_ref)) .any(|predicate| { match predicate { @@ -302,9 +302,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return Some(MethodViolationCode::Generic); } - if self.predicates_of(method.def_id).predicates.into_iter() + if self.predicates_of(method.def_id).predicates.iter() // A trait object can't claim to live more than the concrete type, // so outlives predicates will always hold. + .cloned() .filter(|(p, _)| p.to_opt_type_outlives().is_none()) .collect::>() // Do a shallow visit so that `contains_illegal_self_type_reference` diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index d7b5dd049e350..d3dc1655b0df2 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -407,7 +407,7 @@ fn to_pretty_impl_header(tcx: TyCtxt<'_, '_, '_>, impl_def_id: DefId) -> Option< // The predicates will contain default bounds like `T: Sized`. We need to // remove these bounds, and add `T: ?Sized` to any untouched type parameters. - let predicates = tcx.predicates_of(impl_def_id).predicates; + let predicates = &tcx.predicates_of(impl_def_id).predicates; let mut pretty_predicates = Vec::with_capacity( predicates.len() + types_without_default_bounds.len()); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 83feadd50d77f..4472f23b2c4f9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2126,7 +2126,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } #[inline] - pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> GenericPredicates<'gcx> { + pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Lrc> { tcx.predicates_of(self.did) } @@ -2369,8 +2369,8 @@ impl<'a, 'gcx, 'tcx> AdtDef { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]) }).to_predicate(); - let predicates = tcx.predicates_of(self.did).predicates; - if predicates.into_iter().any(|(p, _)| p == sized_predicate) { + let predicates = &tcx.predicates_of(self.did).predicates; + if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index c834166e67d88..0052628e12aca 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -127,17 +127,18 @@ define_queries! { <'tcx> /// predicate gets in the way of some checks, which are intended /// to operate over only the actual where-clauses written by the /// user.) - [] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + [] fn predicates_of: PredicatesOfItem(DefId) -> Lrc>, /// Maps from the def-id of an item (trait/struct/enum/fn) to the /// predicates (where clauses) directly defined on it. This is /// equal to the `explicit_predicates_of` predicates plus the /// `inferred_outlives_of` predicates. - [] fn predicates_defined_on: PredicatesDefinedOnItem(DefId) -> ty::GenericPredicates<'tcx>, + [] fn predicates_defined_on: PredicatesDefinedOnItem(DefId) + -> Lrc>, /// Returns the predicates written explicit by the user. [] fn explicit_predicates_of: ExplicitPredicatesOfItem(DefId) - -> ty::GenericPredicates<'tcx>, + -> Lrc>, /// Returns the inferred outlives predicates (e.g., for `struct /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). @@ -149,12 +150,12 @@ define_queries! { <'tcx> /// evaluate them even during type conversion, often before the /// full predicates are available (note that supertraits have /// additional acyclicity requirements). - [] fn super_predicates_of: SuperPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + [] fn super_predicates_of: SuperPredicatesOfItem(DefId) -> Lrc>, /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. [] fn type_param_predicates: type_param_predicates((DefId, DefId)) - -> ty::GenericPredicates<'tcx>, + -> Lrc>, [] fn trait_def: TraitDefOfItem(DefId) -> &'tcx ty::TraitDef, [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index e6e1367b592df..e1d9ca5339e6a 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -103,9 +103,9 @@ provide! { <'tcx> tcx, def_id, other, cdata, generics_of => { tcx.alloc_generics(cdata.get_generics(def_id.index, tcx.sess)) } - predicates_of => { cdata.get_predicates(def_id.index, tcx) } - predicates_defined_on => { cdata.get_predicates_defined_on(def_id.index, tcx) } - super_predicates_of => { cdata.get_super_predicates(def_id.index, tcx) } + predicates_of => { Lrc::new(cdata.get_predicates(def_id.index, tcx)) } + predicates_defined_on => { Lrc::new(cdata.get_predicates_defined_on(def_id.index, tcx)) } + super_predicates_of => { Lrc::new(cdata.get_super_predicates(def_id.index, tcx)) } trait_def => { tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx.sess)) } diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 471c0e7abbca6..dc47b15a68f19 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -217,8 +217,9 @@ fn program_clauses_for_trait<'a, 'tcx>( let implemented_from_env = Clause::ForAll(ty::Binder::bind(implemented_from_env)); - let where_clauses = &tcx.predicates_defined_on(def_id).predicates - .into_iter() + let predicates = &tcx.predicates_defined_on(def_id).predicates; + let where_clauses = &predicates + .iter() .map(|(wc, _)| wc.lower()) .map(|wc| wc.subst(tcx, bound_vars)) .collect::>(); @@ -314,8 +315,9 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId let trait_pred = ty::TraitPredicate { trait_ref }.lower(); // `WC` - let where_clauses = tcx.predicates_of(def_id).predicates - .into_iter() + let predicates = &tcx.predicates_of(def_id).predicates; + let where_clauses = predicates + .iter() .map(|(wc, _)| wc.lower()) .map(|wc| wc.subst(tcx, bound_vars)); @@ -352,7 +354,7 @@ pub fn program_clauses_for_type_def<'a, 'tcx>( // `WC` let where_clauses = tcx.predicates_of(def_id).predicates - .into_iter() + .iter() .map(|(wc, _)| wc.lower()) .map(|wc| wc.subst(tcx, bound_vars)) .collect::>(); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 572e79407a10b..d388d75643888 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -24,6 +24,7 @@ use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::{GenericParamDef, GenericParamDefKind}; use rustc::ty::wf::object_region_bounds; +use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi; use std::collections::BTreeSet; use std::slice; @@ -45,7 +46,7 @@ pub trait AstConv<'gcx, 'tcx> { /// Returns the set of bounds in scope for the type parameter with /// the given id. fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) - -> ty::GenericPredicates<'tcx>; + -> Lrc>; /// What lifetime should we use when a lifetime is omitted (and not elided)? fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>) @@ -1119,8 +1120,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { { let tcx = self.tcx(); - let bounds = self.get_type_parameter_bounds(span, ty_param_def_id) - .predicates.into_iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref()); + let predicates = &self.get_type_parameter_bounds(span, ty_param_def_id).predicates; + let bounds = predicates.iter().filter_map(|(p, _)| p.to_opt_poly_trait_ref()); // Check that there is exactly one way to find an associated type with the // correct name. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 41e0c6c0a1972..c936e0833c01f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1869,7 +1869,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) - -> ty::GenericPredicates<'tcx> + -> Lrc> { let tcx = self.tcx; let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); @@ -1877,7 +1877,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { let item_def_id = tcx.hir.local_def_id(item_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; - ty::GenericPredicates { + Lrc::new(ty::GenericPredicates { parent: None, predicates: self.param_env.caller_bounds.iter().filter_map(|&predicate| { match predicate { @@ -1890,7 +1890,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { _ => None } }).collect() - } + }) } fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 8574443190d7c..b5addbd18d2a4 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -910,8 +910,8 @@ fn check_false_global_bounds<'a, 'gcx, 'tcx>( let def_id = fcx.tcx.hir.local_def_id(id); let predicates = fcx.tcx.predicates_of(def_id).predicates - .into_iter() - .map(|(p, _)| p) + .iter() + .map(|(p, _)| *p) .collect(); // Check elaborated bounds let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d2dc226aca250..6ef09d96fd153 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -39,6 +39,7 @@ use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; use rustc::ty::{ReprOptions, ToPredicate}; use rustc::util::captures::Captures; use rustc::util::nodemap::FxHashMap; +use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi; use syntax::ast; @@ -178,7 +179,8 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { self.tcx } - fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) + -> Lrc> { self.tcx .at(span) .type_param_predicates((self.item_def_id, def_id)) @@ -243,7 +245,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { fn type_param_predicates<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, (item_def_id, def_id): (DefId, DefId), -) -> ty::GenericPredicates<'tcx> { +) -> Lrc> { use rustc::hir::*; // In the AST, bounds can derive from two places. Either @@ -264,11 +266,11 @@ fn type_param_predicates<'a, 'tcx>( tcx.generics_of(item_def_id).parent }; - let mut result = parent.map_or( - ty::GenericPredicates { + let mut result = parent.map_or_else( + || Lrc::new(ty::GenericPredicates { parent: None, predicates: vec![], - }, + }), |parent| { let icx = ItemCtxt::new(tcx, parent); icx.get_type_parameter_bounds(DUMMY_SP, def_id) @@ -298,7 +300,7 @@ fn type_param_predicates<'a, 'tcx>( // Implied `Self: Trait` and supertrait bounds. if param_id == item_node_id { let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id); - result + Lrc::make_mut(&mut result) .predicates .push((identity_trait_ref.to_predicate(), item.span)); } @@ -317,7 +319,7 @@ fn type_param_predicates<'a, 'tcx>( }; let icx = ItemCtxt::new(tcx, item_def_id); - result + Lrc::make_mut(&mut result) .predicates .extend(icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))); @@ -685,7 +687,7 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad fn super_predicates_of<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId, -) -> ty::GenericPredicates<'tcx> { +) -> Lrc> { debug!("super_predicates(trait_def_id={:?})", trait_def_id); let trait_node_id = tcx.hir.as_local_node_id(trait_def_id).unwrap(); @@ -729,10 +731,10 @@ fn super_predicates_of<'a, 'tcx>( } } - ty::GenericPredicates { + Lrc::new(ty::GenericPredicates { parent: None, predicates: superbounds, - } + }) } fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::TraitDef { @@ -1605,27 +1607,23 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx>( fn predicates_defined_on<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, -) -> ty::GenericPredicates<'tcx> { - let explicit = tcx.explicit_predicates_of(def_id); - let span = tcx.def_span(def_id); - let predicates = explicit.predicates.into_iter().chain( - tcx.inferred_outlives_of(def_id).iter().map(|&p| (p, span)) - ).collect(); - - ty::GenericPredicates { - parent: explicit.parent, - predicates: predicates, +) -> Lrc> { + let mut result = tcx.explicit_predicates_of(def_id); + let inferred_outlives = tcx.inferred_outlives_of(def_id); + if !inferred_outlives.is_empty() { + let span = tcx.def_span(def_id); + Lrc::make_mut(&mut result) + .predicates + .extend(inferred_outlives.iter().map(|&p| (p, span))); } + result } fn predicates_of<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, -) -> ty::GenericPredicates<'tcx> { - let ty::GenericPredicates { - parent, - mut predicates, - } = tcx.predicates_defined_on(def_id); +) -> Lrc> { + let mut result = tcx.predicates_defined_on(def_id); if tcx.is_trait(def_id) { // For traits, add `Self: Trait` predicate. This is @@ -1641,16 +1639,17 @@ fn predicates_of<'a, 'tcx>( // used, and adding the predicate into this list ensures // that this is done. let span = tcx.def_span(def_id); - predicates.push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span)); + Lrc::make_mut(&mut result) + .predicates + .push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span)); } - - ty::GenericPredicates { parent, predicates } + result } fn explicit_predicates_of<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, -) -> ty::GenericPredicates<'tcx> { +) -> Lrc> { use rustc::hir::*; use rustc_data_structures::fx::FxHashSet; @@ -1761,10 +1760,10 @@ fn explicit_predicates_of<'a, 'tcx>( if impl_trait_fn.is_some() { // impl Trait - return ty::GenericPredicates { + return Lrc::new(ty::GenericPredicates { parent: None, predicates: bounds.predicates(tcx, opaque_ty), - }; + }); } else { // named existential types predicates.extend(bounds.predicates(tcx, opaque_ty)); @@ -1794,7 +1793,7 @@ fn explicit_predicates_of<'a, 'tcx>( // on a trait we need to add in the supertrait bounds and bounds found on // associated types. if let Some((_trait_ref, _)) = is_trait { - predicates.extend(tcx.super_predicates_of(def_id).predicates); + predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned()); } // In default impls, we can assume that the self type implements @@ -1971,10 +1970,10 @@ fn explicit_predicates_of<'a, 'tcx>( ); } - ty::GenericPredicates { + Lrc::new(ty::GenericPredicates { parent: generics.parent, predicates, - } + }) } pub enum SizedByDefault { diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 75f8b78b9ecf3..9b374cf932fa9 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -33,14 +33,14 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { ) -> &RequiredPredicates<'tcx> { self.map.entry(def_id).or_insert_with(|| { let predicates = if def_id.is_local() { - tcx.explicit_predicates_of(def_id).predicates + tcx.explicit_predicates_of(def_id) } else { - tcx.predicates_of(def_id).predicates + tcx.predicates_of(def_id) }; let mut required_predicates = RequiredPredicates::default(); // process predicates and convert to `RequiredPredicates` entry, see below - for (pred, _) in predicates.into_iter() { + for (pred, _) in predicates.predicates.iter() { match pred { ty::Predicate::TypeOutlives(predicate) => { let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 77782c19b7252..924c86ba56f94 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1563,7 +1563,7 @@ impl Clean for hir::Generics { } impl<'a, 'tcx> Clean for (&'a ty::Generics, - &'a ty::GenericPredicates<'tcx>) { + &'a Lrc>) { fn clean(&self, cx: &DocContext) -> Generics { use self::WherePredicate as WP; diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index eda522af92245..635608d140db4 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -156,8 +156,8 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, if child == trait_ { return true } - let predicates = cx.tcx.super_predicates_of(child).predicates; - predicates.iter().filter_map(|(pred, _)| { + let predicates = cx.tcx.super_predicates_of(child); + predicates.predicates.iter().filter_map(|(pred, _)| { if let ty::Predicate::Trait(ref pred) = *pred { if pred.skip_binder().trait_ref.self_ty().is_self() { Some(pred.def_id()) From 15e7df8b519d9420ada60822ae55c202b013f6a6 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 13 Nov 2018 21:34:44 -0500 Subject: [PATCH 45/50] Remove unneeded newline. --- src/libcore/intrinsics.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fe2afc59be8f1..99a7beb58f5e4 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -675,7 +675,6 @@ extern "rust-intrinsic" { /// /// The stabilized version of this intrinsic is /// [`std::mem::size_of`](../../std/mem/fn.size_of.html). - pub fn size_of() -> usize; /// Moves a value to an uninitialized memory location. From 818257e70233fbafdb382b940893c9c1d615da22 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Nov 2018 08:59:32 +1100 Subject: [PATCH 46/50] Use `Mmap` to open the rmeta file. Because those files are quite large, contribute significantly to peak memory usage, but only a small fraction of the data is ever read. --- src/Cargo.lock | 2 ++ src/librustc_metadata/Cargo.toml | 4 +++- src/librustc_metadata/lib.rs | 2 ++ src/librustc_metadata/locator.rs | 26 +++++++++++++++++++++++--- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 0c08e35c18df3..64e18899c9d05 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -2278,12 +2278,14 @@ version = "0.0.0" dependencies = [ "flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", "serialize 0.0.0", + "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_ext 0.0.0", "syntax_pos 0.0.0", diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 338824d5efe4c..276e2a911e697 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -11,12 +11,14 @@ crate-type = ["dylib"] [dependencies] flate2 = "1.0" log = "0.4" +memmap = "0.6" proc_macro = { path = "../libproc_macro" } rustc = { path = "../librustc" } -rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } +rustc_target = { path = "../librustc_target" } serialize = { path = "../libserialize" } +stable_deref_trait = "1.0.0" syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 0cc0707a3a51f..0322c888ad5c9 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -30,6 +30,8 @@ extern crate libc; #[macro_use] extern crate log; +extern crate memmap; +extern crate stable_deref_trait; #[macro_use] extern crate syntax; extern crate syntax_pos; diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index a732446d50481..528c96f240dba 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -243,12 +243,14 @@ use std::cmp; use std::fmt; use std::fs; use std::io::{self, Read}; +use std::ops::Deref; use std::path::{Path, PathBuf}; use std::time::Instant; use flate2::read::DeflateDecoder; use rustc_data_structures::owning_ref::OwningRef; + pub struct CrateMismatch { path: PathBuf, got: String, @@ -856,6 +858,19 @@ fn get_metadata_section(target: &Target, return ret; } +/// A trivial wrapper for `Mmap` that implements `StableDeref`. +struct StableDerefMmap(memmap::Mmap); + +impl Deref for StableDerefMmap { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + self.0.deref() + } +} + +unsafe impl stable_deref_trait::StableDeref for StableDerefMmap {} + fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Path, @@ -892,9 +907,14 @@ fn get_metadata_section_imp(target: &Target, } } CrateFlavor::Rmeta => { - let buf = fs::read(filename).map_err(|_| - format!("failed to read rmeta metadata: '{}'", filename.display()))?; - rustc_erase_owner!(OwningRef::new(buf).map_owner_box()) + // mmap the file, because only a small fraction of it is read. + let file = std::fs::File::open(filename).map_err(|_| + format!("failed to open rmeta metadata: '{}'", filename.display()))?; + let mmap = unsafe { memmap::Mmap::map(&file) }; + let mmap = mmap.map_err(|_| + format!("failed to mmap rmeta metadata: '{}'", filename.display()))?; + + rustc_erase_owner!(OwningRef::new(StableDerefMmap(mmap)).map_owner_box()) } }; let blob = MetadataBlob(raw_bytes); From 64a517265297cc1d4e9e116dcbb06561c063c3d4 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 14 Nov 2018 08:55:53 +0100 Subject: [PATCH 47/50] core/char: Drop `radix == 10` special case This seems to perform equally well --- src/libcore/char/methods.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 46b201f7bbf2c..4207b3c776c7e 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -122,14 +122,7 @@ impl char { #[inline] pub fn to_digit(self, radix: u32) -> Option { assert!(radix <= 36, "to_digit: radix is too high (maximum 36)"); - if radix == 10 { - return match self { - '0' ..= '9' => Some(self as u32 - '0' as u32), - _ => None, - }; - } - - let val = if radix < 10 { + let val = if radix <= 10 { match self { '0' ..= '9' => self as u32 - '0' as u32, _ => return None, From 7843e2792dce0f20d23b3c1cca51652013bef0ea Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 14 Nov 2018 11:26:00 +0100 Subject: [PATCH 48/50] core/char: Add comment to `to_digit()` --- src/libcore/char/methods.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 4207b3c776c7e..d6fcff644acf6 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -122,6 +122,9 @@ impl char { #[inline] pub fn to_digit(self, radix: u32) -> Option { assert!(radix <= 36, "to_digit: radix is too high (maximum 36)"); + + // the code is split up here to improve execution speed for cases where + // the `radix` is constant and 10 or smaller let val = if radix <= 10 { match self { '0' ..= '9' => self as u32 - '0' as u32, From 055e7b7258cafb9b14f53b9d20c3960c1dbcc9b4 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Wed, 14 Nov 2018 12:41:39 -0500 Subject: [PATCH 49/50] add test for issue #55587 --- src/test/ui/issues/issue-55587.rs | 5 +++++ src/test/ui/issues/issue-55587.stderr | 9 +++++++++ 2 files changed, 14 insertions(+) create mode 100644 src/test/ui/issues/issue-55587.rs create mode 100644 src/test/ui/issues/issue-55587.stderr diff --git a/src/test/ui/issues/issue-55587.rs b/src/test/ui/issues/issue-55587.rs new file mode 100644 index 0000000000000..8b78749f6529a --- /dev/null +++ b/src/test/ui/issues/issue-55587.rs @@ -0,0 +1,5 @@ +use std::path::Path; + +fn main() { + let Path::new(); //~ ERROR expected tuple struct/variant +} diff --git a/src/test/ui/issues/issue-55587.stderr b/src/test/ui/issues/issue-55587.stderr new file mode 100644 index 0000000000000..876fb4391b1bc --- /dev/null +++ b/src/test/ui/issues/issue-55587.stderr @@ -0,0 +1,9 @@ +error[E0164]: expected tuple struct/variant, found method `::new` + --> $DIR/issue-55587.rs:4:9 + | +LL | let Path::new(); //~ ERROR expected tuple struct/variant + | ^^^^^^^^^^^ not a tuple variant or struct + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0164`. From e2ef0f742cd6ff1cabea0cef8999d6615a815eeb Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Wed, 14 Nov 2018 12:54:32 -0500 Subject: [PATCH 50/50] add test for issue #54348 --- src/test/ui/issues/issue-54348.rs | 5 +++++ src/test/ui/issues/issue-54348.stderr | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/test/ui/issues/issue-54348.rs create mode 100644 src/test/ui/issues/issue-54348.stderr diff --git a/src/test/ui/issues/issue-54348.rs b/src/test/ui/issues/issue-54348.rs new file mode 100644 index 0000000000000..b980290391d3a --- /dev/null +++ b/src/test/ui/issues/issue-54348.rs @@ -0,0 +1,5 @@ +fn main() { + [1][0u64 as usize]; + [1][1.5 as usize]; // ERROR index out of bounds + [1][1u64 as usize]; // ERROR index out of bounds +} diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr new file mode 100644 index 0000000000000..a9f1b4942584d --- /dev/null +++ b/src/test/ui/issues/issue-54348.stderr @@ -0,0 +1,16 @@ +error: index out of bounds: the len is 1 but the index is 1 + --> $DIR/issue-54348.rs:3:5 + | +LL | [1][1.5 as usize]; // ERROR index out of bounds + | ^^^^^^^^^^^^^^^^^ + | + = note: #[deny(const_err)] on by default + +error: index out of bounds: the len is 1 but the index is 1 + --> $DIR/issue-54348.rs:4:5 + | +LL | [1][1u64 as usize]; // ERROR index out of bounds + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +