Skip to content

Commit

Permalink
Auto merge of rust-lang#125358 - matthiaskrgr:rollup-mx841tg, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#124570 (Miscellaneous cleanups)
 - rust-lang#124772 (Refactor documentation for Apple targets)
 - rust-lang#125011 (Add opt-for-size core lib feature flag)
 - rust-lang#125218 (Migrate `run-make/no-intermediate-extras` to new `rmake.rs`)
 - rust-lang#125225 (Use functions from `crt_externs.h` on iOS/tvOS/watchOS/visionOS)
 - rust-lang#125266 (compiler: add simd_ctpop intrinsic)
 - rust-lang#125348 (Small fixes to `std::path::absolute` docs)

Failed merges:

 - rust-lang#125296 (Fix `unexpected_cfgs` lint on std)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed May 21, 2024
2 parents 45acd46 + 9a4c4c8 commit 725b38e
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 154 deletions.
4 changes: 3 additions & 1 deletion alloc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ compiler-builtins-no-asm = ["compiler_builtins/no-asm"]
compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"]
compiler-builtins-weak-intrinsics = ["compiler_builtins/weak-intrinsics"]
# Make panics and failed asserts immediately abort without formatting any message
panic_immediate_abort = []
panic_immediate_abort = ["core/panic_immediate_abort"]
# Choose algorithms that are optimized for binary size instead of runtime performance
optimize_for_size = ["core/optimize_for_size"]
2 changes: 2 additions & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ rand_xorshift = { version = "0.3.0", default-features = false }
[features]
# Make panics and failed asserts immediately abort without formatting any message
panic_immediate_abort = []
# Choose algorithms that are optimized for binary size instead of runtime performance
optimize_for_size = []
# Make `RefCell` store additional debugging information, which is printed out when
# a borrow error occurs
debug_refcell = []
7 changes: 7 additions & 0 deletions core/src/intrinsics/simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,13 @@ extern "rust-intrinsic" {
#[rustc_nounwind]
pub fn simd_ctlz<T>(x: T) -> T;

/// Count the number of ones in each element.
///
/// `T` must be a vector of integers.
#[rustc_nounwind]
#[cfg(not(bootstrap))]
pub fn simd_ctpop<T>(x: T) -> T;

/// Count the trailing zeros of each element.
///
/// `T` must be a vector of integers.
Expand Down
2 changes: 2 additions & 0 deletions std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ system-llvm-libunwind = ["unwind/system-llvm-libunwind"]

# Make panics and failed asserts immediately abort without formatting any message
panic_immediate_abort = ["core/panic_immediate_abort", "alloc/panic_immediate_abort"]
# Choose algorithms that are optimized for binary size instead of runtime performance
optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"]

# Enable std_detect default features for stdarch/crates/std_detect:
# /~https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
Expand Down
9 changes: 6 additions & 3 deletions std/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3323,7 +3323,7 @@ impl Error for StripPrefixError {
///
/// # Examples
///
/// ## Posix paths
/// ## POSIX paths
///
/// ```
/// # #[cfg(unix)]
Expand Down Expand Up @@ -3369,9 +3369,12 @@ impl Error for StripPrefixError {
/// ```
///
/// For verbatim paths this will simply return the path as given. For other
/// paths this is currently equivalent to calling [`GetFullPathNameW`][windows-path]
/// This may change in the future.
/// paths this is currently equivalent to calling
/// [`GetFullPathNameW`][windows-path].
///
/// Note that this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
/// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
/// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
#[stable(feature = "absolute_path", since = "1.79.0")]
Expand Down
238 changes: 96 additions & 142 deletions std/src/sys/pal/unix/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
#![allow(dead_code)] // runtime init functions not used during testing

use crate::ffi::OsString;
use crate::ffi::{CStr, OsString};
use crate::fmt;
use crate::os::unix::ffi::OsStringExt;
use crate::vec;

/// One-time global initialization.
Expand All @@ -16,7 +17,46 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {

/// Returns the command line arguments
pub fn args() -> Args {
imp::args()
let (argc, argv) = imp::argc_argv();

let mut vec = Vec::with_capacity(argc as usize);

for i in 0..argc {
// SAFETY: `argv` is non-null if `argc` is positive, and it is
// guaranteed to be at least as long as `argc`, so reading from it
// should be safe.
let ptr = unsafe { argv.offset(i).read() };

// Some C commandline parsers (e.g. GLib and Qt) are replacing already
// handled arguments in `argv` with `NULL` and move them to the end.
//
// Since they can't directly ensure updates to `argc` as well, this
// means that `argc` might be bigger than the actual number of
// non-`NULL` pointers in `argv` at this point.
//
// To handle this we simply stop iterating at the first `NULL`
// argument. `argv` is also guaranteed to be `NULL`-terminated so any
// non-`NULL` arguments after the first `NULL` can safely be ignored.
if ptr.is_null() {
// NOTE: On Apple platforms, `-[NSProcessInfo arguments]` does not
// stop iterating here, but instead `continue`, always iterating
// up until it reached `argc`.
//
// This difference will only matter in very specific circumstances
// where `argc`/`argv` have been modified, but in unexpected ways,
// so it likely doesn't really matter which option we choose.
// See the following PR for further discussion:
// </~https://github.com/rust-lang/rust/pull/125225>
break;
}

// SAFETY: Just checked that the pointer is not NULL, and arguments
// are otherwise guaranteed to be valid C strings.
let cstr = unsafe { CStr::from_ptr(ptr) };
vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
}

Args { iter: vec.into_iter() }
}

pub struct Args {
Expand Down Expand Up @@ -75,9 +115,7 @@ impl DoubleEndedIterator for Args {
target_os = "hurd",
))]
mod imp {
use super::Args;
use crate::ffi::{CStr, OsString};
use crate::os::unix::prelude::*;
use crate::ffi::c_char;
use crate::ptr;
use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};

Expand Down Expand Up @@ -126,162 +164,78 @@ mod imp {
init_wrapper
};

pub fn args() -> Args {
Args { iter: clone().into_iter() }
}

fn clone() -> Vec<OsString> {
unsafe {
// Load ARGC and ARGV, which hold the unmodified system-provided
// argc/argv, so we can read the pointed-to memory without atomics
// or synchronization.
//
// If either ARGC or ARGV is still zero or null, then either there
// really are no arguments, or someone is asking for `args()`
// before initialization has completed, and we return an empty
// list.
let argv = ARGV.load(Ordering::Relaxed);
let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
let mut args = Vec::with_capacity(argc as usize);
for i in 0..argc {
let ptr = *argv.offset(i) as *const libc::c_char;

// Some C commandline parsers (e.g. GLib and Qt) are replacing already
// handled arguments in `argv` with `NULL` and move them to the end. That
// means that `argc` might be bigger than the actual number of non-`NULL`
// pointers in `argv` at this point.
//
// To handle this we simply stop iterating at the first `NULL` argument.
//
// `argv` is also guaranteed to be `NULL`-terminated so any non-`NULL` arguments
// after the first `NULL` can safely be ignored.
if ptr.is_null() {
break;
}

let cstr = CStr::from_ptr(ptr);
args.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
}

args
}
pub fn argc_argv() -> (isize, *const *const c_char) {
// Load ARGC and ARGV, which hold the unmodified system-provided
// argc/argv, so we can read the pointed-to memory without atomics or
// synchronization.
//
// If either ARGC or ARGV is still zero or null, then either there
// really are no arguments, or someone is asking for `args()` before
// initialization has completed, and we return an empty list.
let argv = ARGV.load(Ordering::Relaxed);
let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };

// Cast from `*mut *const u8` to `*const *const c_char`
(argc, argv.cast())
}
}

// Use `_NSGetArgc` and `_NSGetArgv` on Apple platforms.
//
// Even though these have underscores in their names, they've been available
// since since the first versions of both macOS and iOS, and are declared in
// the header `crt_externs.h`.
//
// NOTE: This header was added to the iOS 13.0 SDK, which has been the source
// of a great deal of confusion in the past about the availability of these
// APIs.
//
// NOTE(madsmtm): This has not strictly been verified to not cause App Store
// rejections; if this is found to be the case, the previous implementation
// of this used `[[NSProcessInfo processInfo] arguments]`.
#[cfg(target_vendor = "apple")]
mod imp {
use super::Args;
use crate::ffi::CStr;
use crate::ffi::{c_char, c_int};

pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}

#[cfg(target_os = "macos")]
pub fn args() -> Args {
use crate::os::unix::prelude::*;
extern "C" {
// These functions are in crt_externs.h.
fn _NSGetArgc() -> *mut libc::c_int;
fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
}

let vec = unsafe {
let (argc, argv) =
(*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
(0..argc as isize)
.map(|i| {
let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
OsStringExt::from_vec(bytes)
})
.collect::<Vec<_>>()
};
Args { iter: vec.into_iter() }
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
// No need to initialize anything in here, `libdyld.dylib` has already
// done the work for us.
}

// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
// and use underscores in their names - they're most probably
// are considered private and therefore should be avoided.
// Here is another way to get arguments using the Objective-C
// runtime.
//
// In general it looks like:
// res = Vec::new()
// let args = [[NSProcessInfo processInfo] arguments]
// for i in (0..[args count])
// res.push([args objectAtIndex:i])
// res
#[cfg(not(target_os = "macos"))]
pub fn args() -> Args {
use crate::ffi::{c_char, c_void, OsString};
use crate::mem;
use crate::str;

type Sel = *const c_void;
type NsId = *const c_void;
type NSUInteger = usize;

pub fn argc_argv() -> (isize, *const *const c_char) {
extern "C" {
fn sel_registerName(name: *const c_char) -> Sel;
fn objc_getClass(class_name: *const c_char) -> NsId;

// This must be transmuted to an appropriate function pointer type before being called.
fn objc_msgSend();
}

const MSG_SEND_PTR: unsafe extern "C" fn() = objc_msgSend;
const MSG_SEND_NO_ARGUMENTS_RETURN_PTR: unsafe extern "C" fn(NsId, Sel) -> *const c_void =
unsafe { mem::transmute(MSG_SEND_PTR) };
const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER: unsafe extern "C" fn(
NsId,
Sel,
) -> NSUInteger = unsafe { mem::transmute(MSG_SEND_PTR) };
const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR: unsafe extern "C" fn(
NsId,
Sel,
NSUInteger,
)
-> *const c_void = unsafe { mem::transmute(MSG_SEND_PTR) };

let mut res = Vec::new();

unsafe {
let process_info_sel = sel_registerName(c"processInfo".as_ptr());
let arguments_sel = sel_registerName(c"arguments".as_ptr());
let count_sel = sel_registerName(c"count".as_ptr());
let object_at_index_sel = sel_registerName(c"objectAtIndex:".as_ptr());
let utf8string_sel = sel_registerName(c"UTF8String".as_ptr());

let klass = objc_getClass(c"NSProcessInfo".as_ptr());
// `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/release`.
let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(klass, process_info_sel);

// `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `retain/release`.
let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(info, arguments_sel);

let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER(args, count_sel);
for i in 0..cnt {
// `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `retain/release`.
let ns_string =
MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR(args, object_at_index_sel, i);
// The lifetime of this pointer is tied to the NSString, as well as the current autorelease pool, which is why we heap-allocate the string below.
let utf_c_str: *const c_char =
MSG_SEND_NO_ARGUMENTS_RETURN_PTR(ns_string, utf8string_sel).cast();
let bytes = CStr::from_ptr(utf_c_str).to_bytes();
res.push(OsString::from(str::from_utf8(bytes).unwrap()))
}
// These functions are in crt_externs.h.
fn _NSGetArgc() -> *mut c_int;
fn _NSGetArgv() -> *mut *mut *mut c_char;
}

Args { iter: res.into_iter() }
// SAFETY: The returned pointer points to a static initialized early
// in the program lifetime by `libdyld.dylib`, and as such is always
// valid.
//
// NOTE: Similar to `_NSGetEnviron`, there technically isn't anything
// protecting us against concurrent modifications to this, and there
// doesn't exist a lock that we can take. Instead, it is generally
// expected that it's only modified in `main` / before other code
// runs, so reading this here should be fine.
let argc = unsafe { _NSGetArgc().read() };
// SAFETY: Same as above.
let argv = unsafe { _NSGetArgv().read() };

// Cast from `*mut *mut c_char` to `*const *const c_char`
(argc as isize, argv.cast())
}
}

#[cfg(any(target_os = "espidf", target_os = "vita"))]
mod imp {
use super::Args;
use crate::ffi::c_char;
use crate::ptr;

#[inline(always)]
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}

pub fn args() -> Args {
Args { iter: Vec::new().into_iter() }
pub fn argc_argv() -> (isize, *const *const c_char) {
(0, ptr::null())
}
}
11 changes: 5 additions & 6 deletions std/src/sys/pal/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,14 +399,13 @@ cfg_if::cfg_if! {
// Use libumem for the (malloc-compatible) allocator
#[link(name = "umem")]
extern "C" {}
} else if #[cfg(target_os = "macos")] {
} else if #[cfg(target_vendor = "apple")] {
// Link to `libSystem.dylib`.
//
// Don't get confused by the presence of `System.framework`,
// it is a deprecated wrapper over the dynamic library.
#[link(name = "System")]
extern "C" {}
} else if #[cfg(all(target_vendor = "apple", not(target_os = "macos")))] {
#[link(name = "System")]
#[link(name = "objc")]
#[link(name = "Foundation", kind = "framework")]
extern "C" {}
} else if #[cfg(target_os = "fuchsia")] {
#[link(name = "zircon")]
#[link(name = "fdio")]
Expand Down
Loading

0 comments on commit 725b38e

Please sign in to comment.