Auto merge of #132902 - matthiaskrgr:rollup-43qgg3t, r=matthiaskrgr

Rollup of 4 pull requests

Successful merges:

 - #129627 (Ensure that tail expr receive lifetime extension)
 - #130999 (Implement file_lock feature)
 - #132873 (handle separate prefixes in clippy rules)
 - #132891 (Remove `rustc_session::config::rustc_short_optgroups`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-11-11 19:25:06 +00:00
commit 81eef2d362
17 changed files with 674 additions and 57 deletions

View File

@ -934,9 +934,12 @@ pub fn version_at_macro_invocation(
} }
fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) { fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
let groups = if verbose { config::rustc_optgroups() } else { config::rustc_short_optgroups() };
let mut options = getopts::Options::new(); let mut options = getopts::Options::new();
for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) { for option in config::rustc_optgroups()
.iter()
.filter(|x| verbose || !x.is_verbose_help_only)
.filter(|x| include_unstable_options || x.is_stable())
{
option.apply(&mut options); option.apply(&mut options);
} }
let message = "Usage: rustc [OPTIONS] INPUT"; let message = "Usage: rustc [OPTIONS] INPUT";

View File

@ -1398,9 +1398,25 @@ pub enum OptionKind {
} }
pub struct RustcOptGroup { pub struct RustcOptGroup {
apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>, /// The "primary" name for this option. Normally equal to `long_name`,
/// except for options that don't have a long name, in which case
/// `short_name` is used.
///
/// This is needed when interacting with `getopts` in some situations,
/// because if an option has both forms, that library treats the long name
/// as primary and the short name as an alias.
pub name: &'static str, pub name: &'static str,
stability: OptionStability, stability: OptionStability,
kind: OptionKind,
short_name: &'static str,
long_name: &'static str,
desc: &'static str,
value_hint: &'static str,
/// If true, this option should not be printed by `rustc --help`, but
/// should still be printed by `rustc --help -v`.
pub is_verbose_help_only: bool,
} }
impl RustcOptGroup { impl RustcOptGroup {
@ -1409,7 +1425,13 @@ impl RustcOptGroup {
} }
pub fn apply(&self, options: &mut getopts::Options) { pub fn apply(&self, options: &mut getopts::Options) {
(self.apply)(options); let &Self { short_name, long_name, desc, value_hint, .. } = self;
match self.kind {
OptionKind::Opt => options.optopt(short_name, long_name, desc, value_hint),
OptionKind::Multi => options.optmulti(short_name, long_name, desc, value_hint),
OptionKind::Flag => options.optflag(short_name, long_name, desc),
OptionKind::FlagMulti => options.optflagmulti(short_name, long_name, desc),
};
} }
} }
@ -1419,31 +1441,22 @@ pub fn make_opt(
short_name: &'static str, short_name: &'static str,
long_name: &'static str, long_name: &'static str,
desc: &'static str, desc: &'static str,
hint: &'static str, value_hint: &'static str,
) -> RustcOptGroup { ) -> RustcOptGroup {
// "Flag" options don't have a value, and therefore don't have a value hint.
match kind {
OptionKind::Opt | OptionKind::Multi => {}
OptionKind::Flag | OptionKind::FlagMulti => assert_eq!(value_hint, ""),
}
RustcOptGroup { RustcOptGroup {
name: cmp::max_by_key(short_name, long_name, |s| s.len()), name: cmp::max_by_key(short_name, long_name, |s| s.len()),
stability, stability,
apply: match kind { kind,
OptionKind::Opt => Box::new(move |opts: &mut getopts::Options| { short_name,
opts.optopt(short_name, long_name, desc, hint) long_name,
}), desc,
OptionKind::Multi => Box::new(move |opts: &mut getopts::Options| { value_hint,
opts.optmulti(short_name, long_name, desc, hint) is_verbose_help_only: false,
}),
OptionKind::Flag => {
assert_eq!(hint, "");
Box::new(move |opts: &mut getopts::Options| {
opts.optflag(short_name, long_name, desc)
})
}
OptionKind::FlagMulti => {
assert_eq!(hint, "");
Box::new(move |opts: &mut getopts::Options| {
opts.optflagmulti(short_name, long_name, desc)
})
}
},
} }
} }
@ -1454,16 +1467,15 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE
) )
}); });
/// Returns the "short" subset of the rustc command line options, /// Returns all rustc command line options, including metadata for
/// including metadata for each option, such as whether the option is /// each option, such as whether the option is stable.
/// part of the stable long-term interface for rustc. pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
use OptionKind::{Flag, FlagMulti, Multi, Opt}; use OptionKind::{Flag, FlagMulti, Multi, Opt};
use OptionStability::Stable; use OptionStability::{Stable, Unstable};
use self::make_opt as opt; use self::make_opt as opt;
vec![ let mut options = vec![
opt(Stable, Flag, "h", "help", "Display this message", ""), opt(Stable, Flag, "h", "help", "Display this message", ""),
opt( opt(
Stable, Stable,
@ -1550,21 +1562,11 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
opt(Stable, Multi, "C", "codegen", "Set a codegen option", "OPT[=VALUE]"), opt(Stable, Multi, "C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
opt(Stable, Flag, "V", "version", "Print version info and exit", ""), opt(Stable, Flag, "V", "version", "Print version info and exit", ""),
opt(Stable, Flag, "v", "verbose", "Use verbose output", ""), opt(Stable, Flag, "v", "verbose", "Use verbose output", ""),
] ];
}
/// Returns all rustc command line options, including metadata for // Options in this list are hidden from `rustc --help` by default, but are
/// each option, such as whether the option is part of the stable // shown by `rustc --help -v`.
/// long-term interface for rustc. let verbose_only = [
pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
use OptionKind::{Multi, Opt};
use OptionStability::{Stable, Unstable};
use self::make_opt as opt;
let mut opts = rustc_short_optgroups();
// FIXME: none of these descriptions are actually used
opts.extend(vec![
opt( opt(
Stable, Stable,
Multi, Multi,
@ -1590,9 +1592,9 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
"", "",
"color", "color",
"Configure coloring of output: "Configure coloring of output:
auto = colorize, if output goes to a tty (default); auto = colorize, if output goes to a tty (default);
always = always colorize output; always = always colorize output;
never = never colorize output", never = never colorize output",
"auto|always|never", "auto|always|never",
), ),
opt( opt(
@ -1612,8 +1614,13 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
"FROM=TO", "FROM=TO",
), ),
opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "VAR=VALUE"), opt(Unstable, Multi, "", "env-set", "Inject an environment variable", "VAR=VALUE"),
]); ];
opts options.extend(verbose_only.into_iter().map(|mut opt| {
opt.is_verbose_help_only = true;
opt
}));
options
} }
pub fn get_cmd_lint_options( pub fn get_cmd_lint_options(

View File

@ -624,6 +624,223 @@ impl File {
self.inner.datasync() self.inner.datasync()
} }
/// Acquire an exclusive advisory lock on the file. Blocks until the lock can be acquired.
///
/// This acquires an exclusive advisory lock; no other file handle to this file may acquire
/// another lock.
///
/// If this file handle, or a clone of it, already holds an advisory lock the exact behavior is
/// unspecified and platform dependent, including the possibility that it will deadlock.
/// However, if this method returns, then an exclusive lock is held.
///
/// If the file not open for writing, it is unspecified whether this function returns an error.
///
/// Note, this is an advisory lock meant to interact with [`lock_shared`], [`try_lock`],
/// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
/// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` flag,
/// and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` flag. Note that,
/// this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
///
/// [`lock_shared`]: File::lock_shared
/// [`try_lock`]: File::try_lock
/// [`try_lock_shared`]: File::try_lock_shared
/// [`unlock`]: File::unlock
/// [`read`]: Read::read
/// [`write`]: Write::write
///
/// # Examples
///
/// ```no_run
/// #![feature(file_lock)]
/// use std::fs::File;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::open("foo.txt")?;
/// f.lock()?;
/// Ok(())
/// }
/// ```
#[unstable(feature = "file_lock", issue = "130994")]
pub fn lock(&self) -> io::Result<()> {
self.inner.lock()
}
/// Acquire a shared advisory lock on the file. Blocks until the lock can be acquired.
///
/// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but
/// none may hold an exclusive lock.
///
/// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
/// unspecified and platform dependent, including the possibility that it will deadlock.
/// However, if this method returns, then a shared lock is held.
///
/// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`],
/// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
/// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` flag,
/// and the `LockFileEx` function on Windows. Note that, this
/// [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
///
/// [`lock`]: File::lock
/// [`try_lock`]: File::try_lock
/// [`try_lock_shared`]: File::try_lock_shared
/// [`unlock`]: File::unlock
/// [`read`]: Read::read
/// [`write`]: Write::write
///
/// # Examples
///
/// ```no_run
/// #![feature(file_lock)]
/// use std::fs::File;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::open("foo.txt")?;
/// f.lock_shared()?;
/// Ok(())
/// }
/// ```
#[unstable(feature = "file_lock", issue = "130994")]
pub fn lock_shared(&self) -> io::Result<()> {
self.inner.lock_shared()
}
/// Acquire an exclusive advisory lock on the file. Returns `Ok(false)` if the file is locked.
///
/// This acquires an exclusive advisory lock; no other file handle to this file may acquire
/// another lock.
///
/// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
/// unspecified and platform dependent, including the possibility that it will deadlock.
/// However, if this method returns, then an exclusive lock is held.
///
/// If the file not open for writing, it is unspecified whether this function returns an error.
///
/// Note, this is an advisory lock meant to interact with [`lock`], [`lock_shared`],
/// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
/// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` and
/// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK`
/// and `LOCKFILE_FAIL_IMMEDIATELY` flags. Note that, this
/// [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
///
/// [`lock`]: File::lock
/// [`lock_shared`]: File::lock_shared
/// [`try_lock_shared`]: File::try_lock_shared
/// [`unlock`]: File::unlock
/// [`read`]: Read::read
/// [`write`]: Write::write
///
/// # Examples
///
/// ```no_run
/// #![feature(file_lock)]
/// use std::fs::File;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::open("foo.txt")?;
/// f.try_lock()?;
/// Ok(())
/// }
/// ```
#[unstable(feature = "file_lock", issue = "130994")]
pub fn try_lock(&self) -> io::Result<bool> {
self.inner.try_lock()
}
/// Acquire a shared advisory lock on the file.
/// Returns `Ok(false)` if the file is exclusively locked.
///
/// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but
/// none may hold an exclusive lock.
///
/// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
/// unspecified and platform dependent, including the possibility that it will deadlock.
/// However, if this method returns, then a shared lock is held.
///
/// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`],
/// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`]
/// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` and
/// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the
/// `LOCKFILE_FAIL_IMMEDIATELY` flag. Note that, this
/// [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
///
/// [`lock`]: File::lock
/// [`lock_shared`]: File::lock_shared
/// [`try_lock`]: File::try_lock
/// [`unlock`]: File::unlock
/// [`read`]: Read::read
/// [`write`]: Write::write
///
/// # Examples
///
/// ```no_run
/// #![feature(file_lock)]
/// use std::fs::File;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::open("foo.txt")?;
/// f.try_lock_shared()?;
/// Ok(())
/// }
/// ```
#[unstable(feature = "file_lock", issue = "130994")]
pub fn try_lock_shared(&self) -> io::Result<bool> {
self.inner.try_lock_shared()
}
/// Release all locks on the file.
///
/// All remaining locks are released when the file handle, and all clones of it, are dropped.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `flock` function on Unix with the `LOCK_UN` flag,
/// and the `UnlockFile` function on Windows. Note that, this
/// [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
///
/// # Examples
///
/// ```no_run
/// #![feature(file_lock)]
/// use std::fs::File;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::open("foo.txt")?;
/// f.lock()?;
/// f.unlock()?;
/// Ok(())
/// }
/// ```
#[unstable(feature = "file_lock", issue = "130994")]
pub fn unlock(&self) -> io::Result<()> {
self.inner.unlock()
}
/// Truncates or extends the underlying file, updating the size of /// Truncates or extends the underlying file, updating the size of
/// this file to become `size`. /// this file to become `size`.
/// ///

View File

@ -203,6 +203,124 @@ fn file_test_io_seek_and_write() {
assert!(read_str == final_msg); assert!(read_str == final_msg);
} }
#[test]
fn file_lock_multiple_shared() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_multiple_shared_test.txt");
let f1 = check!(File::create(filename));
let f2 = check!(OpenOptions::new().write(true).open(filename));
// Check that we can acquire concurrent shared locks
check!(f1.lock_shared());
check!(f2.lock_shared());
check!(f1.unlock());
check!(f2.unlock());
assert!(check!(f1.try_lock_shared()));
assert!(check!(f2.try_lock_shared()));
}
#[test]
fn file_lock_blocking() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_blocking_test.txt");
let f1 = check!(File::create(filename));
let f2 = check!(OpenOptions::new().write(true).open(filename));
// Check that shared locks block exclusive locks
check!(f1.lock_shared());
assert!(!check!(f2.try_lock()));
check!(f1.unlock());
// Check that exclusive locks block shared locks
check!(f1.lock());
assert!(!check!(f2.try_lock_shared()));
}
#[test]
fn file_lock_drop() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_dup_test.txt");
let f1 = check!(File::create(filename));
let f2 = check!(OpenOptions::new().write(true).open(filename));
// Check that locks are released when the File is dropped
check!(f1.lock_shared());
assert!(!check!(f2.try_lock()));
drop(f1);
assert!(check!(f2.try_lock()));
}
#[test]
fn file_lock_dup() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_dup_test.txt");
let f1 = check!(File::create(filename));
let f2 = check!(OpenOptions::new().write(true).open(filename));
// Check that locks are not dropped if the File has been cloned
check!(f1.lock_shared());
assert!(!check!(f2.try_lock()));
let cloned = check!(f1.try_clone());
drop(f1);
assert!(!check!(f2.try_lock()));
drop(cloned)
}
#[test]
#[cfg(windows)]
fn file_lock_double_unlock() {
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_double_unlock_test.txt");
let f1 = check!(File::create(filename));
let f2 = check!(OpenOptions::new().write(true).open(filename));
// On Windows a file handle may acquire both a shared and exclusive lock.
// Check that both are released by unlock()
check!(f1.lock());
check!(f1.lock_shared());
assert!(!check!(f2.try_lock()));
check!(f1.unlock());
assert!(check!(f2.try_lock()));
}
#[test]
#[cfg(windows)]
fn file_lock_blocking_async() {
use crate::thread::{sleep, spawn};
const FILE_FLAG_OVERLAPPED: u32 = 0x40000000;
let tmpdir = tmpdir();
let filename = &tmpdir.join("file_lock_blocking_async.txt");
let f1 = check!(File::create(filename));
let f2 =
check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(filename));
check!(f1.lock());
// Ensure that lock() is synchronous when the file is opened for asynchronous IO
let t = spawn(move || {
check!(f2.lock());
});
sleep(Duration::from_secs(1));
assert!(!t.is_finished());
check!(f1.unlock());
t.join().unwrap();
// Ensure that lock_shared() is synchronous when the file is opened for asynchronous IO
let f2 =
check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(filename));
check!(f1.lock());
// Ensure that lock() is synchronous when the file is opened for asynchronous IO
let t = spawn(move || {
check!(f2.lock_shared());
});
sleep(Duration::from_secs(1));
assert!(!t.is_finished());
check!(f1.unlock());
t.join().unwrap();
}
#[test] #[test]
fn file_test_io_seek_shakedown() { fn file_test_io_seek_shakedown() {
// 01234567890123 // 01234567890123

View File

@ -364,6 +364,26 @@ impl File {
self.fsync() self.fsync()
} }
pub fn lock(&self) -> io::Result<()> {
unsupported()
}
pub fn lock_shared(&self) -> io::Result<()> {
unsupported()
}
pub fn try_lock(&self) -> io::Result<bool> {
unsupported()
}
pub fn try_lock_shared(&self) -> io::Result<bool> {
unsupported()
}
pub fn unlock(&self) -> io::Result<()> {
unsupported()
}
pub fn truncate(&self, _size: u64) -> io::Result<()> { pub fn truncate(&self, _size: u64) -> io::Result<()> {
Err(Error::from_raw_os_error(22)) Err(Error::from_raw_os_error(22))
} }

View File

@ -350,6 +350,26 @@ impl File {
self.flush() self.flush()
} }
pub fn lock(&self) -> io::Result<()> {
unsupported()
}
pub fn lock_shared(&self) -> io::Result<()> {
unsupported()
}
pub fn try_lock(&self) -> io::Result<bool> {
unsupported()
}
pub fn try_lock_shared(&self) -> io::Result<bool> {
unsupported()
}
pub fn unlock(&self) -> io::Result<()> {
unsupported()
}
pub fn truncate(&self, _size: u64) -> io::Result<()> { pub fn truncate(&self, _size: u64) -> io::Result<()> {
unsupported() unsupported()
} }

View File

@ -1254,6 +1254,43 @@ impl File {
} }
} }
pub fn lock(&self) -> io::Result<()> {
cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX) })?;
return Ok(());
}
pub fn lock_shared(&self) -> io::Result<()> {
cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH) })?;
return Ok(());
}
pub fn try_lock(&self) -> io::Result<bool> {
let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) });
if let Err(ref err) = result {
if err.kind() == io::ErrorKind::WouldBlock {
return Ok(false);
}
}
result?;
return Ok(true);
}
pub fn try_lock_shared(&self) -> io::Result<bool> {
let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) });
if let Err(ref err) = result {
if err.kind() == io::ErrorKind::WouldBlock {
return Ok(false);
}
}
result?;
return Ok(true);
}
pub fn unlock(&self) -> io::Result<()> {
cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_UN) })?;
return Ok(());
}
pub fn truncate(&self, size: u64) -> io::Result<()> { pub fn truncate(&self, size: u64) -> io::Result<()> {
let size: off64_t = let size: off64_t =
size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?; size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;

View File

@ -198,6 +198,26 @@ impl File {
self.0 self.0
} }
pub fn lock(&self) -> io::Result<()> {
self.0
}
pub fn lock_shared(&self) -> io::Result<()> {
self.0
}
pub fn try_lock(&self) -> io::Result<bool> {
self.0
}
pub fn try_lock_shared(&self) -> io::Result<bool> {
self.0
}
pub fn unlock(&self) -> io::Result<()> {
self.0
}
pub fn truncate(&self, _size: u64) -> io::Result<()> { pub fn truncate(&self, _size: u64) -> io::Result<()> {
self.0 self.0
} }

View File

@ -420,6 +420,26 @@ impl File {
self.fd.datasync() self.fd.datasync()
} }
pub fn lock(&self) -> io::Result<()> {
unsupported()
}
pub fn lock_shared(&self) -> io::Result<()> {
unsupported()
}
pub fn try_lock(&self) -> io::Result<bool> {
unsupported()
}
pub fn try_lock_shared(&self) -> io::Result<bool> {
unsupported()
}
pub fn unlock(&self) -> io::Result<()> {
unsupported()
}
pub fn truncate(&self, size: u64) -> io::Result<()> { pub fn truncate(&self, size: u64) -> io::Result<()> {
self.fd.filestat_set_size(size) self.fd.filestat_set_size(size)
} }

View File

@ -2351,6 +2351,9 @@ Windows.Win32.Storage.FileSystem.GetFinalPathNameByHandleW
Windows.Win32.Storage.FileSystem.GetFullPathNameW Windows.Win32.Storage.FileSystem.GetFullPathNameW
Windows.Win32.Storage.FileSystem.GetTempPathW Windows.Win32.Storage.FileSystem.GetTempPathW
Windows.Win32.Storage.FileSystem.INVALID_FILE_ATTRIBUTES Windows.Win32.Storage.FileSystem.INVALID_FILE_ATTRIBUTES
Windows.Win32.Storage.FileSystem.LOCKFILE_EXCLUSIVE_LOCK
Windows.Win32.Storage.FileSystem.LOCKFILE_FAIL_IMMEDIATELY
Windows.Win32.Storage.FileSystem.LockFileEx
Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE
Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE_CALLBACK_REASON Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE_CALLBACK_REASON
Windows.Win32.Storage.FileSystem.MAXIMUM_REPARSE_DATA_BUFFER_SIZE Windows.Win32.Storage.FileSystem.MAXIMUM_REPARSE_DATA_BUFFER_SIZE
@ -2396,6 +2399,7 @@ Windows.Win32.Storage.FileSystem.SYMBOLIC_LINK_FLAG_DIRECTORY
Windows.Win32.Storage.FileSystem.SYMBOLIC_LINK_FLAGS Windows.Win32.Storage.FileSystem.SYMBOLIC_LINK_FLAGS
Windows.Win32.Storage.FileSystem.SYNCHRONIZE Windows.Win32.Storage.FileSystem.SYNCHRONIZE
Windows.Win32.Storage.FileSystem.TRUNCATE_EXISTING Windows.Win32.Storage.FileSystem.TRUNCATE_EXISTING
Windows.Win32.Storage.FileSystem.UnlockFile
Windows.Win32.Storage.FileSystem.VOLUME_NAME_DOS Windows.Win32.Storage.FileSystem.VOLUME_NAME_DOS
Windows.Win32.Storage.FileSystem.VOLUME_NAME_GUID Windows.Win32.Storage.FileSystem.VOLUME_NAME_GUID
Windows.Win32.Storage.FileSystem.VOLUME_NAME_NONE Windows.Win32.Storage.FileSystem.VOLUME_NAME_NONE

View File

@ -65,6 +65,7 @@ windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinit
windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL); windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL);
windows_targets::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32); windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32);
windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL);
@ -96,6 +97,7 @@ windows_targets::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32)
windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> BOOLEAN); windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> BOOLEAN);
windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> BOOLEAN); windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> BOOLEAN);
windows_targets::link!("kernel32.dll" "system" fn UnlockFile(hfile : HANDLE, dwfileoffsetlow : u32, dwfileoffsethigh : u32, nnumberofbytestounlocklow : u32, nnumberofbytestounlockhigh : u32) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT); windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT);
windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT); windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT);
@ -2730,6 +2732,9 @@ pub struct LINGER {
pub l_onoff: u16, pub l_onoff: u16,
pub l_linger: u16, pub l_linger: u16,
} }
pub const LOCKFILE_EXCLUSIVE_LOCK: LOCK_FILE_FLAGS = 2u32;
pub const LOCKFILE_FAIL_IMMEDIATELY: LOCK_FILE_FLAGS = 1u32;
pub type LOCK_FILE_FLAGS = u32;
pub type LPOVERLAPPED_COMPLETION_ROUTINE = Option< pub type LPOVERLAPPED_COMPLETION_ROUTINE = Option<
unsafe extern "system" fn( unsafe extern "system" fn(
dwerrorcode: u32, dwerrorcode: u32,

View File

@ -346,6 +346,120 @@ impl File {
self.fsync() self.fsync()
} }
fn acquire_lock(&self, flags: c::LOCK_FILE_FLAGS) -> io::Result<()> {
unsafe {
let mut overlapped: c::OVERLAPPED = mem::zeroed();
let event = c::CreateEventW(ptr::null_mut(), c::FALSE, c::FALSE, ptr::null());
if event.is_null() {
return Err(io::Error::last_os_error());
}
overlapped.hEvent = event;
let lock_result = cvt(c::LockFileEx(
self.handle.as_raw_handle(),
flags,
0,
u32::MAX,
u32::MAX,
&mut overlapped,
));
let final_result = match lock_result {
Ok(_) => Ok(()),
Err(err) => {
if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) {
// Wait for the lock to be acquired, and get the lock operation status.
// This can happen asynchronously, if the file handle was opened for async IO
let mut bytes_transferred = 0;
cvt(c::GetOverlappedResult(
self.handle.as_raw_handle(),
&mut overlapped,
&mut bytes_transferred,
c::TRUE,
))
.map(|_| ())
} else {
Err(err)
}
}
};
c::CloseHandle(overlapped.hEvent);
final_result
}
}
pub fn lock(&self) -> io::Result<()> {
self.acquire_lock(c::LOCKFILE_EXCLUSIVE_LOCK)
}
pub fn lock_shared(&self) -> io::Result<()> {
self.acquire_lock(0)
}
pub fn try_lock(&self) -> io::Result<bool> {
let result = cvt(unsafe {
let mut overlapped = mem::zeroed();
c::LockFileEx(
self.handle.as_raw_handle(),
c::LOCKFILE_EXCLUSIVE_LOCK | c::LOCKFILE_FAIL_IMMEDIATELY,
0,
u32::MAX,
u32::MAX,
&mut overlapped,
)
});
match result {
Ok(_) => Ok(true),
Err(err)
if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32)
|| err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) =>
{
Ok(false)
}
Err(err) => Err(err),
}
}
pub fn try_lock_shared(&self) -> io::Result<bool> {
let result = cvt(unsafe {
let mut overlapped = mem::zeroed();
c::LockFileEx(
self.handle.as_raw_handle(),
c::LOCKFILE_FAIL_IMMEDIATELY,
0,
u32::MAX,
u32::MAX,
&mut overlapped,
)
});
match result {
Ok(_) => Ok(true),
Err(err)
if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32)
|| err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) =>
{
Ok(false)
}
Err(err) => Err(err),
}
}
pub fn unlock(&self) -> io::Result<()> {
// Unlock the handle twice because LockFileEx() allows a file handle to acquire
// both an exclusive and shared lock, in which case the documentation states that:
// "...two unlock operations are necessary to unlock the region; the first unlock operation
// unlocks the exclusive lock, the second unlock operation unlocks the shared lock"
cvt(unsafe { c::UnlockFile(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX) })?;
let result =
cvt(unsafe { c::UnlockFile(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX) });
match result {
Ok(_) => Ok(()),
Err(err) if err.raw_os_error() == Some(c::ERROR_NOT_LOCKED as i32) => Ok(()),
Err(err) => Err(err),
}
}
pub fn truncate(&self, size: u64) -> io::Result<()> { pub fn truncate(&self, size: u64) -> io::Result<()> {
let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 }; let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 };
api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result() api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()

View File

@ -82,7 +82,7 @@ pub(crate) fn get_clippy_rules_in_order(
{ {
item.iter().for_each(|v| { item.iter().for_each(|v| {
let rule = format!("{prefix}{v}"); let rule = format!("{prefix}{v}");
let position = all_args.iter().position(|t| t == &rule).unwrap(); let position = all_args.iter().position(|t| t == &rule || t == v).unwrap();
result.push((position, rule)); result.push((position, rule));
}); });
} }

View File

@ -323,6 +323,23 @@ fn order_of_clippy_rules() {
assert_eq!(expected, actual); assert_eq!(expected, actual);
} }
#[test]
fn clippy_rule_separate_prefix() {
let args =
vec!["clippy".to_string(), "-A clippy:all".to_string(), "-W clippy::style".to_string()];
let config = Config::parse(Flags::parse(&args));
let actual = match &config.cmd {
crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
get_clippy_rules_in_order(&args, &allow, &deny, &warn, &forbid)
}
_ => panic!("invalid subcommand"),
};
let expected = vec!["-A clippy:all".to_string(), "-W clippy::style".to_string()];
assert_eq!(expected, actual);
}
#[test] #[test]
fn verbose_tests_default_value() { fn verbose_tests_default_value() {
let config = Config::parse(Flags::parse(&["build".into(), "compiler".into()])); let config = Config::parse(Flags::parse(&["build".into(), "compiler".into()]));

View File

@ -0,0 +1 @@
("Hello", 1) [(("Hello", 1),)] "Hello" "Hello" "Hello" ("Hello", 1) ("Hello", 1) ("Hello", 1)

View File

@ -0,0 +1 @@
("Hello", 1) [(("Hello", 1),)] "Hello" "Hello" "Hello" ("Hello", 1) ("Hello", 1) ("Hello", 1)

View File

@ -1,4 +1,21 @@
//@ check-pass // This is a test for the new temporary lifetime behaviour as implemented for RFC 3606.
// In essence, with #3606 we can write the following variable initialisation without
// a borrow checking error because the temporary lifetime is automatically extended.
// ```rust
// let x = if condition() {
// &something()
// } else {
// &something_else()
// };
// ```
// More details can be found in https://github.com/rust-lang/rfcs/pull/3606
//@ run-pass
//@ check-run-results
//@ revisions: edition2021 edition2024
//@ [edition2021] edition: 2021
//@ [edition2024] edition: 2024
//@ [edition2024] compile-flags: -Z unstable-options
fn temp() -> (String, i32) { fn temp() -> (String, i32) {
(String::from("Hello"), 1) (String::from("Hello"), 1)
@ -13,11 +30,7 @@ fn main() {
let _ = 123; let _ = 123;
&(*temp().0)[..] &(*temp().0)[..]
}; };
let f = if true { let f = if true { &temp() } else { &temp() };
&temp()
} else {
&temp()
};
let g = match true { let g = match true {
true => &temp(), true => &temp(),
false => { false => {