Skip to content

Commit e4c8250

Browse files
authored
Rollup merge of #110770 - m-ou-se:fmt-temp-lifetime, r=oli-obk
Limit lifetime of format_args!() with inlined args. Fixes #110769
2 parents 88fbfaf + d5843dd commit e4c8250

File tree

3 files changed

+40
-1
lines changed

3 files changed

+40
-1
lines changed

compiler/rustc_ast_lowering/src/format.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,30 @@ fn expand_format_args<'hir>(
446446
&& argmap.iter().enumerate().all(|(i, (&(j, _), _))| i == j)
447447
&& arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
448448

449-
let args = if use_simple_array {
449+
let args = if arguments.is_empty() {
450+
// Generate:
451+
// &<core::fmt::Argument>::none()
452+
//
453+
// Note:
454+
// `none()` just returns `[]`. We use `none()` rather than `[]` to limit the lifetime.
455+
//
456+
// This makes sure that this still fails to compile, even when the argument is inlined:
457+
//
458+
// ```
459+
// let f = format_args!("{}", "a");
460+
// println!("{f}"); // error E0716
461+
// ```
462+
//
463+
// Cases where keeping the object around is allowed, such as `format_args!("a")`,
464+
// are handled above by the `allow_const` case.
465+
let none_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
466+
macsp,
467+
hir::LangItem::FormatArgument,
468+
sym::none,
469+
));
470+
let none = ctx.expr_call(macsp, none_fn, &[]);
471+
ctx.expr(macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, none))
472+
} else if use_simple_array {
450473
// Generate:
451474
// &[
452475
// <core::fmt::Argument>::new_display(&arg0),

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,7 @@ symbols! {
10331033
non_exhaustive_omitted_patterns_lint,
10341034
non_lifetime_binders,
10351035
non_modrs_mods,
1036+
none,
10361037
nontemporal_store,
10371038
noop_method_borrow,
10381039
noop_method_clone,

library/core/src/fmt/rt.rs

+15
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,21 @@ impl<'a> Argument<'a> {
152152
None
153153
}
154154
}
155+
156+
/// Used by `format_args` when all arguments are gone after inlining,
157+
/// when using `&[]` would incorrectly allow for a bigger lifetime.
158+
///
159+
/// This fails without format argument inlining, and that shouldn't be different
160+
/// when the argument is inlined:
161+
///
162+
/// ```compile_fail,E0716
163+
/// let f = format_args!("{}", "a");
164+
/// println!("{f}");
165+
/// ```
166+
#[inline(always)]
167+
pub fn none() -> [Self; 0] {
168+
[]
169+
}
155170
}
156171

157172
/// This struct represents the unsafety of constructing an `Arguments`.

0 commit comments

Comments
 (0)