Skip to content

Commit 510323f

Browse files
committed
Auto merge of rust-lang#89139 - camsteffen:write-perf, r=Mark-Simulacrum
Use ZST for fmt unsafety as suggested here - rust-lang#83302 (comment).
2 parents 686ac9f + d63fcb2 commit 510323f

File tree

2 files changed

+45
-13
lines changed

2 files changed

+45
-13
lines changed

core/src/fmt/mod.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,26 @@ pub struct ArgumentV1<'a> {
265265
formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
266266
}
267267

268+
/// This struct represents the unsafety of constructing an `Arguments`.
269+
/// It exists, rather than an unsafe function, in order to simplify the expansion
270+
/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
271+
#[allow(missing_debug_implementations)]
272+
#[doc(hidden)]
273+
#[non_exhaustive]
274+
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
275+
pub struct UnsafeArg;
276+
277+
impl UnsafeArg {
278+
/// See documentation where `UnsafeArg` is required to know when it is safe to
279+
/// create and use `UnsafeArg`.
280+
#[doc(hidden)]
281+
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
282+
#[inline(always)]
283+
pub unsafe fn new() -> Self {
284+
Self
285+
}
286+
}
287+
268288
// This guarantees a single stable value for the function pointer associated with
269289
// indices/counts in the formatting infrastructure.
270290
//
@@ -337,22 +357,37 @@ impl<'a> Arguments<'a> {
337357
#[inline]
338358
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
339359
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
340-
pub const unsafe fn new_v1(
341-
pieces: &'a [&'static str],
342-
args: &'a [ArgumentV1<'a>],
343-
) -> Arguments<'a> {
360+
pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
344361
if pieces.len() < args.len() || pieces.len() > args.len() + 1 {
345362
panic!("invalid args");
346363
}
347364
Arguments { pieces, fmt: None, args }
348365
}
349366

350367
/// This function is used to specify nonstandard formatting parameters.
351-
/// The `pieces` array must be at least as long as `fmt` to construct
352-
/// a valid Arguments structure. Also, any `Count` within `fmt` that is
353-
/// `CountIsParam` or `CountIsNextParam` has to point to an argument
354-
/// created with `argumentusize`. However, failing to do so doesn't cause
355-
/// unsafety, but will ignore invalid .
368+
///
369+
/// An `UnsafeArg` is required because the following invariants must be held
370+
/// in order for this function to be safe:
371+
/// 1. The `pieces` slice must be at least as long as `fmt`.
372+
/// 2. Every [`rt::v1::Argument::position`] value within `fmt` must be a
373+
/// valid index of `args`.
374+
/// 3. Every [`Count::Param`] within `fmt` must contain a valid index of
375+
/// `args`.
376+
#[cfg(not(bootstrap))]
377+
#[doc(hidden)]
378+
#[inline]
379+
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
380+
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
381+
pub const fn new_v1_formatted(
382+
pieces: &'a [&'static str],
383+
args: &'a [ArgumentV1<'a>],
384+
fmt: &'a [rt::v1::Argument],
385+
_unsafe_arg: UnsafeArg,
386+
) -> Arguments<'a> {
387+
Arguments { pieces, fmt: Some(fmt), args }
388+
}
389+
390+
#[cfg(bootstrap)]
356391
#[doc(hidden)]
357392
#[inline]
358393
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]

core/src/panicking.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,7 @@ pub fn panic(expr: &'static str) -> ! {
4747
// truncation and padding (even though none is used here). Using
4848
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
4949
// output binary, saving up to a few kilobytes.
50-
panic_fmt(
51-
// SAFETY: Arguments::new_v1 is safe with exactly one str and zero args
52-
unsafe { fmt::Arguments::new_v1(&[expr], &[]) },
53-
);
50+
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
5451
}
5552

5653
#[inline]

0 commit comments

Comments
 (0)