From 897d278160630a2f84e96d6f468284e0fd7dab95 Mon Sep 17 00:00:00 2001 From: Hsiang-Cheng Yang Date: Tue, 10 Sep 2019 15:35:38 +0800 Subject: [PATCH 1/7] libstd: Fix typos in doc --- src/libstd/path.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index fd6ff1032bb81..966aaec4f0c46 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1627,7 +1627,7 @@ impl<'a> From> for PathBuf { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Arc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `PathBuf` into an `Arc` by moving the `PathBuf` data into a new `Arc` buffer. #[inline] fn from(s: PathBuf) -> Arc { let arc: Arc = Arc::from(s.into_os_string()); @@ -1637,7 +1637,7 @@ impl From for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&Path> for Arc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `Path` into an `Arc` by copying the `Path` data into a new `Arc` buffer. #[inline] fn from(s: &Path) -> Arc { let arc: Arc = Arc::from(s.as_os_str()); @@ -1647,7 +1647,7 @@ impl From<&Path> for Arc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From for Rc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `PathBuf` into an `Rc` by moving the `PathBuf` data into a new `Rc` buffer. #[inline] fn from(s: PathBuf) -> Rc { let rc: Rc = Rc::from(s.into_os_string()); @@ -1657,7 +1657,7 @@ impl From for Rc { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&Path> for Rc { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `Path` into an `Rc` by copying the `Path` data into a new `Rc` buffer. #[inline] fn from(s: &Path) -> Rc { let rc: Rc = Rc::from(s.as_os_str()); From 309b9563d4fd9c30ffa9f4431b6f7d0ed55758e2 Mon Sep 17 00:00:00 2001 From: oxalica Date: Fri, 4 Oct 2019 16:17:23 +0800 Subject: [PATCH 2/7] Prefer statx on linux if available --- src/libstd/fs.rs | 13 +++ src/libstd/sys/unix/fs.rs | 171 +++++++++++++++++++++++++++++++++++++- 2 files changed, 182 insertions(+), 2 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 8933f027a065f..cfcf564ad6a1f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -3441,5 +3441,18 @@ mod tests { check!(a.created()); check!(b.created()); } + + if cfg!(target_os = "linux") { + // Not always available + match (a.created(), b.created()) { + (Ok(t1), Ok(t2)) => assert!(t1 <= t2), + (Err(e1), Err(e2)) if e1.kind() == ErrorKind::Other && + e2.kind() == ErrorKind::Other => {} + (a, b) => panic!( + "creation time must be always supported or not supported: {:?} {:?}", + a, b, + ), + } + } } } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 3b1eb86b84fe1..1d43844e8359d 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -20,6 +20,10 @@ use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, re use libc::fstatat64; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] use libc::dirfd; +// We only use struct `statx`, not the function `statx`. +// Instead, use `syscall` to check if it is available at runtime. +#[cfg(target_os = "linux")] +use libc::{statx, makedev}; #[cfg(target_os = "android")] use libc::{stat as stat64, fstat as fstat64, fstatat as fstatat64, lstat as lstat64, lseek64, dirent as dirent64, open as open64}; @@ -44,6 +48,82 @@ pub struct File(FileDesc); #[derive(Clone)] pub struct FileAttr { stat: stat64, + #[cfg(target_os = "linux")] + statx_extra_fields: Option, +} + +#[derive(Clone)] +struct StatxExtraFields { + // This is needed to check if btime is supported by the filesystem. + stx_mask: u32, + stx_btime: libc::statx_timestamp, +} + +// We prefer `statx` if available, which contains file creation time. +#[cfg(target_os = "linux")] +unsafe fn try_statx( + fd: c_int, + path: *const libc::c_char, + flags: i32, + mask: u32, +) -> Option> { + use crate::sync::atomic::{AtomicBool, Ordering}; + + // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` + // We store the availability in a global to avoid unnecessary syscalls + static HAS_STATX: AtomicBool = AtomicBool::new(true); + syscall! { + fn statx( + fd: c_int, + pathname: *const libc::c_char, + flags: c_int, + mask: libc::c_uint, + statxbuf: *mut statx + ) -> c_int + } + + if !HAS_STATX.load(Ordering::Relaxed) { + return None; + } + + let mut buf: statx = mem::zeroed(); + let ret = cvt(statx(fd, path, flags, mask, &mut buf)); + match ret { + Err(err) => match err.raw_os_error() { + Some(libc::ENOSYS) => { + HAS_STATX.store(false, Ordering::Relaxed); + return None; + } + _ => return Some(Err(err)), + } + Ok(_) => { + // We cannot fill `stat64` exhaustively because of private padding fields. + let mut stat: stat64 = mem::zeroed(); + stat.st_dev = makedev(buf.stx_dev_major, buf.stx_dev_minor); + stat.st_ino = buf.stx_ino; + stat.st_nlink = buf.stx_nlink as u64; + stat.st_mode = buf.stx_mode as u32; + stat.st_uid = buf.stx_uid; + stat.st_gid = buf.stx_gid; + stat.st_rdev = makedev(buf.stx_rdev_major, buf.stx_rdev_minor); + stat.st_size = buf.stx_size as i64; + stat.st_blksize = buf.stx_blksize as i64; + stat.st_blocks = buf.stx_blocks as i64; + stat.st_atime = buf.stx_atime.tv_sec; + stat.st_atime_nsec = buf.stx_atime.tv_nsec as i64; + stat.st_mtime = buf.stx_mtime.tv_sec; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as i64; + stat.st_ctime = buf.stx_ctime.tv_sec; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as i64; + + let extra = StatxExtraFields { + stx_mask: buf.stx_mask, + stx_btime: buf.stx_btime, + }; + + Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) + } + } } // all DirEntry's will have a reference to this struct @@ -148,6 +228,26 @@ impl FileAttr { })) } + #[cfg(target_os = "linux")] + pub fn created(&self) -> io::Result { + match &self.statx_extra_fields { + Some(ext) if (ext.stx_mask & libc::STATX_BTIME) != 0 => { + Ok(SystemTime::from(libc::timespec { + tv_sec: ext.stx_btime.tv_sec as libc::time_t, + tv_nsec: ext.stx_btime.tv_nsec as libc::c_long, + })) + } + Some(_) => Err(io::Error::new( + io::ErrorKind::Other, + "creation time is not available for the filesystam", + )), + None => Err(io::Error::new( + io::ErrorKind::Other, + "creation time is not available on this platform currently", + )), + } + } + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "macos", @@ -159,7 +259,8 @@ impl FileAttr { })) } - #[cfg(not(any(target_os = "freebsd", + #[cfg(not(any(target_os = "linux", + target_os = "freebsd", target_os = "openbsd", target_os = "macos", target_os = "ios")))] @@ -304,7 +405,23 @@ impl DirEntry { OsStr::from_bytes(self.name_bytes()).to_os_string() } - #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] + #[cfg(target_os = "linux")] + pub fn metadata(&self) -> io::Result { + let dir_fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?; + let pathname = self.entry.d_name.as_ptr(); + unsafe { try_statx( + dir_fd, + pathname, + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) }.unwrap_or_else(|| { + let mut stat = unsafe { mem::zeroed() }; + cvt(unsafe { fstatat64(dir_fd, pathname, &mut stat, libc::AT_SYMLINK_NOFOLLOW) })?; + Ok(FileAttr { stat, statx_extra_fields: None }) + }) + } + + #[cfg(any(target_os = "emscripten", target_os = "android"))] pub fn metadata(&self) -> io::Result { let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; let mut stat: stat64 = unsafe { mem::zeroed() }; @@ -516,6 +633,22 @@ impl File { Ok(File(fd)) } + #[cfg(target_os = "linux")] + pub fn file_attr(&self) -> io::Result { + let fd = self.0.raw(); + unsafe { try_statx( + fd, + b"\0" as *const _ as *const libc::c_char, + libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) }.unwrap_or_else(|| { + let mut stat = unsafe { mem::zeroed() }; + cvt(unsafe { fstat64(fd, &mut stat) })?; + Ok(FileAttr { stat, statx_extra_fields: None }) + }) + } + + #[cfg(not(target_os = "linux"))] pub fn file_attr(&self) -> io::Result { let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { @@ -796,6 +929,23 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { Ok(()) } +#[cfg(target_os = "linux")] +pub fn stat(p: &Path) -> io::Result { + let p = cstr(p)?; + let p = p.as_ptr(); + unsafe { try_statx( + libc::AT_FDCWD, + p, + libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) }.unwrap_or_else(|| { + let mut stat = unsafe { mem::zeroed() }; + cvt(unsafe { stat64(p, &mut stat) })?; + Ok(FileAttr { stat, statx_extra_fields: None }) + }) +} + +#[cfg(not(target_os = "linux"))] pub fn stat(p: &Path) -> io::Result { let p = cstr(p)?; let mut stat: stat64 = unsafe { mem::zeroed() }; @@ -805,6 +955,23 @@ pub fn stat(p: &Path) -> io::Result { Ok(FileAttr { stat }) } +#[cfg(target_os = "linux")] +pub fn lstat(p: &Path) -> io::Result { + let p = cstr(p)?; + let p = p.as_ptr(); + unsafe { try_statx( + libc::AT_FDCWD, + p, + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) }.unwrap_or_else(|| { + let mut stat = unsafe { mem::zeroed() }; + cvt(unsafe { lstat64(p, &mut stat) })?; + Ok(FileAttr { stat, statx_extra_fields: None }) + }) +} + +#[cfg(not(target_os = "linux"))] pub fn lstat(p: &Path) -> io::Result { let p = cstr(p)?; let mut stat: stat64 = unsafe { mem::zeroed() }; From 3e6920035dc7333a2e3d30e8d9f19fa4b5f36bed Mon Sep 17 00:00:00 2001 From: oxalica Date: Sat, 5 Oct 2019 17:02:00 +0800 Subject: [PATCH 3/7] Fix docs --- src/libstd/fs.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index cfcf564ad6a1f..52663cc7d0486 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1090,13 +1090,14 @@ impl Metadata { /// Returns the creation time listed in this metadata. /// - /// The returned value corresponds to the `birthtime` field of `stat` on + /// The returned value corresponds to the `btime` field of `statx` on + /// Linux not prior to 4.11, the `birthtime` field of `stat` on other /// Unix platforms and the `ftCreationTime` field on Windows platforms. /// /// # Errors /// /// This field may not be available on all platforms, and will return an - /// `Err` on platforms where it is not available. + /// `Err` on platforms or filesystems where it is not available. /// /// # Examples /// @@ -1109,7 +1110,7 @@ impl Metadata { /// if let Ok(time) = metadata.created() { /// println!("{:?}", time); /// } else { - /// println!("Not supported on this platform"); + /// println!("Not supported on this platform or filesystem"); /// } /// Ok(()) /// } From 79bc6d417ba337cc5d93514ef7b5c823dd513e09 Mon Sep 17 00:00:00 2001 From: oxalica Date: Wed, 9 Oct 2019 02:35:01 +0800 Subject: [PATCH 4/7] Use cfg blocks and fix docs --- src/libstd/sys/unix/fs.rs | 177 ++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 92 deletions(-) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 1d43844e8359d..c869ad3860b1d 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -59,7 +59,8 @@ struct StatxExtraFields { stx_btime: libc::statx_timestamp, } -// We prefer `statx` if available, which contains file creation time. +// We prefer `statx` on Linux if available, which contains file creation time. +// Default `stat64` contains no creation time. #[cfg(target_os = "linux")] unsafe fn try_statx( fd: c_int, @@ -178,6 +179,14 @@ pub struct FileType { mode: mode_t } pub struct DirBuilder { mode: mode_t } impl FileAttr { + fn from_stat64(stat: stat64) -> Self { + Self { + stat, + #[cfg(target_os = "linux")] + statx_extra_fields: None, + } + } + pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { FilePermissions { mode: (self.stat.st_mode as mode_t) } @@ -228,26 +237,6 @@ impl FileAttr { })) } - #[cfg(target_os = "linux")] - pub fn created(&self) -> io::Result { - match &self.statx_extra_fields { - Some(ext) if (ext.stx_mask & libc::STATX_BTIME) != 0 => { - Ok(SystemTime::from(libc::timespec { - tv_sec: ext.stx_btime.tv_sec as libc::time_t, - tv_nsec: ext.stx_btime.tv_nsec as libc::c_long, - })) - } - Some(_) => Err(io::Error::new( - io::ErrorKind::Other, - "creation time is not available for the filesystam", - )), - None => Err(io::Error::new( - io::ErrorKind::Other, - "creation time is not available on this platform currently", - )), - } - } - #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "macos", @@ -259,12 +248,28 @@ impl FileAttr { })) } - #[cfg(not(any(target_os = "linux", - target_os = "freebsd", + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "macos", target_os = "ios")))] pub fn created(&self) -> io::Result { + #[cfg(target_os = "linux")] + { + if let Some(ext) = &self.statx_extra_fields { + return if (ext.stx_mask & libc::STATX_BTIME) != 0 { + Ok(SystemTime::from(libc::timespec { + tv_sec: ext.stx_btime.tv_sec as libc::time_t, + tv_nsec: ext.stx_btime.tv_nsec as libc::c_long, + })) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + "creation time is not available for the filesystam", + )) + }; + } + } + Err(io::Error::new(io::ErrorKind::Other, "creation time is not available on this platform \ currently")) @@ -405,30 +410,28 @@ impl DirEntry { OsStr::from_bytes(self.name_bytes()).to_os_string() } - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] pub fn metadata(&self) -> io::Result { - let dir_fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?; - let pathname = self.entry.d_name.as_ptr(); - unsafe { try_statx( - dir_fd, - pathname, - libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, - libc::STATX_ALL, - ) }.unwrap_or_else(|| { - let mut stat = unsafe { mem::zeroed() }; - cvt(unsafe { fstatat64(dir_fd, pathname, &mut stat, libc::AT_SYMLINK_NOFOLLOW) })?; - Ok(FileAttr { stat, statx_extra_fields: None }) - }) - } + let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?; + let name = self.entry.d_name.as_ptr(); + + #[cfg(target_os = "linux")] + { + if let Some(ret) = unsafe { try_statx( + fd, + name, + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } - #[cfg(any(target_os = "emscripten", target_os = "android"))] - pub fn metadata(&self) -> io::Result { - let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW) + fstatat64(fd, name, &mut stat, libc::AT_SYMLINK_NOFOLLOW) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))] @@ -633,28 +636,26 @@ impl File { Ok(File(fd)) } - #[cfg(target_os = "linux")] pub fn file_attr(&self) -> io::Result { let fd = self.0.raw(); - unsafe { try_statx( - fd, - b"\0" as *const _ as *const libc::c_char, - libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, - libc::STATX_ALL, - ) }.unwrap_or_else(|| { - let mut stat = unsafe { mem::zeroed() }; - cvt(unsafe { fstat64(fd, &mut stat) })?; - Ok(FileAttr { stat, statx_extra_fields: None }) - }) - } - #[cfg(not(target_os = "linux"))] - pub fn file_attr(&self) -> io::Result { + #[cfg(target_os = "linux")] + { + if let Some(ret) = unsafe { try_statx( + fd, + b"\0" as *const _ as *const libc::c_char, + libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - fstat64(self.0.raw(), &mut stat) + fstat64(fd, &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn fsync(&self) -> io::Result<()> { @@ -929,56 +930,48 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { Ok(()) } -#[cfg(target_os = "linux")] pub fn stat(p: &Path) -> io::Result { let p = cstr(p)?; - let p = p.as_ptr(); - unsafe { try_statx( - libc::AT_FDCWD, - p, - libc::AT_STATX_SYNC_AS_STAT, - libc::STATX_ALL, - ) }.unwrap_or_else(|| { - let mut stat = unsafe { mem::zeroed() }; - cvt(unsafe { stat64(p, &mut stat) })?; - Ok(FileAttr { stat, statx_extra_fields: None }) - }) -} -#[cfg(not(target_os = "linux"))] -pub fn stat(p: &Path) -> io::Result { - let p = cstr(p)?; + #[cfg(target_os = "linux")] + { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } -#[cfg(target_os = "linux")] pub fn lstat(p: &Path) -> io::Result { let p = cstr(p)?; - let p = p.as_ptr(); - unsafe { try_statx( - libc::AT_FDCWD, - p, - libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, - libc::STATX_ALL, - ) }.unwrap_or_else(|| { - let mut stat = unsafe { mem::zeroed() }; - cvt(unsafe { lstat64(p, &mut stat) })?; - Ok(FileAttr { stat, statx_extra_fields: None }) - }) -} -#[cfg(not(target_os = "linux"))] -pub fn lstat(p: &Path) -> io::Result { - let p = cstr(p)?; + #[cfg(target_os = "linux")] + { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn canonicalize(p: &Path) -> io::Result { From 21b45779857fc2fb39ac6cbbcb42b3061519c711 Mon Sep 17 00:00:00 2001 From: oxalica Date: Wed, 9 Oct 2019 18:34:02 +0800 Subject: [PATCH 5/7] Remove global `use`s for `statx` and fix typo --- src/libstd/sys/unix/fs.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index c869ad3860b1d..3f842e31fb3ef 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -20,10 +20,6 @@ use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, re use libc::fstatat64; #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] use libc::dirfd; -// We only use struct `statx`, not the function `statx`. -// Instead, use `syscall` to check if it is available at runtime. -#[cfg(target_os = "linux")] -use libc::{statx, makedev}; #[cfg(target_os = "android")] use libc::{stat as stat64, fstat as fstat64, fstatat as fstatat64, lstat as lstat64, lseek64, dirent as dirent64, open as open64}; @@ -79,7 +75,7 @@ unsafe fn try_statx( pathname: *const libc::c_char, flags: c_int, mask: libc::c_uint, - statxbuf: *mut statx + statxbuf: *mut libc::statx ) -> c_int } @@ -87,7 +83,7 @@ unsafe fn try_statx( return None; } - let mut buf: statx = mem::zeroed(); + let mut buf: libc::statx = mem::zeroed(); let ret = cvt(statx(fd, path, flags, mask, &mut buf)); match ret { Err(err) => match err.raw_os_error() { @@ -100,13 +96,13 @@ unsafe fn try_statx( Ok(_) => { // We cannot fill `stat64` exhaustively because of private padding fields. let mut stat: stat64 = mem::zeroed(); - stat.st_dev = makedev(buf.stx_dev_major, buf.stx_dev_minor); + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor); stat.st_ino = buf.stx_ino; stat.st_nlink = buf.stx_nlink as u64; stat.st_mode = buf.stx_mode as u32; stat.st_uid = buf.stx_uid; stat.st_gid = buf.stx_gid; - stat.st_rdev = makedev(buf.stx_rdev_major, buf.stx_rdev_minor); + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor); stat.st_size = buf.stx_size as i64; stat.st_blksize = buf.stx_blksize as i64; stat.st_blocks = buf.stx_blocks as i64; @@ -264,7 +260,7 @@ impl FileAttr { } else { Err(io::Error::new( io::ErrorKind::Other, - "creation time is not available for the filesystam", + "creation time is not available for the filesystem", )) }; } From f7d0a8ea4f2ff5775fcd89601e8f80a0d9b1f622 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 9 Oct 2019 08:50:39 -0400 Subject: [PATCH 6/7] don't assume we can *always* find a return type hint in async fn In particular, we sometimes cannot if there is an earlier error. --- src/librustc_typeck/check/closure.rs | 15 ++++++++++++--- src/test/ui/async-await/issues/issue-65159.rs | 10 ++++++++++ src/test/ui/async-await/issues/issue-65159.stderr | 9 +++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/async-await/issues/issue-65159.rs create mode 100644 src/test/ui/async-await/issues/issue-65159.stderr diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 162555cd3ce4c..1f8ac316310b1 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -612,6 +612,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn)) => { debug!("supplied_sig_of_closure: closure is async fn body"); self.deduce_future_output_from_obligations(expr_def_id) + .unwrap_or_else(|| { + // AFAIK, deducing the future output + // always succeeds *except* in error cases + // like #65159. I'd like to return Error + // here, but I can't because I can't + // easily (and locally) prove that we + // *have* reported an + // error. --nikomatsakis + astconv.ty_infer(None, decl.output.span()) + }) } _ => astconv.ty_infer(None, decl.output.span()), @@ -646,7 +656,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn deduce_future_output_from_obligations( &self, expr_def_id: DefId, - ) -> Ty<'tcx> { + ) -> Option> { debug!("deduce_future_output_from_obligations(expr_def_id={:?})", expr_def_id); let ret_coercion = @@ -689,8 +699,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { None } - }) - .unwrap(); + }); debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty); output_ty diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs new file mode 100644 index 0000000000000..b5fee061f277e --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65159.rs @@ -0,0 +1,10 @@ +// Regression test for #65159. We used to ICE. +// +// edition:2018 + +async fn copy() -> Result<()> //~ ERROR wrong number of type arguments +{ + Ok(()) +} + +fn main() { } diff --git a/src/test/ui/async-await/issues/issue-65159.stderr b/src/test/ui/async-await/issues/issue-65159.stderr new file mode 100644 index 0000000000000..56d2c38b302e9 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-65159.stderr @@ -0,0 +1,9 @@ +error[E0107]: wrong number of type arguments: expected 2, found 1 + --> $DIR/issue-65159.rs:5:20 + | +LL | async fn copy() -> Result<()> + | ^^^^^^^^^^ expected 2 type arguments + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. From 6ae36a37ac1279d2ce20eca927cd89136a15a346 Mon Sep 17 00:00:00 2001 From: Andreas Jonson Date: Wed, 9 Oct 2019 17:45:19 +0200 Subject: [PATCH 7/7] make it possible to add args to cargo in x.py eg. make it easier to test -Ztimings for rustc --- src/bootstrap/builder.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 9b43bb0eff0e8..b8071b98f707f 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -817,12 +817,22 @@ impl<'a> Builder<'a> { let mut rustflags = Rustflags::new(&target); if stage != 0 { + if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") { + cargo.args(s.split_whitespace()); + } rustflags.env("RUSTFLAGS_NOT_BOOTSTRAP"); } else { + if let Ok(s) = env::var("CARGOFLAGS_BOOTSTRAP") { + cargo.args(s.split_whitespace()); + } rustflags.env("RUSTFLAGS_BOOTSTRAP"); rustflags.arg("--cfg=bootstrap"); } + if let Ok(s) = env::var("CARGOFLAGS") { + cargo.args(s.split_whitespace()); + } + match mode { Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}, Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {