Auto merge of #139746 - ChrisDenton:rollup-eq08b2e, r=ChrisDenton

Rollup of 10 pull requests

Successful merges:

 - #138972 (std: Fix build for NuttX targets)
 - #139177 (Use -C target-cpu=z13 on s390x vector test)
 - #139511 (libtest: Pass the test's panic payload as Option instead of Result)
 - #139605 (update ```miniz_oxide``` to 0.8.8)
 - #139618 (compiletest: Make `SUGGESTION` annotations viral)
 - #139677 (Fix profiler_builtins build script to handle full path to profiler lib)
 - #139683 (Use `with_native_path` for Windows)
 - #139710 (Move `args` into `std::sys`)
 - #139721 (End all lines in src/stage0 with trailing newline)
 - #139726 (Move `select_unpredictable` to the `hint` module)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-04-13 14:56:44 +00:00
commit 092a284ba0
71 changed files with 494 additions and 565 deletions

View file

@ -1212,7 +1212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide 0.8.7", "miniz_oxide 0.8.8",
] ]
[[package]] [[package]]
@ -2282,9 +2282,9 @@ dependencies = [
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.7" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [ dependencies = [
"adler2", "adler2",
] ]

View file

@ -176,9 +176,9 @@ dependencies = [
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.7" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [ dependencies = [
"adler2", "adler2",
"compiler_builtins", "compiler_builtins",

View file

@ -61,52 +61,4 @@ impl bool {
pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> { pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
if self { Some(f()) } else { None } if self { Some(f()) } else { None }
} }
/// Returns either `true_val` or `false_val` depending on the value of
/// `self`, with a hint to the compiler that `self` is unlikely
/// to be correctly predicted by a CPUs branch predictor.
///
/// This method is functionally equivalent to
/// ```ignore (this is just for illustrative purposes)
/// fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
/// if b { true_val } else { false_val }
/// }
/// ```
/// but might generate different assembly. In particular, on platforms with
/// a conditional move or select instruction (like `cmov` on x86 or `csel`
/// on ARM) the optimizer might use these instructions to avoid branches,
/// which can benefit performance if the branch predictor is struggling
/// with predicting `condition`, such as in an implementation of binary
/// search.
///
/// Note however that this lowering is not guaranteed (on any platform) and
/// should not be relied upon when trying to write constant-time code. Also
/// be aware that this lowering might *decrease* performance if `condition`
/// is well-predictable. It is advisable to perform benchmarks to tell if
/// this function is useful.
///
/// # Examples
///
/// Distribute values evenly between two buckets:
/// ```
/// #![feature(select_unpredictable)]
///
/// use std::hash::BuildHasher;
///
/// fn append<H: BuildHasher>(hasher: &H, v: i32, bucket_one: &mut Vec<i32>, bucket_two: &mut Vec<i32>) {
/// let hash = hasher.hash_one(&v);
/// let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two);
/// bucket.push(v);
/// }
/// # let hasher = std::collections::hash_map::RandomState::new();
/// # let mut bucket_one = Vec::new();
/// # let mut bucket_two = Vec::new();
/// # append(&hasher, 42, &mut bucket_one, &mut bucket_two);
/// # assert_eq!(bucket_one.len() + bucket_two.len(), 1);
/// ```
#[inline(always)]
#[unstable(feature = "select_unpredictable", issue = "133962")]
pub fn select_unpredictable<T>(self, true_val: T, false_val: T) -> T {
crate::intrinsics::select_unpredictable(self, true_val, false_val)
}
} }

View file

@ -734,3 +734,52 @@ pub const fn unlikely(b: bool) -> bool {
pub const fn cold_path() { pub const fn cold_path() {
crate::intrinsics::cold_path() crate::intrinsics::cold_path()
} }
/// Returns either `true_val` or `false_val` depending on the value of `b`,
/// with a hint to the compiler that `b` is unlikely to be correctly
/// predicted by a CPUs branch predictor.
///
/// This method is functionally equivalent to
/// ```ignore (this is just for illustrative purposes)
/// fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
/// if b { true_val } else { false_val }
/// }
/// ```
/// but might generate different assembly. In particular, on platforms with
/// a conditional move or select instruction (like `cmov` on x86 or `csel`
/// on ARM) the optimizer might use these instructions to avoid branches,
/// which can benefit performance if the branch predictor is struggling
/// with predicting `condition`, such as in an implementation of binary
/// search.
///
/// Note however that this lowering is not guaranteed (on any platform) and
/// should not be relied upon when trying to write constant-time code. Also
/// be aware that this lowering might *decrease* performance if `condition`
/// is well-predictable. It is advisable to perform benchmarks to tell if
/// this function is useful.
///
/// # Examples
///
/// Distribute values evenly between two buckets:
/// ```
/// #![feature(select_unpredictable)]
///
/// use std::hash::BuildHasher;
/// use std::hint;
///
/// fn append<H: BuildHasher>(hasher: &H, v: i32, bucket_one: &mut Vec<i32>, bucket_two: &mut Vec<i32>) {
/// let hash = hasher.hash_one(&v);
/// let bucket = hint::select_unpredictable(hash % 2 == 0, bucket_one, bucket_two);
/// bucket.push(v);
/// }
/// # let hasher = std::collections::hash_map::RandomState::new();
/// # let mut bucket_one = Vec::new();
/// # let mut bucket_two = Vec::new();
/// # append(&hasher, 42, &mut bucket_one, &mut bucket_two);
/// # assert_eq!(bucket_one.len() + bucket_two.len(), 1);
/// ```
#[inline(always)]
#[unstable(feature = "select_unpredictable", issue = "133962")]
pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
crate::intrinsics::select_unpredictable(b, true_val, false_val)
}

View file

@ -1326,7 +1326,7 @@ pub const fn unlikely(b: bool) -> bool {
/// Therefore, implementations must not require the user to uphold /// Therefore, implementations must not require the user to uphold
/// any safety invariants. /// any safety invariants.
/// ///
/// The public form of this instrinsic is [`bool::select_unpredictable`]. /// The public form of this instrinsic is [`core::hint::select_unpredictable`].
#[unstable(feature = "core_intrinsics", issue = "none")] #[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic] #[rustc_intrinsic]
#[rustc_nounwind] #[rustc_nounwind]

View file

@ -2822,7 +2822,7 @@ impl<T> [T] {
// Binary search interacts poorly with branch prediction, so force // Binary search interacts poorly with branch prediction, so force
// the compiler to use conditional moves if supported by the target // the compiler to use conditional moves if supported by the target
// architecture. // architecture.
base = (cmp == Greater).select_unpredictable(base, mid); base = hint::select_unpredictable(cmp == Greater, base, mid);
// This is imprecise in the case where `size` is odd and the // This is imprecise in the case where `size` is odd and the
// comparison returns Greater: the mid element still gets included // comparison returns Greater: the mid element still gets included

View file

@ -2,7 +2,7 @@
use crate::mem::{self, ManuallyDrop, MaybeUninit}; use crate::mem::{self, ManuallyDrop, MaybeUninit};
use crate::slice::sort::shared::FreezeMarker; use crate::slice::sort::shared::FreezeMarker;
use crate::{intrinsics, ptr, slice}; use crate::{hint, intrinsics, ptr, slice};
// It's important to differentiate between SMALL_SORT_THRESHOLD performance for // It's important to differentiate between SMALL_SORT_THRESHOLD performance for
// small slices and small-sort performance sorting small sub-slices as part of // small slices and small-sort performance sorting small sub-slices as part of
@ -408,8 +408,8 @@ where
// } // }
// The goal is to generate cmov instructions here. // The goal is to generate cmov instructions here.
let v_a_swap = should_swap.select_unpredictable(v_b, v_a); let v_a_swap = hint::select_unpredictable(should_swap, v_b, v_a);
let v_b_swap = should_swap.select_unpredictable(v_a, v_b); let v_b_swap = hint::select_unpredictable(should_swap, v_a, v_b);
let v_b_swap_tmp = ManuallyDrop::new(ptr::read(v_b_swap)); let v_b_swap_tmp = ManuallyDrop::new(ptr::read(v_b_swap));
ptr::copy(v_a_swap, v_a, 1); ptr::copy(v_a_swap, v_a, 1);
@ -640,15 +640,15 @@ pub unsafe fn sort4_stable<T, F: FnMut(&T, &T) -> bool>(
// 1, 1 | c b a d // 1, 1 | c b a d
let c3 = is_less(&*c, &*a); let c3 = is_less(&*c, &*a);
let c4 = is_less(&*d, &*b); let c4 = is_less(&*d, &*b);
let min = c3.select_unpredictable(c, a); let min = hint::select_unpredictable(c3, c, a);
let max = c4.select_unpredictable(b, d); let max = hint::select_unpredictable(c4, b, d);
let unknown_left = c3.select_unpredictable(a, c4.select_unpredictable(c, b)); let unknown_left = hint::select_unpredictable(c3, a, hint::select_unpredictable(c4, c, b));
let unknown_right = c4.select_unpredictable(d, c3.select_unpredictable(b, c)); let unknown_right = hint::select_unpredictable(c4, d, hint::select_unpredictable(c3, b, c));
// Sort the last two unknown elements. // Sort the last two unknown elements.
let c5 = is_less(&*unknown_right, &*unknown_left); let c5 = is_less(&*unknown_right, &*unknown_left);
let lo = c5.select_unpredictable(unknown_right, unknown_left); let lo = hint::select_unpredictable(c5, unknown_right, unknown_left);
let hi = c5.select_unpredictable(unknown_left, unknown_right); let hi = hint::select_unpredictable(c5, unknown_left, unknown_right);
ptr::copy_nonoverlapping(min, dst, 1); ptr::copy_nonoverlapping(min, dst, 1);
ptr::copy_nonoverlapping(lo, dst.add(1), 1); ptr::copy_nonoverlapping(lo, dst.add(1), 1);

View file

@ -9,8 +9,14 @@ use std::path::PathBuf;
fn main() { fn main() {
if let Ok(rt) = tracked_env_var("LLVM_PROFILER_RT_LIB") { if let Ok(rt) = tracked_env_var("LLVM_PROFILER_RT_LIB") {
println!("cargo::rustc-link-lib=static:+verbatim={rt}"); let rt = PathBuf::from(rt);
return; if let Some(lib) = rt.file_name() {
if let Some(dir) = rt.parent() {
println!("cargo::rustc-link-search=native={}", dir.display());
}
println!("cargo::rustc-link-lib=static:+verbatim={}", lib.to_str().unwrap());
return;
}
} }
let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set"); let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set");

View file

@ -0,0 +1,43 @@
use crate::ffi::OsString;
use crate::{fmt, vec};
pub struct Args {
iter: vec::IntoIter<OsString>,
}
impl !Send for Args {}
impl !Sync for Args {}
impl Args {
pub(super) fn new(args: Vec<OsString>) -> Self {
Args { iter: args.into_iter() }
}
}
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.as_slice().fmt(f)
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.iter.len()
}
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> {
self.iter.next_back()
}
}

View file

@ -1,8 +1,12 @@
use crate::ffi::{CStr, OsString, c_char}; use crate::ffi::{CStr, OsString, c_char};
use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::ffi::OsStringExt;
use crate::ptr;
use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
use crate::sync::atomic::{AtomicIsize, AtomicPtr}; use crate::sync::atomic::{AtomicIsize, AtomicPtr};
use crate::{fmt, ptr, vec};
#[path = "common.rs"]
mod common;
pub use common::Args;
static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGC: AtomicIsize = AtomicIsize::new(0);
static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
@ -27,40 +31,5 @@ pub fn args() -> Args {
}) })
.collect(); .collect();
Args { iter: args.into_iter() } Args::new(args)
}
pub struct Args {
iter: vec::IntoIter<OsString>,
}
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.as_slice().fmt(f)
}
}
impl !Send for Args {}
impl !Sync for Args {}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.iter.len()
}
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> {
self.iter.next_back()
}
} }

View file

@ -0,0 +1,34 @@
//! Platform-dependent command line arguments abstraction.
#![forbid(unsafe_op_in_unsafe_fn)]
cfg_if::cfg_if! {
if #[cfg(all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))))] {
mod unix;
pub use unix::*;
} else if #[cfg(target_family = "windows")] {
mod windows;
pub use windows::*;
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use hermit::*;
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx;
pub use sgx::*;
} else if #[cfg(target_os = "uefi")] {
mod uefi;
pub use uefi::*;
} else if #[cfg(target_os = "wasi")] {
mod wasi;
pub use wasi::*;
} else if #[cfg(target_os = "xous")] {
mod xous;
pub use xous::*;
} else if #[cfg(target_os = "zkvm")] {
mod zkvm;
pub use zkvm::*;
} else {
mod unsupported;
pub use unsupported::*;
}
}

View file

@ -1,8 +1,10 @@
use super::abi::usercalls::alloc; #![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers
use super::abi::usercalls::raw::ByteBuffer;
use crate::ffi::OsString; use crate::ffi::OsString;
use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sys::os_str::Buf; use crate::sys::os_str::Buf;
use crate::sys::pal::abi::usercalls::alloc;
use crate::sys::pal::abi::usercalls::raw::ByteBuffer;
use crate::sys_common::FromInner; use crate::sys_common::FromInner;
use crate::{fmt, slice}; use crate::{fmt, slice};

View file

@ -1,14 +1,13 @@
use r_efi::protocols::loaded_image; use r_efi::protocols::loaded_image;
use super::helpers;
use crate::env::current_exe; use crate::env::current_exe;
use crate::ffi::OsString; use crate::ffi::OsString;
use crate::iter::Iterator; use crate::iter::Iterator;
use crate::{fmt, vec}; use crate::sys::pal::helpers;
pub struct Args { #[path = "common.rs"]
parsed_args_list: vec::IntoIter<OsString>, mod common;
} pub use common::Args;
pub fn args() -> Args { pub fn args() -> Args {
let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]); let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]);
@ -22,51 +21,17 @@ pub fn args() -> Args {
let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize; let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize;
// Break if we are sure that it cannot be UTF-16 // Break if we are sure that it cannot be UTF-16
if lp_size < size_of::<u16>() || lp_size % size_of::<u16>() != 0 { if lp_size < size_of::<u16>() || lp_size % size_of::<u16>() != 0 {
return Args { parsed_args_list: lazy_current_exe().into_iter() }; return Args::new(lazy_current_exe());
} }
let lp_size = lp_size / size_of::<u16>(); let lp_size = lp_size / size_of::<u16>();
let lp_cmd_line = unsafe { (*protocol.as_ptr()).load_options as *const u16 }; let lp_cmd_line = unsafe { (*protocol.as_ptr()).load_options as *const u16 };
if !lp_cmd_line.is_aligned() { if !lp_cmd_line.is_aligned() {
return Args { parsed_args_list: lazy_current_exe().into_iter() }; return Args::new(lazy_current_exe());
} }
let lp_cmd_line = unsafe { crate::slice::from_raw_parts(lp_cmd_line, lp_size) }; let lp_cmd_line = unsafe { crate::slice::from_raw_parts(lp_cmd_line, lp_size) };
Args { Args::new(parse_lp_cmd_line(lp_cmd_line).unwrap_or_else(lazy_current_exe))
parsed_args_list: parse_lp_cmd_line(lp_cmd_line)
.unwrap_or_else(lazy_current_exe)
.into_iter(),
}
}
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.parsed_args_list.as_slice().fmt(f)
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
self.parsed_args_list.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.parsed_args_list.size_hint()
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.parsed_args_list.len()
}
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> {
self.parsed_args_list.next_back()
}
} }
/// Implements the UEFI command-line argument parsing algorithm. /// Implements the UEFI command-line argument parsing algorithm.

View file

@ -5,13 +5,16 @@
#![allow(dead_code)] // runtime init functions not used during testing #![allow(dead_code)] // runtime init functions not used during testing
use crate::ffi::{CStr, OsString}; use crate::ffi::CStr;
use crate::os::unix::ffi::OsStringExt; use crate::os::unix::ffi::OsStringExt;
use crate::{fmt, vec};
#[path = "common.rs"]
mod common;
pub use common::Args;
/// One-time global initialization. /// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { pub unsafe fn init(argc: isize, argv: *const *const u8) {
imp::init(argc, argv) unsafe { imp::init(argc, argv) }
} }
/// Returns the command line arguments /// Returns the command line arguments
@ -55,42 +58,7 @@ pub fn args() -> Args {
vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec())); vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
} }
Args { iter: vec.into_iter() } Args::new(vec)
}
pub struct Args {
iter: vec::IntoIter<OsString>,
}
impl !Send for Args {}
impl !Sync for Args {}
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.as_slice().fmt(f)
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.iter.len()
}
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> {
self.iter.next_back()
}
} }
#[cfg(any( #[cfg(any(
@ -141,7 +109,7 @@ mod imp {
pub unsafe fn init(argc: isize, argv: *const *const u8) { pub unsafe fn init(argc: isize, argv: *const *const u8) {
// on GNU/Linux if we are main then we will init argv and argc twice, it "duplicates work" // on GNU/Linux if we are main then we will init argv and argc twice, it "duplicates work"
// BUT edge-cases are real: only using .init_array can break most emulators, dlopen, etc. // BUT edge-cases are real: only using .init_array can break most emulators, dlopen, etc.
really_init(argc, argv); unsafe { really_init(argc, argv) };
} }
/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension. /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
@ -159,9 +127,7 @@ mod imp {
argv: *const *const u8, argv: *const *const u8,
_envp: *const *const u8, _envp: *const *const u8,
) { ) {
unsafe { unsafe { really_init(argc as isize, argv) };
really_init(argc as isize, argv);
}
} }
init_wrapper init_wrapper
}; };
@ -228,16 +194,3 @@ mod imp {
(argc as isize, argv.cast()) (argc as isize, argv.cast())
} }
} }
#[cfg(any(target_os = "espidf", target_os = "vita"))]
mod imp {
use crate::ffi::c_char;
use crate::ptr;
#[inline(always)]
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
pub fn argc_argv() -> (isize, *const *const c_char) {
(0, ptr::null())
}
}

View file

@ -0,0 +1,29 @@
#![forbid(unsafe_op_in_unsafe_fn)]
use crate::ffi::{CStr, OsStr, OsString};
use crate::os::wasi::ffi::OsStrExt;
#[path = "common.rs"]
mod common;
pub use common::Args;
/// Returns the command line arguments
pub fn args() -> Args {
Args::new(maybe_args().unwrap_or(Vec::new()))
}
fn maybe_args() -> Option<Vec<OsString>> {
unsafe {
let (argc, buf_size) = wasi::args_sizes_get().ok()?;
let mut argv = Vec::with_capacity(argc);
let mut buf = Vec::with_capacity(buf_size);
wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?;
argv.set_len(argc);
let mut ret = Vec::with_capacity(argc);
for ptr in argv {
let s = CStr::from_ptr(ptr.cast());
ret.push(OsStr::from_bytes(s.to_bytes()).to_owned());
}
Some(ret)
}
}

View file

@ -6,17 +6,21 @@
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use super::ensure_no_nuls;
use super::os::current_exe;
use crate::ffi::{OsStr, OsString}; use crate::ffi::{OsStr, OsString};
use crate::num::NonZero; use crate::num::NonZero;
use crate::os::windows::prelude::*; use crate::os::windows::prelude::*;
use crate::path::{Path, PathBuf}; use crate::path::{Path, PathBuf};
use crate::sys::pal::os::current_exe;
use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf};
use crate::sys::path::get_long_path; use crate::sys::path::get_long_path;
use crate::sys::{c, to_u16s}; use crate::sys::{c, to_u16s};
use crate::sys_common::AsInner; use crate::sys_common::AsInner;
use crate::sys_common::wstr::WStrUnits; use crate::sys_common::wstr::WStrUnits;
use crate::{fmt, io, iter, vec}; use crate::{io, iter, ptr};
#[path = "common.rs"]
mod common;
pub use common::Args;
pub fn args() -> Args { pub fn args() -> Args {
// SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16 // SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16
@ -27,7 +31,7 @@ pub fn args() -> Args {
current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new()) current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new())
}); });
Args { parsed_args_list: parsed_args_list.into_iter() } Args::new(parsed_args_list)
} }
} }
@ -153,38 +157,6 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>(
ret_val ret_val
} }
pub struct Args {
parsed_args_list: vec::IntoIter<OsString>,
}
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.parsed_args_list.as_slice().fmt(f)
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
self.parsed_args_list.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.parsed_args_list.size_hint()
}
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> {
self.parsed_args_list.next_back()
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.parsed_args_list.len()
}
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum Arg { pub(crate) enum Arg {
/// Add quotes (if needed) /// Add quotes (if needed)
@ -384,9 +356,6 @@ pub(crate) fn to_user_path(path: &Path) -> io::Result<Vec<u16>> {
from_wide_to_user_path(to_u16s(path)?) from_wide_to_user_path(to_u16s(path)?)
} }
pub(crate) fn from_wide_to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> { pub(crate) fn from_wide_to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
use super::fill_utf16_buf;
use crate::ptr;
// UTF-16 encoded code points, used in parsing and building UTF-16 paths. // UTF-16 encoded code points, used in parsing and building UTF-16 paths.
// All of these are in the ASCII range so they can be cast directly to `u16`. // All of these are in the ASCII range so they can be cast directly to `u16`.
const SEP: u16 = b'\\' as _; const SEP: u16 = b'\\' as _;

View file

@ -0,0 +1,23 @@
use crate::sys::pal::os::get_application_parameters;
use crate::sys::pal::os::params::ArgumentList;
#[path = "common.rs"]
mod common;
pub use common::Args;
pub fn args() -> Args {
let Some(params) = get_application_parameters() else {
return Args::new(vec![]);
};
for param in params {
if let Ok(args) = ArgumentList::try_from(&param) {
let mut parsed_args = vec![];
for arg in args {
parsed_args.push(arg.into());
}
return Args::new(parsed_args);
}
}
Args::new(vec![])
}

View file

@ -1,7 +1,7 @@
use super::{WORD_SIZE, abi};
use crate::ffi::OsString; use crate::ffi::OsString;
use crate::fmt; use crate::fmt;
use crate::sys::os_str; use crate::sys::os_str;
use crate::sys::pal::{WORD_SIZE, abi};
use crate::sys_common::FromInner; use crate::sys_common::FromInner;
pub struct Args { pub struct Args {

View file

@ -71,9 +71,11 @@ const fn max_iov() -> usize {
target_os = "android", target_os = "android",
target_os = "dragonfly", target_os = "dragonfly",
target_os = "emscripten", target_os = "emscripten",
target_os = "espidf",
target_os = "freebsd", target_os = "freebsd",
target_os = "linux", target_os = "linux",
target_os = "netbsd", target_os = "netbsd",
target_os = "nuttx",
target_os = "nto", target_os = "nto",
target_os = "openbsd", target_os = "openbsd",
target_os = "horizon", target_os = "horizon",

View file

@ -20,6 +20,7 @@ cfg_if::cfg_if! {
mod windows; mod windows;
use windows as imp; use windows as imp;
pub use windows::{symlink_inner, junction_point}; pub use windows::{symlink_inner, junction_point};
use crate::sys::path::with_native_path;
} else if #[cfg(target_os = "hermit")] { } else if #[cfg(target_os = "hermit")] {
mod hermit; mod hermit;
use hermit as imp; use hermit as imp;
@ -39,7 +40,7 @@ cfg_if::cfg_if! {
} }
// FIXME: Replace this with platform-specific path conversion functions. // FIXME: Replace this with platform-specific path conversion functions.
#[cfg(not(target_family = "unix"))] #[cfg(not(any(target_family = "unix", target_os = "windows")))]
#[inline] #[inline]
pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> io::Result<T> { pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> io::Result<T> {
f(path) f(path)
@ -51,7 +52,7 @@ pub use imp::{
}; };
pub fn read_dir(path: &Path) -> io::Result<ReadDir> { pub fn read_dir(path: &Path) -> io::Result<ReadDir> {
// FIXME: use with_native_path // FIXME: use with_native_path on all platforms
imp::readdir(path) imp::readdir(path)
} }
@ -68,8 +69,11 @@ pub fn remove_dir(path: &Path) -> io::Result<()> {
} }
pub fn remove_dir_all(path: &Path) -> io::Result<()> { pub fn remove_dir_all(path: &Path) -> io::Result<()> {
// FIXME: use with_native_path // FIXME: use with_native_path on all platforms
imp::remove_dir_all(path) #[cfg(not(windows))]
return imp::remove_dir_all(path);
#[cfg(windows)]
with_native_path(path, &imp::remove_dir_all)
} }
pub fn read_link(path: &Path) -> io::Result<PathBuf> { pub fn read_link(path: &Path) -> io::Result<PathBuf> {
@ -77,6 +81,10 @@ pub fn read_link(path: &Path) -> io::Result<PathBuf> {
} }
pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
// FIXME: use with_native_path on all platforms
#[cfg(windows)]
return imp::symlink(original, link);
#[cfg(not(windows))]
with_native_path(original, &|original| { with_native_path(original, &|original| {
with_native_path(link, &|link| imp::symlink(original, link)) with_native_path(link, &|link| imp::symlink(original, link))
}) })
@ -105,11 +113,17 @@ pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
} }
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
// FIXME: use with_native_path // FIXME: use with_native_path on all platforms
imp::copy(from, to) #[cfg(not(windows))]
return imp::copy(from, to);
#[cfg(windows)]
with_native_path(from, &|from| with_native_path(to, &|to| imp::copy(from, to)))
} }
pub fn exists(path: &Path) -> io::Result<bool> { pub fn exists(path: &Path) -> io::Result<bool> {
// FIXME: use with_native_path // FIXME: use with_native_path on all platforms
imp::exists(path) #[cfg(not(windows))]
return imp::exists(path);
#[cfg(windows)]
with_native_path(path, &imp::exists)
} }

View file

@ -12,7 +12,7 @@ use crate::sync::Arc;
use crate::sys::handle::Handle; use crate::sys::handle::Handle;
use crate::sys::pal::api::{self, WinError, set_file_information_by_handle}; use crate::sys::pal::api::{self, WinError, set_file_information_by_handle};
use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul}; use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul};
use crate::sys::path::maybe_verbatim; use crate::sys::path::{WCStr, maybe_verbatim};
use crate::sys::time::SystemTime; use crate::sys::time::SystemTime;
use crate::sys::{Align8, c, cvt}; use crate::sys::{Align8, c, cvt};
use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::sys_common::{AsInner, FromInner, IntoInner};
@ -298,10 +298,12 @@ impl OpenOptions {
impl File { impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let path = maybe_verbatim(path)?; let path = maybe_verbatim(path)?;
// SAFETY: maybe_verbatim returns null-terminated strings
let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) };
Self::open_native(&path, opts) Self::open_native(&path, opts)
} }
fn open_native(path: &[u16], opts: &OpenOptions) -> io::Result<File> { fn open_native(path: &WCStr, opts: &OpenOptions) -> io::Result<File> {
let creation = opts.get_creation_mode()?; let creation = opts.get_creation_mode()?;
let handle = unsafe { let handle = unsafe {
c::CreateFileW( c::CreateFileW(
@ -1212,9 +1214,8 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
} }
} }
pub fn unlink(p: &Path) -> io::Result<()> { pub fn unlink(path: &WCStr) -> io::Result<()> {
let p_u16s = maybe_verbatim(p)?; if unsafe { c::DeleteFileW(path.as_ptr()) } == 0 {
if unsafe { c::DeleteFileW(p_u16s.as_ptr()) } == 0 {
let err = api::get_last_error(); let err = api::get_last_error();
// if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove // if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove
// the file while ignoring the readonly attribute. // the file while ignoring the readonly attribute.
@ -1223,7 +1224,7 @@ pub fn unlink(p: &Path) -> io::Result<()> {
let mut opts = OpenOptions::new(); let mut opts = OpenOptions::new();
opts.access_mode(c::DELETE); opts.access_mode(c::DELETE);
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT);
if let Ok(f) = File::open_native(&p_u16s, &opts) { if let Ok(f) = File::open_native(&path, &opts) {
if f.posix_delete().is_ok() { if f.posix_delete().is_ok() {
return Ok(()); return Ok(());
} }
@ -1236,10 +1237,7 @@ pub fn unlink(p: &Path) -> io::Result<()> {
} }
} }
pub fn rename(old: &Path, new: &Path) -> io::Result<()> { pub fn rename(old: &WCStr, new: &WCStr) -> io::Result<()> {
let old = maybe_verbatim(old)?;
let new = maybe_verbatim(new)?;
if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 { if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 {
let err = api::get_last_error(); let err = api::get_last_error();
// if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move // if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move
@ -1253,7 +1251,8 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
// Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation` // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation`
// This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size. // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size.
let Ok(new_len_without_nul_in_bytes): Result<u32, _> = ((new.len() - 1) * 2).try_into() let Ok(new_len_without_nul_in_bytes): Result<u32, _> =
((new.count_bytes() - 1) * 2).try_into()
else { else {
return Err(err).io_result(); return Err(err).io_result();
}; };
@ -1282,7 +1281,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
new.as_ptr().copy_to_nonoverlapping( new.as_ptr().copy_to_nonoverlapping(
(&raw mut (*file_rename_info).FileName).cast::<u16>(), (&raw mut (*file_rename_info).FileName).cast::<u16>(),
new.len(), new.count_bytes(),
); );
} }
@ -1309,20 +1308,19 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
Ok(()) Ok(())
} }
pub fn rmdir(p: &Path) -> io::Result<()> { pub fn rmdir(p: &WCStr) -> io::Result<()> {
let p = maybe_verbatim(p)?;
cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?; cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?;
Ok(()) Ok(())
} }
pub fn remove_dir_all(path: &Path) -> io::Result<()> { pub fn remove_dir_all(path: &WCStr) -> io::Result<()> {
// Open a file or directory without following symlinks. // Open a file or directory without following symlinks.
let mut opts = OpenOptions::new(); let mut opts = OpenOptions::new();
opts.access_mode(c::FILE_LIST_DIRECTORY); opts.access_mode(c::FILE_LIST_DIRECTORY);
// `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories. // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories.
// `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target. // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target.
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
let file = File::open(path, &opts)?; let file = File::open_native(path, &opts)?;
// Test if the file is not a directory or a symlink to a directory. // Test if the file is not a directory or a symlink to a directory.
if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 { if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 {
@ -1333,14 +1331,14 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> {
remove_dir_all_iterative(file).io_result() remove_dir_all_iterative(file).io_result()
} }
pub fn readlink(path: &Path) -> io::Result<PathBuf> { pub fn readlink(path: &WCStr) -> io::Result<PathBuf> {
// Open the link with no access mode, instead of generic read. // Open the link with no access mode, instead of generic read.
// By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so // By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so
// this is needed for a common case. // this is needed for a common case.
let mut opts = OpenOptions::new(); let mut opts = OpenOptions::new();
opts.access_mode(0); opts.access_mode(0);
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
let file = File::open(path, &opts)?; let file = File::open_native(&path, &opts)?;
file.readlink() file.readlink()
} }
@ -1378,19 +1376,17 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()>
} }
#[cfg(not(target_vendor = "uwp"))] #[cfg(not(target_vendor = "uwp"))]
pub fn link(original: &Path, link: &Path) -> io::Result<()> { pub fn link(original: &WCStr, link: &WCStr) -> io::Result<()> {
let original = maybe_verbatim(original)?;
let link = maybe_verbatim(link)?;
cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?; cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?;
Ok(()) Ok(())
} }
#[cfg(target_vendor = "uwp")] #[cfg(target_vendor = "uwp")]
pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { pub fn link(_original: &WCStr, _link: &WCStr) -> io::Result<()> {
return Err(io::const_error!(io::ErrorKind::Unsupported, "hard link are not supported on UWP")); return Err(io::const_error!(io::ErrorKind::Unsupported, "hard link are not supported on UWP"));
} }
pub fn stat(path: &Path) -> io::Result<FileAttr> { pub fn stat(path: &WCStr) -> io::Result<FileAttr> {
match metadata(path, ReparsePoint::Follow) { match metadata(path, ReparsePoint::Follow) {
Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => { Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => {
if let Ok(attrs) = lstat(path) { if let Ok(attrs) = lstat(path) {
@ -1404,7 +1400,7 @@ pub fn stat(path: &Path) -> io::Result<FileAttr> {
} }
} }
pub fn lstat(path: &Path) -> io::Result<FileAttr> { pub fn lstat(path: &WCStr) -> io::Result<FileAttr> {
metadata(path, ReparsePoint::Open) metadata(path, ReparsePoint::Open)
} }
@ -1420,7 +1416,7 @@ impl ReparsePoint {
} }
} }
fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> { fn metadata(path: &WCStr, reparse: ReparsePoint) -> io::Result<FileAttr> {
let mut opts = OpenOptions::new(); let mut opts = OpenOptions::new();
// No read or write permissions are necessary // No read or write permissions are necessary
opts.access_mode(0); opts.access_mode(0);
@ -1429,7 +1425,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
// Attempt to open the file normally. // Attempt to open the file normally.
// If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileExW`. // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileExW`.
// If the fallback fails for any reason we return the original error. // If the fallback fails for any reason we return the original error.
match File::open(path, &opts) { match File::open_native(&path, &opts) {
Ok(file) => file.file_attr(), Ok(file) => file.file_attr(),
Err(e) Err(e)
if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)] if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)]
@ -1442,8 +1438,6 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
// However, there are special system files, such as // However, there are special system files, such as
// `C:\hiberfil.sys`, that are locked in a way that denies even that. // `C:\hiberfil.sys`, that are locked in a way that denies even that.
unsafe { unsafe {
let path = maybe_verbatim(path)?;
// `FindFirstFileExW` accepts wildcard file names. // `FindFirstFileExW` accepts wildcard file names.
// Fortunately wildcards are not valid file names and // Fortunately wildcards are not valid file names and
// `ERROR_SHARING_VIOLATION` means the file exists (but is locked) // `ERROR_SHARING_VIOLATION` means the file exists (but is locked)
@ -1482,8 +1476,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
} }
} }
pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { pub fn set_perm(p: &WCStr, perm: FilePermissions) -> io::Result<()> {
let p = maybe_verbatim(p)?;
unsafe { unsafe {
cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?; cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?;
Ok(()) Ok(())
@ -1499,17 +1492,17 @@ fn get_path(f: &File) -> io::Result<PathBuf> {
) )
} }
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { pub fn canonicalize(p: &WCStr) -> io::Result<PathBuf> {
let mut opts = OpenOptions::new(); let mut opts = OpenOptions::new();
// No read or write permissions are necessary // No read or write permissions are necessary
opts.access_mode(0); opts.access_mode(0);
// This flag is so we can open directories too // This flag is so we can open directories too
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
let f = File::open(p, &opts)?; let f = File::open_native(p, &opts)?;
get_path(&f) get_path(&f)
} }
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { pub fn copy(from: &WCStr, to: &WCStr) -> io::Result<u64> {
unsafe extern "system" fn callback( unsafe extern "system" fn callback(
_TotalFileSize: i64, _TotalFileSize: i64,
_TotalBytesTransferred: i64, _TotalBytesTransferred: i64,
@ -1528,13 +1521,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
c::PROGRESS_CONTINUE c::PROGRESS_CONTINUE
} }
} }
let pfrom = maybe_verbatim(from)?;
let pto = maybe_verbatim(to)?;
let mut size = 0i64; let mut size = 0i64;
cvt(unsafe { cvt(unsafe {
c::CopyFileExW( c::CopyFileExW(
pfrom.as_ptr(), from.as_ptr(),
pto.as_ptr(), to.as_ptr(),
Some(callback), Some(callback),
(&raw mut size) as *mut _, (&raw mut size) as *mut _,
ptr::null_mut(), ptr::null_mut(),
@ -1624,14 +1615,14 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> {
} }
// Try to see if a file exists but, unlike `exists`, report I/O errors. // Try to see if a file exists but, unlike `exists`, report I/O errors.
pub fn exists(path: &Path) -> io::Result<bool> { pub fn exists(path: &WCStr) -> io::Result<bool> {
// Open the file to ensure any symlinks are followed to their target. // Open the file to ensure any symlinks are followed to their target.
let mut opts = OpenOptions::new(); let mut opts = OpenOptions::new();
// No read, write, etc access rights are needed. // No read, write, etc access rights are needed.
opts.access_mode(0); opts.access_mode(0);
// Backup semantics enables opening directories as well as files. // Backup semantics enables opening directories as well as files.
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
match File::open(path, &opts) { match File::open_native(path, &opts) {
Err(e) => match e.kind() { Err(e) => match e.kind() {
// The file definitely does not exist // The file definitely does not exist
io::ErrorKind::NotFound => Ok(false), io::ErrorKind::NotFound => Ok(false),

View file

@ -9,6 +9,7 @@ mod alloc;
mod personality; mod personality;
pub mod anonymous_pipe; pub mod anonymous_pipe;
pub mod args;
pub mod backtrace; pub mod backtrace;
pub mod cmath; pub mod cmath;
pub mod exit_guard; pub mod exit_guard;

View file

@ -1,5 +1,6 @@
use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t}; use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t};
#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
use crate::ffi::CStr; use crate::ffi::CStr;
use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Shutdown, SocketAddr}; use crate::net::{Shutdown, SocketAddr};

View file

@ -18,7 +18,6 @@
use crate::os::raw::c_char; use crate::os::raw::c_char;
pub mod args;
pub mod env; pub mod env;
pub mod futex; pub mod futex;
pub mod os; pub mod os;
@ -58,7 +57,7 @@ pub extern "C" fn __rust_abort() {
// NOTE: this is not guaranteed to run, for example when Rust code is called externally. // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
unsafe { unsafe {
args::init(argc, argv); crate::sys::args::init(argc, argv);
} }
} }

View file

@ -9,7 +9,6 @@ use crate::io::ErrorKind;
use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::atomic::{AtomicBool, Ordering};
pub mod abi; pub mod abi;
pub mod args;
pub mod env; pub mod env;
mod libunwind_integration; mod libunwind_integration;
pub mod os; pub mod os;
@ -24,7 +23,7 @@ pub mod waitqueue;
// NOTE: this is not guaranteed to run, for example when Rust code is called externally. // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
unsafe { unsafe {
args::init(argc, argv); crate::sys::args::init(argc, argv);
} }
} }

View file

@ -16,8 +16,6 @@ pub mod itron {
use super::unsupported; use super::unsupported;
} }
#[path = "../unsupported/args.rs"]
pub mod args;
pub mod env; pub mod env;
// `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as
// `crate::sys::error` // `crate::sys::error`

View file

@ -6,8 +6,6 @@
#![allow(unused_variables)] #![allow(unused_variables)]
#![allow(dead_code)] #![allow(dead_code)]
#[path = "../unsupported/args.rs"]
pub mod args;
#[path = "../unsupported/env.rs"] #[path = "../unsupported/env.rs"]
pub mod env; pub mod env;
//pub mod fd; //pub mod fd;

View file

@ -1,7 +1,5 @@
//! System bindings for the Trusty OS. //! System bindings for the Trusty OS.
#[path = "../unsupported/args.rs"]
pub mod args;
#[path = "../unsupported/common.rs"] #[path = "../unsupported/common.rs"]
#[deny(unsafe_op_in_unsafe_fn)] #[deny(unsafe_op_in_unsafe_fn)]
mod common; mod common;

View file

@ -13,7 +13,6 @@
//! [`OsString`]: crate::ffi::OsString //! [`OsString`]: crate::ffi::OsString
#![forbid(unsafe_op_in_unsafe_fn)] #![forbid(unsafe_op_in_unsafe_fn)]
pub mod args;
pub mod env; pub mod env;
pub mod helpers; pub mod helpers;
pub mod os; pub mod os;

View file

@ -6,7 +6,6 @@ use crate::io::ErrorKind;
#[macro_use] #[macro_use]
pub mod weak; pub mod weak;
pub mod args;
pub mod env; pub mod env;
#[cfg(target_os = "fuchsia")] #[cfg(target_os = "fuchsia")]
pub mod fuchsia; pub mod fuchsia;
@ -27,6 +26,7 @@ pub mod time;
pub fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {} pub fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
#[cfg(not(target_os = "espidf"))] #[cfg(not(target_os = "espidf"))]
#[cfg_attr(target_os = "vita", allow(unused_variables))]
// SAFETY: must be called only once during runtime initialization. // SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally. // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
// See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`. // See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`.
@ -47,7 +47,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
reset_sigpipe(sigpipe); reset_sigpipe(sigpipe);
stack_overflow::init(); stack_overflow::init();
args::init(argc, argv); #[cfg(not(target_os = "vita"))]
crate::sys::args::init(argc, argv);
// Normally, `thread::spawn` will call `Thread::set_name` but since this thread // Normally, `thread::spawn` will call `Thread::set_name` but since this thread
// already exists, we have to call it ourselves. We only do this on Apple targets // already exists, we have to call it ourselves. We only do this on Apple targets

View file

@ -1,6 +1,5 @@
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
pub mod args;
pub mod env; pub mod env;
pub mod os; pub mod os;
pub mod pipe; pub mod pipe;

View file

@ -1,61 +0,0 @@
#![forbid(unsafe_op_in_unsafe_fn)]
use crate::ffi::{CStr, OsStr, OsString};
use crate::os::wasi::ffi::OsStrExt;
use crate::{fmt, vec};
pub struct Args {
iter: vec::IntoIter<OsString>,
}
impl !Send for Args {}
impl !Sync for Args {}
/// Returns the command line arguments
pub fn args() -> Args {
Args { iter: maybe_args().unwrap_or(Vec::new()).into_iter() }
}
fn maybe_args() -> Option<Vec<OsString>> {
unsafe {
let (argc, buf_size) = wasi::args_sizes_get().ok()?;
let mut argv = Vec::with_capacity(argc);
let mut buf = Vec::with_capacity(buf_size);
wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?;
argv.set_len(argc);
let mut ret = Vec::with_capacity(argc);
for ptr in argv {
let s = CStr::from_ptr(ptr.cast());
ret.push(OsStr::from_bytes(s.to_bytes()).to_owned());
}
Some(ret)
}
}
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.iter.as_slice().fmt(f)
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.iter.len()
}
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> {
self.iter.next_back()
}
}

View file

@ -13,7 +13,6 @@
//! compiling for wasm. That way it's a compile time error for something that's //! compiling for wasm. That way it's a compile time error for something that's
//! guaranteed to be a runtime error! //! guaranteed to be a runtime error!
pub mod args;
pub mod env; pub mod env;
#[allow(unused)] #[allow(unused)]
#[path = "../wasm/atomics/futex.rs"] #[path = "../wasm/atomics/futex.rs"]

View file

@ -6,8 +6,6 @@
//! To begin with, this target mirrors the wasi target 1 to 1, but over //! To begin with, this target mirrors the wasi target 1 to 1, but over
//! time this will change significantly. //! time this will change significantly.
#[path = "../wasi/args.rs"]
pub mod args;
#[path = "../wasi/env.rs"] #[path = "../wasi/env.rs"]
pub mod env; pub mod env;
#[allow(unused)] #[allow(unused)]

View file

@ -16,8 +16,6 @@
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
#[path = "../unsupported/args.rs"]
pub mod args;
pub mod env; pub mod env;
#[path = "../unsupported/os.rs"] #[path = "../unsupported/os.rs"]
pub mod os; pub mod os;

View file

@ -14,7 +14,6 @@ pub mod compat;
pub mod api; pub mod api;
pub mod args;
pub mod c; pub mod c;
pub mod env; pub mod env;
#[cfg(not(target_vendor = "win7"))] #[cfg(not(target_vendor = "win7"))]

View file

@ -1,53 +0,0 @@
use crate::ffi::OsString;
use crate::sys::pal::xous::os::get_application_parameters;
use crate::sys::pal::xous::os::params::ArgumentList;
use crate::{fmt, vec};
pub struct Args {
parsed_args_list: vec::IntoIter<OsString>,
}
pub fn args() -> Args {
let Some(params) = get_application_parameters() else {
return Args { parsed_args_list: vec![].into_iter() };
};
for param in params {
if let Ok(args) = ArgumentList::try_from(&param) {
let mut parsed_args = vec![];
for arg in args {
parsed_args.push(arg.into());
}
return Args { parsed_args_list: parsed_args.into_iter() };
}
}
Args { parsed_args_list: vec![].into_iter() }
}
impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.parsed_args_list.as_slice().fmt(f)
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
self.parsed_args_list.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.parsed_args_list.size_hint()
}
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> {
self.parsed_args_list.next_back()
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.parsed_args_list.len()
}
}

View file

@ -1,6 +1,5 @@
#![forbid(unsafe_op_in_unsafe_fn)] #![forbid(unsafe_op_in_unsafe_fn)]
pub mod args;
#[path = "../unsupported/env.rs"] #[path = "../unsupported/env.rs"]
pub mod env; pub mod env;
pub mod os; pub mod os;

View file

@ -8,11 +8,9 @@
//! will likely change over time. //! will likely change over time.
#![forbid(unsafe_op_in_unsafe_fn)] #![forbid(unsafe_op_in_unsafe_fn)]
const WORD_SIZE: usize = size_of::<u32>(); pub const WORD_SIZE: usize = size_of::<u32>();
pub mod abi; pub mod abi;
#[path = "../zkvm/args.rs"]
pub mod args;
pub mod env; pub mod env;
pub mod os; pub mod os;
#[path = "../unsupported/pipe.rs"] #[path = "../unsupported/pipe.rs"]

View file

@ -10,6 +10,40 @@ mod tests;
pub const MAIN_SEP_STR: &str = "\\"; pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\'; pub const MAIN_SEP: char = '\\';
/// A null terminated wide string.
#[repr(transparent)]
pub struct WCStr([u16]);
impl WCStr {
/// Convert a slice to a WCStr without checks.
///
/// Though it is memory safe, the slice should also not contain interior nulls
/// as this may lead to unwanted truncation.
///
/// # Safety
///
/// The slice must end in a null.
pub unsafe fn from_wchars_with_null_unchecked(s: &[u16]) -> &Self {
unsafe { &*(s as *const [u16] as *const Self) }
}
pub fn as_ptr(&self) -> *const u16 {
self.0.as_ptr()
}
pub fn count_bytes(&self) -> usize {
self.0.len()
}
}
#[inline]
pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&WCStr) -> io::Result<T>) -> io::Result<T> {
let path = maybe_verbatim(path)?;
// SAFETY: maybe_verbatim returns null-terminated strings
let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) };
f(path)
}
#[inline] #[inline]
pub fn is_sep_byte(b: u8) -> bool { pub fn is_sep_byte(b: u8) -> bool {
b == b'/' || b == b'\\' b == b'/' || b == b'\\'

View file

@ -666,10 +666,11 @@ fn run_test_in_process(
io::set_output_capture(None); io::set_output_capture(None);
let test_result = match result { // Determine whether the test passed or failed, by comparing its panic
Ok(()) => calc_result(&desc, Ok(()), time_opts.as_ref(), exec_time.as_ref()), // payload (if any) with its `ShouldPanic` value, and by checking for
Err(e) => calc_result(&desc, Err(e.as_ref()), time_opts.as_ref(), exec_time.as_ref()), // fatal timeout.
}; let test_result =
calc_result(&desc, result.err().as_deref(), time_opts.as_ref(), exec_time.as_ref());
let stdout = data.lock().unwrap_or_else(|e| e.into_inner()).to_vec(); let stdout = data.lock().unwrap_or_else(|e| e.into_inner()).to_vec();
let message = CompletedTest::new(id, desc, test_result, exec_time, stdout); let message = CompletedTest::new(id, desc, test_result, exec_time, stdout);
monitor_ch.send(message).unwrap(); monitor_ch.send(message).unwrap();
@ -741,10 +742,7 @@ fn spawn_test_subprocess(
fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) -> ! { fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) -> ! {
let builtin_panic_hook = panic::take_hook(); let builtin_panic_hook = panic::take_hook();
let record_result = Arc::new(move |panic_info: Option<&'_ PanicHookInfo<'_>>| { let record_result = Arc::new(move |panic_info: Option<&'_ PanicHookInfo<'_>>| {
let test_result = match panic_info { let test_result = calc_result(&desc, panic_info.map(|info| info.payload()), None, None);
Some(info) => calc_result(&desc, Err(info.payload()), None, None),
None => calc_result(&desc, Ok(()), None, None),
};
// We don't support serializing TrFailedMsg, so just // We don't support serializing TrFailedMsg, so just
// print the message out to stderr. // print the message out to stderr.

View file

@ -39,15 +39,18 @@ pub enum TestResult {
/// Creates a `TestResult` depending on the raw result of test execution /// Creates a `TestResult` depending on the raw result of test execution
/// and associated data. /// and associated data.
pub(crate) fn calc_result<'a>( pub(crate) fn calc_result(
desc: &TestDesc, desc: &TestDesc,
task_result: Result<(), &'a (dyn Any + 'static + Send)>, panic_payload: Option<&(dyn Any + Send)>,
time_opts: Option<&time::TestTimeOptions>, time_opts: Option<&time::TestTimeOptions>,
exec_time: Option<&time::TestExecTime>, exec_time: Option<&time::TestExecTime>,
) -> TestResult { ) -> TestResult {
let result = match (&desc.should_panic, task_result) { let result = match (desc.should_panic, panic_payload) {
(&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk, // The test did or didn't panic, as expected.
(&ShouldPanic::YesWithMessage(msg), Err(err)) => { (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestResult::TrOk,
// Check the actual panic message against the expected message.
(ShouldPanic::YesWithMessage(msg), Some(err)) => {
let maybe_panic_str = err let maybe_panic_str = err
.downcast_ref::<String>() .downcast_ref::<String>()
.map(|e| &**e) .map(|e| &**e)
@ -71,10 +74,14 @@ pub(crate) fn calc_result<'a>(
)) ))
} }
} }
(&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => {
// The test should have panicked, but didn't panic.
(ShouldPanic::Yes, None) | (ShouldPanic::YesWithMessage(_), None) => {
TestResult::TrFailedMsg("test did not panic as expected".to_string()) TestResult::TrFailedMsg("test did not panic as expected".to_string())
} }
_ => TestResult::TrFailed,
// The test should not have panicked, but did panic.
(ShouldPanic::No, Some(_)) => TestResult::TrFailed,
}; };
// If test is already failed (or allowed to fail), do not change the result. // If test is already failed (or allowed to fail), do not change the result.

View file

@ -563,9 +563,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.5" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [ dependencies = [
"adler2", "adler2",
] ]

View file

@ -101,6 +101,7 @@ for more details.
| `normalize-stdout` | Normalize actual stdout with a rule `"<raw>" -> "<normalized>"` before comparing against snapshot | `ui`, `incremental` | `"<RAW>" -> "<NORMALIZED>"`, `<RAW>`/`<NORMALIZED>` is regex capture and replace syntax | | `normalize-stdout` | Normalize actual stdout with a rule `"<raw>" -> "<normalized>"` before comparing against snapshot | `ui`, `incremental` | `"<RAW>" -> "<NORMALIZED>"`, `<RAW>`/`<NORMALIZED>` is regex capture and replace syntax |
| `dont-check-compiler-stderr` | Don't check actual compiler stderr vs stderr snapshot | `ui` | N/A | | `dont-check-compiler-stderr` | Don't check actual compiler stderr vs stderr snapshot | `ui` | N/A |
| `dont-check-compiler-stdout` | Don't check actual compiler stdout vs stdout snapshot | `ui` | N/A | | `dont-check-compiler-stdout` | Don't check actual compiler stdout vs stdout snapshot | `ui` | N/A |
| `dont-require-annotations` | Don't require line annotations for the given diagnostic kind (`//~ KIND`) to be exhaustive | `ui`, `incremental` | `ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` |
| `run-rustfix` | Apply all suggestions via `rustfix`, snapshot fixed output, and check fixed output builds | `ui` | N/A | | `run-rustfix` | Apply all suggestions via `rustfix`, snapshot fixed output, and check fixed output builds | `ui` | N/A |
| `rustfix-only-machine-applicable` | `run-rustfix` but only machine-applicable suggestions | `ui` | N/A | | `rustfix-only-machine-applicable` | `run-rustfix` but only machine-applicable suggestions | `ui` | N/A |
| `exec-env` | Env var to set when executing a test | `ui`, `crashes` | `<KEY>=<VALUE>` | | `exec-env` | Env var to set when executing a test | `ui`, `crashes` | `<KEY>=<VALUE>` |

View file

@ -303,8 +303,7 @@ It should be preferred to using `error-pattern`, which is imprecise and non-exha
### `error-pattern` ### `error-pattern`
The `error-pattern` [directive](directives.md) can be used for runtime messages, which don't The `error-pattern` [directive](directives.md) can be used for runtime messages, which don't
have a specific span, or for compile time messages if imprecise matching is required due to have a specific span, or in exceptional cases for compile time messages.
multi-line platform specific diagnostics.
Let's think about this test: Let's think about this test:
@ -318,7 +317,7 @@ fn main() {
``` ```
We want to ensure this shows "index out of bounds" but we cannot use the `ERROR` We want to ensure this shows "index out of bounds" but we cannot use the `ERROR`
annotation since the error doesn't have any span. Then it's time to use the annotation since the runtime error doesn't have any span. Then it's time to use the
`error-pattern` directive: `error-pattern` directive:
```rust,ignore ```rust,ignore
@ -331,29 +330,51 @@ fn main() {
} }
``` ```
But for strict testing, try to use the `ERROR` annotation as much as possible, Use of `error-pattern` is not recommended in general.
including `//~?` annotations for diagnostics without span.
For compile time diagnostics `error-pattern` should very rarely be necessary.
Per-line annotations (`//~`) are still checked in tests using `error-pattern`. For strict testing of compile time output, try to use the line annotations `//~` as much as
To opt out of these checks, use `//@ compile-flags: --error-format=human`. possible, including `//~?` annotations for diagnostics without span.
Do that only in exceptional cases.
### Error levels If the compile time output is target dependent or too verbose, use directive
`//@ dont-require-annotations: <diagnostic-kind>` to make the line annotation checking
non-exhaustive, some of the compiler messages can stay uncovered by annotations in this mode.
The error levels that you can have are: For checking runtime output `//@ check-run-results` may be preferable.
Only use `error-pattern` if none of the above works.
Line annotations `//~` are still checked in tests using `error-pattern`.
In exceptional cases use `//@ compile-flags: --error-format=human` to opt out of these checks.
### Diagnostic kinds (error levels)
The diagnostic kinds that you can have are:
- `ERROR` - `ERROR`
- `WARN` or `WARNING` - `WARN` (or `WARNING`)
- `NOTE` - `NOTE`
- `HELP` and `SUGGESTION` - `HELP`
- `SUGGESTION`
You are allowed to not include a level, but you should include it at least for The `SUGGESTION` kind is used for specifying what the expected replacement text
the primary message.
The `SUGGESTION` level is used for specifying what the expected replacement text
should be for a diagnostic suggestion. should be for a diagnostic suggestion.
`ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations
`//~` by default.
Other kinds only need to be line-annotated if at least one annotation of that kind appears
in the test file. For example, one `//~ NOTE` will also require all other `//~ NOTE`s in the file
to be written out explicitly.
Use directive `//@ dont-require-annotations` to opt out of exhaustive annotations.
E.g. use `//@ dont-require-annotations: NOTE` to annotate notes selectively.
Avoid using this directive for `ERROR`s and `WARN`ings, unless there's a serious reason, like
target-dependent compiler output.
Missing diagnostic kinds (`//~ message`) are currently accepted, but are being phased away.
They will match any compiler output kind, but will not force exhaustive annotations for that kind.
Prefer explicit kind and `//@ dont-require-annotations` to achieve the same effect.
UI tests use the `-A unused` flag by default to ignore all unused warnings, as UI tests use the `-A unused` flag by default to ignore all unused warnings, as
unused warnings are usually not the focus of a test. However, simple code unused warnings are usually not the focus of a test. However, simple code
samples often have unused warnings. If the test is specifically testing an samples often have unused warnings. If the test is specifically testing an

View file

@ -65,32 +65,33 @@ impl Tool {
nightly_branch, nightly_branch,
} = &self.config; } = &self.config;
file_content.push_str(&format!("dist_server={}", dist_server)); file_content.push_str(&format!("dist_server={}\n", dist_server));
file_content.push_str(&format!("\nartifacts_server={}", artifacts_server)); file_content.push_str(&format!("artifacts_server={}\n", artifacts_server));
file_content.push_str(&format!( file_content.push_str(&format!(
"\nartifacts_with_llvm_assertions_server={}", "artifacts_with_llvm_assertions_server={}\n",
artifacts_with_llvm_assertions_server artifacts_with_llvm_assertions_server
)); ));
file_content.push_str(&format!("\ngit_merge_commit_email={}", git_merge_commit_email)); file_content.push_str(&format!("git_merge_commit_email={}\n", git_merge_commit_email));
file_content.push_str(&format!("\ngit_repository={}", git_repository)); file_content.push_str(&format!("git_repository={}\n", git_repository));
file_content.push_str(&format!("\nnightly_branch={}", nightly_branch)); file_content.push_str(&format!("nightly_branch={}\n", nightly_branch));
file_content.push_str("\n\n"); file_content.push_str("\n");
file_content.push_str(COMMENTS); file_content.push_str(COMMENTS);
file_content.push_str("\n");
let compiler = self.detect_compiler()?; let compiler = self.detect_compiler()?;
file_content.push_str(&format!("\ncompiler_date={}", compiler.date)); file_content.push_str(&format!("compiler_date={}\n", compiler.date));
file_content.push_str(&format!("\ncompiler_version={}", compiler.version)); file_content.push_str(&format!("compiler_version={}\n", compiler.version));
if let Some(rustfmt) = self.detect_rustfmt()? { if let Some(rustfmt) = self.detect_rustfmt()? {
file_content.push_str(&format!("\nrustfmt_date={}", rustfmt.date)); file_content.push_str(&format!("rustfmt_date={}\n", rustfmt.date));
file_content.push_str(&format!("\nrustfmt_version={}", rustfmt.version)); file_content.push_str(&format!("rustfmt_version={}\n", rustfmt.version));
} }
file_content.push_str("\n"); file_content.push_str("\n");
for (key, value) in self.checksums { for (key, value) in self.checksums {
file_content.push_str(&format!("\n{}={}", key, value)); file_content.push_str(&format!("{}={}\n", key, value));
} }
std::fs::write(PATH, file_content)?; std::fs::write(PATH, file_content)?;

View file

@ -1,4 +1,4 @@
use std::collections::{HashMap, HashSet}; use std::collections::HashSet;
use std::env; use std::env;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
@ -198,7 +198,7 @@ pub struct TestProps {
/// that don't otherwise want/need `-Z build-std`. /// that don't otherwise want/need `-Z build-std`.
pub add_core_stubs: bool, pub add_core_stubs: bool,
/// Whether line annotatins are required for the given error kind. /// Whether line annotatins are required for the given error kind.
pub require_annotations: HashMap<ErrorKind, bool>, pub dont_require_annotations: HashSet<ErrorKind>,
} }
mod directives { mod directives {
@ -301,13 +301,7 @@ impl TestProps {
no_auto_check_cfg: false, no_auto_check_cfg: false,
has_enzyme: false, has_enzyme: false,
add_core_stubs: false, add_core_stubs: false,
require_annotations: HashMap::from([ dont_require_annotations: Default::default(),
(ErrorKind::Help, true),
(ErrorKind::Note, true),
(ErrorKind::Error, true),
(ErrorKind::Warning, true),
(ErrorKind::Suggestion, false),
]),
} }
} }
@ -593,8 +587,8 @@ impl TestProps {
if let Some(err_kind) = if let Some(err_kind) =
config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
{ {
self.require_annotations self.dont_require_annotations
.insert(ErrorKind::expect_from_user_str(&err_kind), false); .insert(ErrorKind::expect_from_user_str(err_kind.trim()));
} }
}, },
); );

View file

@ -22,7 +22,7 @@ use crate::common::{
output_base_dir, output_base_name, output_testname_unique, output_base_dir, output_base_name, output_testname_unique,
}; };
use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
use crate::errors::{self, Error, ErrorKind}; use crate::errors::{Error, ErrorKind};
use crate::header::TestProps; use crate::header::TestProps;
use crate::read2::{Truncated, read2_abbreviated}; use crate::read2::{Truncated, read2_abbreviated};
use crate::util::{PathBufExt, add_dylib_path, logv, static_regex}; use crate::util::{PathBufExt, add_dylib_path, logv, static_regex};
@ -675,7 +675,7 @@ impl<'test> TestCx<'test> {
} }
} }
fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &ProcRes) { fn check_expected_errors(&self, expected_errors: Vec<Error>, proc_res: &ProcRes) {
debug!( debug!(
"check_expected_errors: expected_errors={:?} proc_res.status={:?}", "check_expected_errors: expected_errors={:?} proc_res.status={:?}",
expected_errors, proc_res.status expected_errors, proc_res.status
@ -710,8 +710,12 @@ impl<'test> TestCx<'test> {
self.testpaths.file.display().to_string() self.testpaths.file.display().to_string()
}; };
let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help)); // Errors and warnings are always expected, other diagnostics are only expected
let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note)); // if one of them actually occurs in the test.
let expected_kinds: HashSet<_> = [ErrorKind::Error, ErrorKind::Warning]
.into_iter()
.chain(expected_errors.iter().filter_map(|e| e.kind))
.collect();
// Parse the JSON output from the compiler and extract out the messages. // Parse the JSON output from the compiler and extract out the messages.
let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res); let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
@ -737,8 +741,11 @@ impl<'test> TestCx<'test> {
} }
None => { None => {
// If the test is a known bug, don't require that the error is annotated if actual_error.require_annotation
if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note) && actual_error.kind.map_or(false, |kind| {
expected_kinds.contains(&kind)
&& !self.props.dont_require_annotations.contains(&kind)
})
{ {
self.error(&format!( self.error(&format!(
"{}:{}: unexpected {}: '{}'", "{}:{}: unexpected {}: '{}'",
@ -796,27 +803,6 @@ impl<'test> TestCx<'test> {
} }
} }
/// Returns `true` if we should report an error about `actual_error`,
/// which did not match any of the expected error.
fn is_unexpected_compiler_message(
&self,
actual_error: &Error,
expect_help: bool,
expect_note: bool,
) -> bool {
actual_error.require_annotation
&& actual_error.kind.map_or(false, |err_kind| {
// If the test being checked doesn't contain any "help" or "note" annotations, then
// we don't require annotating "help" or "note" (respecively) diagnostics at all.
let default_require_annotations = self.props.require_annotations[&err_kind];
match err_kind {
ErrorKind::Help => expect_help && default_require_annotations,
ErrorKind::Note => expect_note && default_require_annotations,
_ => default_require_annotations,
}
})
}
fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit { fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit {
match (pm, self.props.fail_mode, self.config.mode) { match (pm, self.props.fail_mode, self.config.mode) {
(Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => Emit::Metadata, (Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => Emit::Metadata,

View file

@ -156,9 +156,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.7" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [ dependencies = [
"adler2", "adler2",
] ]

View file

@ -981,9 +981,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.7" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [ dependencies = [
"adler2", "adler2",
] ]

View file

@ -1,8 +1,11 @@
//@ revisions: OPT2 OPT3 //@ revisions: OPT2 OPT3 OPT3_S390X
//@[OPT2] compile-flags: -Copt-level=2 //@[OPT2] compile-flags: -Copt-level=2
//@[OPT3] compile-flags: -C opt-level=3 //@[OPT3] compile-flags: -C opt-level=3
// some targets don't do the opt we are looking for // some targets don't do the opt we are looking for
//@[OPT3] only-64bit //@[OPT3] only-64bit
//@[OPT3] ignore-s390x
//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13
//@[OPT3_S390X] only-s390x
#![crate_type = "lib"] #![crate_type = "lib"]
#![no_std] #![no_std]
@ -17,6 +20,10 @@
// OPT3-NEXT: call <8 x i16> @llvm.bswap // OPT3-NEXT: call <8 x i16> @llvm.bswap
// OPT3-NEXT: store <8 x i16> // OPT3-NEXT: store <8 x i16>
// OPT3-NEXT: ret void // OPT3-NEXT: ret void
// OPT3_S390X: load <8 x i16>
// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap
// OPT3_S390X-NEXT: store <8 x i16>
// OPT3_S390X-NEXT: ret void
#[no_mangle] #[no_mangle]
pub fn convert(value: [u16; 8]) -> [u8; 16] { pub fn convert(value: [u16; 8]) -> [u8; 16] {
#[cfg(target_endian = "little")] #[cfg(target_endian = "little")]

View file

@ -46,21 +46,21 @@ pub fn test_zst(p: bool, a: (), b: ()) -> () {
pub fn test_int2(p: bool, a: u64, b: u64) -> u64 { pub fn test_int2(p: bool, a: u64, b: u64) -> u64 {
// CHECK-LABEL: define{{.*}} @test_int2 // CHECK-LABEL: define{{.*}} @test_int2
// CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable // CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable
p.select_unpredictable(a, b) core::hint::select_unpredictable(p, a, b)
} }
#[no_mangle] #[no_mangle]
pub fn test_pair2(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) { pub fn test_pair2(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) {
// CHECK-LABEL: define{{.*}} @test_pair2 // CHECK-LABEL: define{{.*}} @test_pair2
// CHECK: select i1 %p, {{.*}}, !unpredictable // CHECK: select i1 %p, {{.*}}, !unpredictable
p.select_unpredictable(a, b) core::hint::select_unpredictable(p, a, b)
} }
#[no_mangle] #[no_mangle]
pub fn test_struct2(p: bool, a: Large, b: Large) -> Large { pub fn test_struct2(p: bool, a: Large, b: Large) -> Large {
// CHECK-LABEL: define{{.*}} @test_struct2 // CHECK-LABEL: define{{.*}} @test_struct2
// CHECK: select i1 %p, {{.*}}, !unpredictable // CHECK: select i1 %p, {{.*}}, !unpredictable
p.select_unpredictable(a, b) core::hint::select_unpredictable(p, a, b)
} }
#[no_mangle] #[no_mangle]
@ -68,5 +68,5 @@ pub fn test_zst2(p: bool, a: (), b: ()) -> () {
// CHECK-LABEL: define{{.*}} @test_zst2 // CHECK-LABEL: define{{.*}} @test_zst2
// CHECK-NEXT: start: // CHECK-NEXT: start:
// CHECK-NEXT: ret void // CHECK-NEXT: ret void
p.select_unpredictable(a, b) core::hint::select_unpredictable(p, a, b)
} }

View file

@ -1,4 +1,5 @@
//@ edition:2018 //@ edition:2018
//@ dont-require-annotations: SUGGESTION
fn take_u32(_x: u32) {} fn take_u32(_x: u32) {}

View file

@ -1,5 +1,5 @@
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:12:14 --> $DIR/suggest-missing-await.rs:13:14
| |
LL | take_u32(x) LL | take_u32(x)
| -------- ^ expected `u32`, found future | -------- ^ expected `u32`, found future
@ -7,12 +7,12 @@ LL | take_u32(x)
| arguments to this function are incorrect | arguments to this function are incorrect
| |
note: calling an async function returns a future note: calling an async function returns a future
--> $DIR/suggest-missing-await.rs:12:14 --> $DIR/suggest-missing-await.rs:13:14
| |
LL | take_u32(x) LL | take_u32(x)
| ^ | ^
note: function defined here note: function defined here
--> $DIR/suggest-missing-await.rs:3:4 --> $DIR/suggest-missing-await.rs:4:4
| |
LL | fn take_u32(_x: u32) {} LL | fn take_u32(_x: u32) {}
| ^^^^^^^^ ------- | ^^^^^^^^ -------
@ -22,13 +22,13 @@ LL | take_u32(x.await)
| ++++++ | ++++++
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:22:5 --> $DIR/suggest-missing-await.rs:23:5
| |
LL | dummy() LL | dummy()
| ^^^^^^^ expected `()`, found future | ^^^^^^^ expected `()`, found future
| |
note: calling an async function returns a future note: calling an async function returns a future
--> $DIR/suggest-missing-await.rs:22:5 --> $DIR/suggest-missing-await.rs:23:5
| |
LL | dummy() LL | dummy()
| ^^^^^^^ | ^^^^^^^
@ -42,7 +42,7 @@ LL | dummy();
| + | +
error[E0308]: `if` and `else` have incompatible types error[E0308]: `if` and `else` have incompatible types
--> $DIR/suggest-missing-await.rs:35:9 --> $DIR/suggest-missing-await.rs:36:9
| |
LL | let _x = if true { LL | let _x = if true {
| ______________- | ______________-
@ -64,7 +64,7 @@ LL | dummy().await
| ++++++ | ++++++
error[E0308]: `match` arms have incompatible types error[E0308]: `match` arms have incompatible types
--> $DIR/suggest-missing-await.rs:45:14 --> $DIR/suggest-missing-await.rs:46:14
| |
LL | let _x = match 0usize { LL | let _x = match 0usize {
| ______________- | ______________-
@ -87,7 +87,7 @@ LL ~ 1 => dummy().await,
| |
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:53:9 --> $DIR/suggest-missing-await.rs:54:9
| |
LL | let _x = match dummy() { LL | let _x = match dummy() {
| ------- this expression has type `impl Future<Output = ()>` | ------- this expression has type `impl Future<Output = ()>`
@ -102,7 +102,7 @@ LL | let _x = match dummy().await {
| ++++++ | ++++++
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:67:9 --> $DIR/suggest-missing-await.rs:68:9
| |
LL | match dummy_result() { LL | match dummy_result() {
| -------------- this expression has type `impl Future<Output = Result<(), ()>>` | -------------- this expression has type `impl Future<Output = Result<(), ()>>`
@ -118,7 +118,7 @@ LL | match dummy_result().await {
| ++++++ | ++++++
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:69:9 --> $DIR/suggest-missing-await.rs:70:9
| |
LL | match dummy_result() { LL | match dummy_result() {
| -------------- this expression has type `impl Future<Output = Result<(), ()>>` | -------------- this expression has type `impl Future<Output = Result<(), ()>>`
@ -134,7 +134,7 @@ LL | match dummy_result().await {
| ++++++ | ++++++
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:77:27 --> $DIR/suggest-missing-await.rs:78:27
| |
LL | Some(do_async()).map(|()| {}); LL | Some(do_async()).map(|()| {});
| ^^ | ^^

View file

@ -1,3 +1,5 @@
//@ dont-require-annotations: SUGGESTION
fn main() { fn main() {
let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool` let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool`
//~| HELP compare with zero instead //~| HELP compare with zero instead

View file

@ -1,5 +1,5 @@
error[E0054]: cannot cast `i32` as `bool` error[E0054]: cannot cast `i32` as `bool`
--> $DIR/cast-as-bool.rs:2:13 --> $DIR/cast-as-bool.rs:4:13
| |
LL | let u = 5 as bool; LL | let u = 5 as bool;
| ^^^^^^^^^ | ^^^^^^^^^
@ -11,7 +11,7 @@ LL + let u = 5 != 0;
| |
error[E0054]: cannot cast `i32` as `bool` error[E0054]: cannot cast `i32` as `bool`
--> $DIR/cast-as-bool.rs:6:13 --> $DIR/cast-as-bool.rs:8:13
| |
LL | let t = (1 + 2) as bool; LL | let t = (1 + 2) as bool;
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
@ -23,7 +23,7 @@ LL + let t = (1 + 2) != 0;
| |
error[E0054]: cannot cast `u32` as `bool` error[E0054]: cannot cast `u32` as `bool`
--> $DIR/cast-as-bool.rs:10:13 --> $DIR/cast-as-bool.rs:12:13
| |
LL | let _ = 5_u32 as bool; LL | let _ = 5_u32 as bool;
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
@ -35,7 +35,7 @@ LL + let _ = 5_u32 != 0;
| |
error[E0054]: cannot cast `f64` as `bool` error[E0054]: cannot cast `f64` as `bool`
--> $DIR/cast-as-bool.rs:13:13 --> $DIR/cast-as-bool.rs:15:13
| |
LL | let _ = 64.0_f64 as bool; LL | let _ = 64.0_f64 as bool;
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
@ -47,43 +47,43 @@ LL + let _ = 64.0_f64 != 0;
| |
error[E0054]: cannot cast `IntEnum` as `bool` error[E0054]: cannot cast `IntEnum` as `bool`
--> $DIR/cast-as-bool.rs:24:13 --> $DIR/cast-as-bool.rs:26:13
| |
LL | let _ = IntEnum::One as bool; LL | let _ = IntEnum::One as bool;
| ^^^^^^^^^^^^^^^^^^^^ unsupported cast | ^^^^^^^^^^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `fn(u8) -> String {uwu}` as `bool` error[E0054]: cannot cast `fn(u8) -> String {uwu}` as `bool`
--> $DIR/cast-as-bool.rs:33:13 --> $DIR/cast-as-bool.rs:35:13
| |
LL | let _ = uwu as bool; LL | let _ = uwu as bool;
| ^^^^^^^^^^^ unsupported cast | ^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `unsafe fn() {owo}` as `bool` error[E0054]: cannot cast `unsafe fn() {owo}` as `bool`
--> $DIR/cast-as-bool.rs:35:13 --> $DIR/cast-as-bool.rs:37:13
| |
LL | let _ = owo as bool; LL | let _ = owo as bool;
| ^^^^^^^^^^^ unsupported cast | ^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `fn(u8) -> String` as `bool` error[E0054]: cannot cast `fn(u8) -> String` as `bool`
--> $DIR/cast-as-bool.rs:38:13 --> $DIR/cast-as-bool.rs:40:13
| |
LL | let _ = uwu as fn(u8) -> String as bool; LL | let _ = uwu as fn(u8) -> String as bool;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsupported cast | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `char` as `bool` error[E0054]: cannot cast `char` as `bool`
--> $DIR/cast-as-bool.rs:40:13 --> $DIR/cast-as-bool.rs:42:13
| |
LL | let _ = 'x' as bool; LL | let _ = 'x' as bool;
| ^^^^^^^^^^^ unsupported cast | ^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `*const ()` as `bool` error[E0054]: cannot cast `*const ()` as `bool`
--> $DIR/cast-as-bool.rs:44:13 --> $DIR/cast-as-bool.rs:46:13
| |
LL | let _ = ptr as bool; LL | let _ = ptr as bool;
| ^^^^^^^^^^^ unsupported cast | ^^^^^^^^^^^ unsupported cast
error[E0606]: casting `&'static str` as `bool` is invalid error[E0606]: casting `&'static str` as `bool` is invalid
--> $DIR/cast-as-bool.rs:46:13 --> $DIR/cast-as-bool.rs:48:13
| |
LL | let v = "hello" as bool; LL | let v = "hello" as bool;
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^

View file

@ -1,6 +1,6 @@
// Error, the linked empty library is `no_std` and doesn't provide a panic handler. // Error, the linked empty library is `no_std` and doesn't provide a panic handler.
//@ dont-require-annotations:ERROR //@ dont-require-annotations: ERROR
//@ dont-check-compiler-stderr //@ dont-check-compiler-stderr
//@ aux-build: cfg_false_lib_no_std_before.rs //@ aux-build: cfg_false_lib_no_std_before.rs

View file

@ -19,6 +19,7 @@ fn fn_mut() -> _ {
let x = String::new(); let x = String::new();
//~^ HELP: consider changing this to be mutable //~^ HELP: consider changing this to be mutable
//~| NOTE binding `x` declared here //~| NOTE binding `x` declared here
//~| SUGGESTION mut
|c| { //~ NOTE: value captured here |c| { //~ NOTE: value captured here
x.push(c); x.push(c);
//~^ ERROR: does not live long enough //~^ ERROR: does not live long enough

View file

@ -21,7 +21,7 @@ LL | fn fn_mut() -> _ {
= note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
--> $DIR/suggest-return-closure.rs:32:13 --> $DIR/suggest-return-closure.rs:33:13
| |
LL | fn fun() -> _ { LL | fn fun() -> _ {
| ^ | ^
@ -32,7 +32,7 @@ LL | fn fun() -> _ {
= note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html = note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> $DIR/suggest-return-closure.rs:23:9 --> $DIR/suggest-return-closure.rs:24:9
| |
LL | x.push(c); LL | x.push(c);
| ^ cannot borrow as mutable | ^ cannot borrow as mutable
@ -43,7 +43,7 @@ LL | let mut x = String::new();
| +++ | +++
error[E0597]: `x` does not live long enough error[E0597]: `x` does not live long enough
--> $DIR/suggest-return-closure.rs:23:9 --> $DIR/suggest-return-closure.rs:24:9
| |
LL | let x = String::new(); LL | let x = String::new();
| - binding `x` declared here | - binding `x` declared here

View file

@ -1,6 +1,6 @@
// ignore-tidy-linelength // ignore-tidy-linelength
//@ build-fail //@ build-fail
//@ dont-require-annotations:ERROR //@ dont-require-annotations: ERROR
//@ dont-check-compiler-stderr //@ dont-check-compiler-stderr
//@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind.rs
//@ aux-build:panic-runtime-unwind2.rs //@ aux-build:panic-runtime-unwind2.rs

View file

@ -1,6 +1,6 @@
// ignore-tidy-linelength // ignore-tidy-linelength
//@ build-fail //@ build-fail
//@ dont-require-annotations:ERROR //@ dont-require-annotations: ERROR
//@ dont-check-compiler-stderr //@ dont-check-compiler-stderr
//@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind.rs
//@ compile-flags:-C panic=abort //@ compile-flags:-C panic=abort

View file

@ -1,6 +1,6 @@
// ignore-tidy-linelength // ignore-tidy-linelength
//@ build-fail //@ build-fail
//@ dont-require-annotations:ERROR //@ dont-require-annotations: ERROR
//@ dont-check-compiler-stderr //@ dont-check-compiler-stderr
//@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind.rs
//@ aux-build:wants-panic-runtime-unwind.rs //@ aux-build:wants-panic-runtime-unwind.rs

View file

@ -1,3 +1,5 @@
//@ dont-require-annotations: SUGGESTION
struct S; struct S;
impl S { impl S {

View file

@ -1,5 +1,5 @@
error: expected one of `:`, `@`, or `|`, found `bar` error: expected one of `:`, `@`, or `|`, found `bar`
--> $DIR/inverted-parameters.rs:4:24 --> $DIR/inverted-parameters.rs:6:24
| |
LL | fn foo(&self, &str bar) {} LL | fn foo(&self, &str bar) {}
| -----^^^ | -----^^^
@ -8,7 +8,7 @@ LL | fn foo(&self, &str bar) {}
| help: declare the type after the parameter binding: `<identifier>: <type>` | help: declare the type after the parameter binding: `<identifier>: <type>`
error: expected one of `:`, `@`, or `|`, found `quux` error: expected one of `:`, `@`, or `|`, found `quux`
--> $DIR/inverted-parameters.rs:10:10 --> $DIR/inverted-parameters.rs:12:10
| |
LL | fn baz(S quux, xyzzy: i32) {} LL | fn baz(S quux, xyzzy: i32) {}
| --^^^^ | --^^^^
@ -17,19 +17,19 @@ LL | fn baz(S quux, xyzzy: i32) {}
| help: declare the type after the parameter binding: `<identifier>: <type>` | help: declare the type after the parameter binding: `<identifier>: <type>`
error: expected one of `:`, `@`, or `|`, found `a` error: expected one of `:`, `@`, or `|`, found `a`
--> $DIR/inverted-parameters.rs:15:12 --> $DIR/inverted-parameters.rs:17:12
| |
LL | fn one(i32 a b) {} LL | fn one(i32 a b) {}
| ^ expected one of `:`, `@`, or `|` | ^ expected one of `:`, `@`, or `|`
error: expected one of `:` or `|`, found `(` error: expected one of `:` or `|`, found `(`
--> $DIR/inverted-parameters.rs:18:23 --> $DIR/inverted-parameters.rs:20:23
| |
LL | fn pattern((i32, i32) (a, b)) {} LL | fn pattern((i32, i32) (a, b)) {}
| ^ expected one of `:` or `|` | ^ expected one of `:` or `|`
error: expected one of `:`, `@`, or `|`, found `)` error: expected one of `:`, `@`, or `|`, found `)`
--> $DIR/inverted-parameters.rs:21:12 --> $DIR/inverted-parameters.rs:23:12
| |
LL | fn fizz(i32) {} LL | fn fizz(i32) {}
| ^ expected one of `:`, `@`, or `|` | ^ expected one of `:`, `@`, or `|`
@ -49,7 +49,7 @@ LL | fn fizz(_: i32) {}
| ++ | ++
error: expected one of `:`, `@`, or `|`, found `S` error: expected one of `:`, `@`, or `|`, found `S`
--> $DIR/inverted-parameters.rs:27:23 --> $DIR/inverted-parameters.rs:29:23
| |
LL | fn missing_colon(quux S) {} LL | fn missing_colon(quux S) {}
| -----^ | -----^

View file

@ -1,3 +1,5 @@
//@ dont-require-annotations: SUGGESTION
struct X(usize); struct X(usize);
impl X { impl X {

View file

@ -1,5 +1,5 @@
error[E0594]: cannot assign to `self.0`, which is behind a `&` reference error[E0594]: cannot assign to `self.0`, which is behind a `&` reference
--> $DIR/suggest-ref-mut.rs:7:9 --> $DIR/suggest-ref-mut.rs:9:9
| |
LL | self.0 = 32; LL | self.0 = 32;
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
@ -10,7 +10,7 @@ LL | fn zap(&mut self) {
| +++ | +++
error[E0594]: cannot assign to `*foo`, which is behind a `&` reference error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
--> $DIR/suggest-ref-mut.rs:15:5 --> $DIR/suggest-ref-mut.rs:17:5
| |
LL | *foo = 32; LL | *foo = 32;
| ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
@ -21,7 +21,7 @@ LL | let ref mut foo = 16;
| +++ | +++
error[E0594]: cannot assign to `*bar`, which is behind a `&` reference error[E0594]: cannot assign to `*bar`, which is behind a `&` reference
--> $DIR/suggest-ref-mut.rs:19:9 --> $DIR/suggest-ref-mut.rs:21:9
| |
LL | *bar = 32; LL | *bar = 32;
| ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written | ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written
@ -32,7 +32,7 @@ LL | if let Some(ref mut bar) = Some(16) {
| +++ | +++
error[E0594]: cannot assign to `*quo`, which is behind a `&` reference error[E0594]: cannot assign to `*quo`, which is behind a `&` reference
--> $DIR/suggest-ref-mut.rs:23:22 --> $DIR/suggest-ref-mut.rs:25:22
| |
LL | ref quo => { *quo = 32; }, LL | ref quo => { *quo = 32; },
| ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written | ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written

View file

@ -1,4 +1,5 @@
//@ edition:2018 //@ edition:2018
//@ dont-require-annotations: SUGGESTION
async fn hello() { //~ HELP try adding a return type async fn hello() { //~ HELP try adding a return type
0 0

View file

@ -1,5 +1,5 @@
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/issue-90027-async-fn-return-suggestion.rs:4:5 --> $DIR/issue-90027-async-fn-return-suggestion.rs:5:5
| |
LL | async fn hello() { LL | async fn hello() {
| - help: try adding a return type: `-> i32` | - help: try adding a return type: `-> i32`
@ -7,7 +7,7 @@ LL | 0
| ^ expected `()`, found integer | ^ expected `()`, found integer
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/issue-90027-async-fn-return-suggestion.rs:9:5 --> $DIR/issue-90027-async-fn-return-suggestion.rs:10:5
| |
LL | async fn world() -> () { LL | async fn world() -> () {
| -- expected `()` because of return type | -- expected `()` because of return type
@ -15,13 +15,13 @@ LL | 0
| ^ expected `()`, found integer | ^ expected `()`, found integer
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5 --> $DIR/issue-90027-async-fn-return-suggestion.rs:15:5
| |
LL | hello() LL | hello()
| ^^^^^^^ expected `()`, found future | ^^^^^^^ expected `()`, found future
| |
note: calling an async function returns a future note: calling an async function returns a future
--> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5 --> $DIR/issue-90027-async-fn-return-suggestion.rs:15:5
| |
LL | hello() LL | hello()
| ^^^^^^^ | ^^^^^^^