Skip to content

Commit 725b38e

Browse files
committed
Auto merge of rust-lang#125358 - matthiaskrgr:rollup-mx841tg, r=matthiaskrgr
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
2 parents 45acd46 + 9a4c4c8 commit 725b38e

File tree

9 files changed

+148
-154
lines changed

9 files changed

+148
-154
lines changed

alloc/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@ compiler-builtins-no-asm = ["compiler_builtins/no-asm"]
3737
compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"]
3838
compiler-builtins-weak-intrinsics = ["compiler_builtins/weak-intrinsics"]
3939
# Make panics and failed asserts immediately abort without formatting any message
40-
panic_immediate_abort = []
40+
panic_immediate_abort = ["core/panic_immediate_abort"]
41+
# Choose algorithms that are optimized for binary size instead of runtime performance
42+
optimize_for_size = ["core/optimize_for_size"]

core/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ rand_xorshift = { version = "0.3.0", default-features = false }
3131
[features]
3232
# Make panics and failed asserts immediately abort without formatting any message
3333
panic_immediate_abort = []
34+
# Choose algorithms that are optimized for binary size instead of runtime performance
35+
optimize_for_size = []
3436
# Make `RefCell` store additional debugging information, which is printed out when
3537
# a borrow error occurs
3638
debug_refcell = []

core/src/intrinsics/simd.rs

+7
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,13 @@ extern "rust-intrinsic" {
569569
#[rustc_nounwind]
570570
pub fn simd_ctlz<T>(x: T) -> T;
571571

572+
/// Count the number of ones in each element.
573+
///
574+
/// `T` must be a vector of integers.
575+
#[rustc_nounwind]
576+
#[cfg(not(bootstrap))]
577+
pub fn simd_ctpop<T>(x: T) -> T;
578+
572579
/// Count the trailing zeros of each element.
573580
///
574581
/// `T` must be a vector of integers.

std/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
7878

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

8284
# Enable std_detect default features for stdarch/crates/std_detect:
8385
# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml

std/src/path.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -3323,7 +3323,7 @@ impl Error for StripPrefixError {
33233323
///
33243324
/// # Examples
33253325
///
3326-
/// ## Posix paths
3326+
/// ## POSIX paths
33273327
///
33283328
/// ```
33293329
/// # #[cfg(unix)]
@@ -3369,9 +3369,12 @@ impl Error for StripPrefixError {
33693369
/// ```
33703370
///
33713371
/// For verbatim paths this will simply return the path as given. For other
3372-
/// paths this is currently equivalent to calling [`GetFullPathNameW`][windows-path]
3373-
/// This may change in the future.
3372+
/// paths this is currently equivalent to calling
3373+
/// [`GetFullPathNameW`][windows-path].
33743374
///
3375+
/// Note that this [may change in the future][changes].
3376+
///
3377+
/// [changes]: io#platform-specific-behavior
33753378
/// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
33763379
/// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
33773380
#[stable(feature = "absolute_path", since = "1.79.0")]

std/src/sys/pal/unix/args.rs

+96-142
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
66
#![allow(dead_code)] // runtime init functions not used during testing
77

8-
use crate::ffi::OsString;
8+
use crate::ffi::{CStr, OsString};
99
use crate::fmt;
10+
use crate::os::unix::ffi::OsStringExt;
1011
use crate::vec;
1112

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

1718
/// Returns the command line arguments
1819
pub fn args() -> Args {
19-
imp::args()
20+
let (argc, argv) = imp::argc_argv();
21+
22+
let mut vec = Vec::with_capacity(argc as usize);
23+
24+
for i in 0..argc {
25+
// SAFETY: `argv` is non-null if `argc` is positive, and it is
26+
// guaranteed to be at least as long as `argc`, so reading from it
27+
// should be safe.
28+
let ptr = unsafe { argv.offset(i).read() };
29+
30+
// Some C commandline parsers (e.g. GLib and Qt) are replacing already
31+
// handled arguments in `argv` with `NULL` and move them to the end.
32+
//
33+
// Since they can't directly ensure updates to `argc` as well, this
34+
// means that `argc` might be bigger than the actual number of
35+
// non-`NULL` pointers in `argv` at this point.
36+
//
37+
// To handle this we simply stop iterating at the first `NULL`
38+
// argument. `argv` is also guaranteed to be `NULL`-terminated so any
39+
// non-`NULL` arguments after the first `NULL` can safely be ignored.
40+
if ptr.is_null() {
41+
// NOTE: On Apple platforms, `-[NSProcessInfo arguments]` does not
42+
// stop iterating here, but instead `continue`, always iterating
43+
// up until it reached `argc`.
44+
//
45+
// This difference will only matter in very specific circumstances
46+
// where `argc`/`argv` have been modified, but in unexpected ways,
47+
// so it likely doesn't really matter which option we choose.
48+
// See the following PR for further discussion:
49+
// <https://github.com/rust-lang/rust/pull/125225>
50+
break;
51+
}
52+
53+
// SAFETY: Just checked that the pointer is not NULL, and arguments
54+
// are otherwise guaranteed to be valid C strings.
55+
let cstr = unsafe { CStr::from_ptr(ptr) };
56+
vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
57+
}
58+
59+
Args { iter: vec.into_iter() }
2060
}
2161

2262
pub struct Args {
@@ -75,9 +115,7 @@ impl DoubleEndedIterator for Args {
75115
target_os = "hurd",
76116
))]
77117
mod imp {
78-
use super::Args;
79-
use crate::ffi::{CStr, OsString};
80-
use crate::os::unix::prelude::*;
118+
use crate::ffi::c_char;
81119
use crate::ptr;
82120
use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
83121

@@ -126,162 +164,78 @@ mod imp {
126164
init_wrapper
127165
};
128166

129-
pub fn args() -> Args {
130-
Args { iter: clone().into_iter() }
131-
}
132-
133-
fn clone() -> Vec<OsString> {
134-
unsafe {
135-
// Load ARGC and ARGV, which hold the unmodified system-provided
136-
// argc/argv, so we can read the pointed-to memory without atomics
137-
// or synchronization.
138-
//
139-
// If either ARGC or ARGV is still zero or null, then either there
140-
// really are no arguments, or someone is asking for `args()`
141-
// before initialization has completed, and we return an empty
142-
// list.
143-
let argv = ARGV.load(Ordering::Relaxed);
144-
let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
145-
let mut args = Vec::with_capacity(argc as usize);
146-
for i in 0..argc {
147-
let ptr = *argv.offset(i) as *const libc::c_char;
148-
149-
// Some C commandline parsers (e.g. GLib and Qt) are replacing already
150-
// handled arguments in `argv` with `NULL` and move them to the end. That
151-
// means that `argc` might be bigger than the actual number of non-`NULL`
152-
// pointers in `argv` at this point.
153-
//
154-
// To handle this we simply stop iterating at the first `NULL` argument.
155-
//
156-
// `argv` is also guaranteed to be `NULL`-terminated so any non-`NULL` arguments
157-
// after the first `NULL` can safely be ignored.
158-
if ptr.is_null() {
159-
break;
160-
}
161-
162-
let cstr = CStr::from_ptr(ptr);
163-
args.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
164-
}
165-
166-
args
167-
}
167+
pub fn argc_argv() -> (isize, *const *const c_char) {
168+
// Load ARGC and ARGV, which hold the unmodified system-provided
169+
// argc/argv, so we can read the pointed-to memory without atomics or
170+
// synchronization.
171+
//
172+
// If either ARGC or ARGV is still zero or null, then either there
173+
// really are no arguments, or someone is asking for `args()` before
174+
// initialization has completed, and we return an empty list.
175+
let argv = ARGV.load(Ordering::Relaxed);
176+
let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
177+
178+
// Cast from `*mut *const u8` to `*const *const c_char`
179+
(argc, argv.cast())
168180
}
169181
}
170182

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

176-
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
177-
178-
#[cfg(target_os = "macos")]
179-
pub fn args() -> Args {
180-
use crate::os::unix::prelude::*;
181-
extern "C" {
182-
// These functions are in crt_externs.h.
183-
fn _NSGetArgc() -> *mut libc::c_int;
184-
fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
185-
}
186-
187-
let vec = unsafe {
188-
let (argc, argv) =
189-
(*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
190-
(0..argc as isize)
191-
.map(|i| {
192-
let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
193-
OsStringExt::from_vec(bytes)
194-
})
195-
.collect::<Vec<_>>()
196-
};
197-
Args { iter: vec.into_iter() }
200+
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
201+
// No need to initialize anything in here, `libdyld.dylib` has already
202+
// done the work for us.
198203
}
199204

200-
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
201-
// and use underscores in their names - they're most probably
202-
// are considered private and therefore should be avoided.
203-
// Here is another way to get arguments using the Objective-C
204-
// runtime.
205-
//
206-
// In general it looks like:
207-
// res = Vec::new()
208-
// let args = [[NSProcessInfo processInfo] arguments]
209-
// for i in (0..[args count])
210-
// res.push([args objectAtIndex:i])
211-
// res
212-
#[cfg(not(target_os = "macos"))]
213-
pub fn args() -> Args {
214-
use crate::ffi::{c_char, c_void, OsString};
215-
use crate::mem;
216-
use crate::str;
217-
218-
type Sel = *const c_void;
219-
type NsId = *const c_void;
220-
type NSUInteger = usize;
221-
205+
pub fn argc_argv() -> (isize, *const *const c_char) {
222206
extern "C" {
223-
fn sel_registerName(name: *const c_char) -> Sel;
224-
fn objc_getClass(class_name: *const c_char) -> NsId;
225-
226-
// This must be transmuted to an appropriate function pointer type before being called.
227-
fn objc_msgSend();
228-
}
229-
230-
const MSG_SEND_PTR: unsafe extern "C" fn() = objc_msgSend;
231-
const MSG_SEND_NO_ARGUMENTS_RETURN_PTR: unsafe extern "C" fn(NsId, Sel) -> *const c_void =
232-
unsafe { mem::transmute(MSG_SEND_PTR) };
233-
const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER: unsafe extern "C" fn(
234-
NsId,
235-
Sel,
236-
) -> NSUInteger = unsafe { mem::transmute(MSG_SEND_PTR) };
237-
const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR: unsafe extern "C" fn(
238-
NsId,
239-
Sel,
240-
NSUInteger,
241-
)
242-
-> *const c_void = unsafe { mem::transmute(MSG_SEND_PTR) };
243-
244-
let mut res = Vec::new();
245-
246-
unsafe {
247-
let process_info_sel = sel_registerName(c"processInfo".as_ptr());
248-
let arguments_sel = sel_registerName(c"arguments".as_ptr());
249-
let count_sel = sel_registerName(c"count".as_ptr());
250-
let object_at_index_sel = sel_registerName(c"objectAtIndex:".as_ptr());
251-
let utf8string_sel = sel_registerName(c"UTF8String".as_ptr());
252-
253-
let klass = objc_getClass(c"NSProcessInfo".as_ptr());
254-
// `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/release`.
255-
let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(klass, process_info_sel);
256-
257-
// `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `retain/release`.
258-
let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(info, arguments_sel);
259-
260-
let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER(args, count_sel);
261-
for i in 0..cnt {
262-
// `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `retain/release`.
263-
let ns_string =
264-
MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR(args, object_at_index_sel, i);
265-
// 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.
266-
let utf_c_str: *const c_char =
267-
MSG_SEND_NO_ARGUMENTS_RETURN_PTR(ns_string, utf8string_sel).cast();
268-
let bytes = CStr::from_ptr(utf_c_str).to_bytes();
269-
res.push(OsString::from(str::from_utf8(bytes).unwrap()))
270-
}
207+
// These functions are in crt_externs.h.
208+
fn _NSGetArgc() -> *mut c_int;
209+
fn _NSGetArgv() -> *mut *mut *mut c_char;
271210
}
272211

273-
Args { iter: res.into_iter() }
212+
// SAFETY: The returned pointer points to a static initialized early
213+
// in the program lifetime by `libdyld.dylib`, and as such is always
214+
// valid.
215+
//
216+
// NOTE: Similar to `_NSGetEnviron`, there technically isn't anything
217+
// protecting us against concurrent modifications to this, and there
218+
// doesn't exist a lock that we can take. Instead, it is generally
219+
// expected that it's only modified in `main` / before other code
220+
// runs, so reading this here should be fine.
221+
let argc = unsafe { _NSGetArgc().read() };
222+
// SAFETY: Same as above.
223+
let argv = unsafe { _NSGetArgv().read() };
224+
225+
// Cast from `*mut *mut c_char` to `*const *const c_char`
226+
(argc as isize, argv.cast())
274227
}
275228
}
276229

277230
#[cfg(any(target_os = "espidf", target_os = "vita"))]
278231
mod imp {
279-
use super::Args;
232+
use crate::ffi::c_char;
233+
use crate::ptr;
280234

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

284-
pub fn args() -> Args {
285-
Args { iter: Vec::new().into_iter() }
238+
pub fn argc_argv() -> (isize, *const *const c_char) {
239+
(0, ptr::null())
286240
}
287241
}

std/src/sys/pal/unix/mod.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -399,14 +399,13 @@ cfg_if::cfg_if! {
399399
// Use libumem for the (malloc-compatible) allocator
400400
#[link(name = "umem")]
401401
extern "C" {}
402-
} else if #[cfg(target_os = "macos")] {
402+
} else if #[cfg(target_vendor = "apple")] {
403+
// Link to `libSystem.dylib`.
404+
//
405+
// Don't get confused by the presence of `System.framework`,
406+
// it is a deprecated wrapper over the dynamic library.
403407
#[link(name = "System")]
404408
extern "C" {}
405-
} else if #[cfg(all(target_vendor = "apple", not(target_os = "macos")))] {
406-
#[link(name = "System")]
407-
#[link(name = "objc")]
408-
#[link(name = "Foundation", kind = "framework")]
409-
extern "C" {}
410409
} else if #[cfg(target_os = "fuchsia")] {
411410
#[link(name = "zircon")]
412411
#[link(name = "fdio")]

0 commit comments

Comments
 (0)