Skip to content

Use UnsafeArg in Arguments::new_v1 #89155

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -846,26 +846,28 @@ impl<'a, 'b> Context<'a, 'b> {

let args_slice = self.ecx.expr_addr_of(self.macsp, args_match);

// Now create the fmt::Arguments struct with all our locals we created.
let (fn_name, fn_args) = if self.all_pieces_simple {
("new_v1", vec![pieces, args_slice])
} else {
// Build up the static array which will store our precompiled
// nonstandard placeholders, if there are any.
let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces);

let unsafe_arg = {
let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]);
let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new());
let unsafe_expr = self.ecx.expr_block(P(ast::Block {
self.ecx.expr_block(P(ast::Block {
stmts: vec![self.ecx.stmt_expr(unsafe_arg)],
id: ast::DUMMY_NODE_ID,
rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
span: self.macsp,
tokens: None,
could_be_bare_literal: false,
}));
}))
};

// Now create the fmt::Arguments struct with all our locals we created.
let (fn_name, fn_args) = if self.all_pieces_simple {
("new_v1", vec![pieces, args_slice, unsafe_arg])
} else {
// Build up the static array which will store our precompiled
// nonstandard placeholders, if there are any.
let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces);

("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_expr])
("new_v1_formatted", vec![pieces, args_slice, fmt, unsafe_arg])
};

let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]);
Expand Down
18 changes: 17 additions & 1 deletion library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ impl UnsafeArg {
#[doc(hidden)]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
#[inline(always)]
pub unsafe fn new() -> Self {
pub const unsafe fn new() -> Self {
Self
}
}
Expand Down Expand Up @@ -353,6 +353,22 @@ enum FlagV1 {
impl<'a> Arguments<'a> {
/// When using the format_args!() macro, this function is used to generate the
/// Arguments structure.
///
/// An `UnsafeArg` is required because this function is unsafe unless
/// `pieces` is at least as long as `args`.
#[cfg(not(bootstrap))]
#[doc(hidden)]
#[inline]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
pub const fn new_v1(
pieces: &'a [&'static str],
args: &'a [ArgumentV1<'a>],
_unsafe_arg: UnsafeArg,
) -> Arguments<'a> {
Arguments { pieces, fmt: None, args }
}
#[cfg(bootstrap)]
#[doc(hidden)]
#[inline]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
Expand Down
10 changes: 9 additions & 1 deletion library/core/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,15 @@ pub fn panic(expr: &'static str) -> ! {
// truncation and padding (even though none is used here). Using
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
// output binary, saving up to a few kilobytes.
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
panic_fmt(fmt::Arguments::new_v1(
&[expr],
&[],
#[cfg(not(bootstrap))]
// SAFETY: Arguments::new_v1 is safe with exactly one str and zero args
unsafe {
fmt::UnsafeArg::new()
},
));
}

#[inline]
Expand Down
5 changes: 4 additions & 1 deletion src/test/pretty/dollar-crate.pp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"],
&match () {
() => [],
}));
},
unsafe {
::core::fmt::UnsafeArg::new()
}));
};
}
52 changes: 31 additions & 21 deletions src/test/pretty/issue-4264.pp
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,37 @@
((::alloc::fmt::format as
for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1
as
fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test"
as
&str)]
as
[&str; 1])
as
&[&str; 1]),
(&(match (()
as
())
{
()
=>
([]
as
[ArgumentV1; 0]),
}
as
[ArgumentV1; 0])
as
&[ArgumentV1; 0]))
fn(&[&'static str], &[ArgumentV1], core::fmt::UnsafeArg) -> Arguments {Arguments::new_v1})((&([("test"
as
&str)]
as
[&str; 1])
as
&[&str; 1]),
(&(match (()
as
())
{
()
=>
([]
as
[ArgumentV1; 0]),
}
as
[ArgumentV1; 0])
as
&[ArgumentV1; 0]),
(unsafe
{
((::core::fmt::UnsafeArg::new
as
unsafe fn() -> core::fmt::UnsafeArg {core::fmt::UnsafeArg::new})()
as
core::fmt::UnsafeArg)
}
as
core::fmt::UnsafeArg))
as
Arguments))
as String);
Expand Down
5 changes: 4 additions & 1 deletion src/test/ui/attributes/key-value-expansion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ error: unexpected token: `{
(arg0,) =>
[::core::fmt::ArgumentV1::new(arg0,
::core::fmt::Display::fmt)],
}));
},
unsafe {
::core::fmt::UnsafeArg::new()
}));
res
}.as_str()`
--> $DIR/key-value-expansion.rs:48:23
Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_utils/src/higher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ impl FormatArgsExpn<'tcx> {
if let ExprKind::Call(_, args) = expr.kind;
if let Some((strs_ref, args, fmt_expr)) = match args {
// Arguments::new_v1
[strs_ref, args] => Some((strs_ref, args, None)),
[strs_ref, args, _unsafe_arg] => Some((strs_ref, args, None)),
// Arguments::new_v1_formatted
[strs_ref, args, fmt_expr, _unsafe_arg] => Some((strs_ref, args, Some(fmt_expr))),
_ => None,
Expand Down