Skip to content

Commit f2f6bcc

Browse files
committed
Don't allow new const panic through format flattening.
panic!("a {}", "b") is still not allowed in const, even if the hir flattens to panic!("a b").
1 parent 96d2521 commit f2f6bcc

File tree

7 files changed

+66
-17
lines changed

7 files changed

+66
-17
lines changed

compiler/rustc_ast_lowering/src/format.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ use std::borrow::Cow;
1313

1414
impl<'hir> LoweringContext<'_, 'hir> {
1515
pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
16+
// Never call the const constructor of `fmt::Arguments` if the
17+
// format_args!() had any arguments _before_ flattening/inlining.
18+
let allow_const = fmt.arguments.all_args().is_empty();
1619
let fmt = flatten_format_args(Cow::Borrowed(fmt));
1720
let fmt = inline_literals(fmt);
18-
expand_format_args(self, sp, &fmt)
21+
expand_format_args(self, sp, &fmt, allow_const)
1922
}
2023
}
2124

@@ -342,6 +345,7 @@ fn expand_format_args<'hir>(
342345
ctx: &mut LoweringContext<'_, 'hir>,
343346
macsp: Span,
344347
fmt: &FormatArgs,
348+
allow_const: bool,
345349
) -> hir::ExprKind<'hir> {
346350
let mut incomplete_lit = String::new();
347351
let lit_pieces =
@@ -411,6 +415,18 @@ fn expand_format_args<'hir>(
411415

412416
let arguments = fmt.arguments.all_args();
413417

418+
if allow_const && arguments.is_empty() && argmap.is_empty() {
419+
// Generate:
420+
// <core::fmt::Arguments>::new_const(lit_pieces)
421+
let new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
422+
macsp,
423+
hir::LangItem::FormatArguments,
424+
sym::new_const,
425+
));
426+
let new_args = ctx.arena.alloc_from_iter([lit_pieces]);
427+
return hir::ExprKind::Call(new, new_args);
428+
}
429+
414430
// If the args array contains exactly all the original arguments once,
415431
// in order, we can use a simple array instead of a `match` construction.
416432
// However, if there's a yield point in any argument except the first one,

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,7 @@ symbols! {
984984
never_type_fallback,
985985
new,
986986
new_binary,
987+
new_const,
987988
new_debug,
988989
new_display,
989990
new_lower_exp,

library/core/src/fmt/mod.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,31 @@ enum FlagV1 {
392392
}
393393

394394
impl<'a> Arguments<'a> {
395+
#[doc(hidden)]
396+
#[inline]
397+
#[unstable(feature = "fmt_internals", issue = "none")]
398+
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
399+
pub const fn new_const(pieces: &'a [&'static str]) -> Self {
400+
if pieces.len() > 1 {
401+
panic!("invalid args");
402+
}
403+
Arguments { pieces, fmt: None, args: &[] }
404+
}
405+
395406
/// When using the format_args!() macro, this function is used to generate the
396407
/// Arguments structure.
408+
#[cfg(not(bootstrap))]
409+
#[doc(hidden)]
410+
#[inline]
411+
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
412+
pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
413+
if pieces.len() < args.len() || pieces.len() > args.len() + 1 {
414+
panic!("invalid args");
415+
}
416+
Arguments { pieces, fmt: None, args }
417+
}
418+
419+
#[cfg(bootstrap)]
397420
#[doc(hidden)]
398421
#[inline]
399422
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
@@ -417,8 +440,7 @@ impl<'a> Arguments<'a> {
417440
#[doc(hidden)]
418441
#[inline]
419442
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
420-
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
421-
pub const fn new_v1_formatted(
443+
pub fn new_v1_formatted(
422444
pieces: &'a [&'static str],
423445
args: &'a [ArgumentV1<'a>],
424446
fmt: &'a [rt::v1::Argument],

library/core/src/panicking.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub const fn panic(expr: &'static str) -> ! {
111111
// truncation and padding (even though none is used here). Using
112112
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
113113
// output binary, saving up to a few kilobytes.
114-
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
114+
panic_fmt(fmt::Arguments::new_const(&[expr]));
115115
}
116116

117117
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
@@ -120,7 +120,7 @@ pub const fn panic(expr: &'static str) -> ! {
120120
#[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
121121
#[rustc_nounwind]
122122
pub fn panic_nounwind(expr: &'static str) -> ! {
123-
panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[]));
123+
panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]));
124124
}
125125

126126
#[inline]

tests/ui/borrowck/issue-64453.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: `Arguments::<'a>::new_v1` is not yet stable as a const fn
1+
error: `Arguments::<'a>::new_const` is not yet stable as a const fn
22
--> $DIR/issue-64453.rs:4:31
33
|
44
LL | static settings_dir: String = format!("");

tests/ui/consts/const-eval/format.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
const fn failure() {
22
panic!("{:?}", 0);
33
//~^ ERROR cannot call non-const formatting macro in constant functions
4+
//~| ERROR cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
45
}
56

67
const fn print() {
78
println!("{:?}", 0);
89
//~^ ERROR cannot call non-const formatting macro in constant functions
9-
//~| ERROR `Arguments::<'a>::new_v1` is not yet stable as a const fn
10+
//~| ERROR cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
1011
//~| ERROR cannot call non-const fn `_print` in constant functions
1112
}
1213

tests/ui/consts/const-eval/format.stderr

+19-10
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,35 @@ LL | panic!("{:?}", 0);
77
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
88
= note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
99

10+
error[E0015]: cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
11+
--> $DIR/format.rs:2:5
12+
|
13+
LL | panic!("{:?}", 0);
14+
| ^^^^^^^^^^^^^^^^^
15+
|
16+
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
17+
= note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
18+
1019
error[E0015]: cannot call non-const formatting macro in constant functions
11-
--> $DIR/format.rs:7:22
20+
--> $DIR/format.rs:8:22
1221
|
1322
LL | println!("{:?}", 0);
1423
| ^
1524
|
1625
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
1726
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
1827

19-
error: `Arguments::<'a>::new_v1` is not yet stable as a const fn
20-
--> $DIR/format.rs:7:5
28+
error[E0015]: cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
29+
--> $DIR/format.rs:8:5
2130
|
2231
LL | println!("{:?}", 0);
2332
| ^^^^^^^^^^^^^^^^^^^
2433
|
25-
= help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
34+
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
2635
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
2736

2837
error[E0015]: cannot call non-const fn `_print` in constant functions
29-
--> $DIR/format.rs:7:5
38+
--> $DIR/format.rs:8:5
3039
|
3140
LL | println!("{:?}", 0);
3241
| ^^^^^^^^^^^^^^^^^^^
@@ -63,33 +72,33 @@ LL | panic!("{:?}", 0);
6372
= note: this note originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
6473

6574
note: erroneous constant used
66-
--> $DIR/format.rs:7:14
75+
--> $DIR/format.rs:8:14
6776
|
6877
LL | println!("{:?}", 0);
6978
| ^^^^^^
7079

7180
note: erroneous constant used
72-
--> $DIR/format.rs:7:14
81+
--> $DIR/format.rs:8:14
7382
|
7483
LL | println!("{:?}", 0);
7584
| ^^^^^^
7685

7786
note: erroneous constant used
78-
--> $DIR/format.rs:7:22
87+
--> $DIR/format.rs:8:22
7988
|
8089
LL | println!("{:?}", 0);
8190
| ^
8291
|
8392
= note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
8493

8594
note: erroneous constant used
86-
--> $DIR/format.rs:7:22
95+
--> $DIR/format.rs:8:22
8796
|
8897
LL | println!("{:?}", 0);
8998
| ^
9099
|
91100
= note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
92101

93-
error: aborting due to 4 previous errors
102+
error: aborting due to 5 previous errors
94103

95104
For more information about this error, try `rustc --explain E0015`.

0 commit comments

Comments
 (0)