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").
This commit is contained in:
parent
96d252160e
commit
f2f6bcc499
7 changed files with 66 additions and 17 deletions
|
@ -13,9 +13,12 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
impl<'hir> LoweringContext<'_, 'hir> {
|
impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
|
pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
|
||||||
|
// Never call the const constructor of `fmt::Arguments` if the
|
||||||
|
// format_args!() had any arguments _before_ flattening/inlining.
|
||||||
|
let allow_const = fmt.arguments.all_args().is_empty();
|
||||||
let fmt = flatten_format_args(Cow::Borrowed(fmt));
|
let fmt = flatten_format_args(Cow::Borrowed(fmt));
|
||||||
let fmt = inline_literals(fmt);
|
let fmt = inline_literals(fmt);
|
||||||
expand_format_args(self, sp, &fmt)
|
expand_format_args(self, sp, &fmt, allow_const)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +345,7 @@ fn expand_format_args<'hir>(
|
||||||
ctx: &mut LoweringContext<'_, 'hir>,
|
ctx: &mut LoweringContext<'_, 'hir>,
|
||||||
macsp: Span,
|
macsp: Span,
|
||||||
fmt: &FormatArgs,
|
fmt: &FormatArgs,
|
||||||
|
allow_const: bool,
|
||||||
) -> hir::ExprKind<'hir> {
|
) -> hir::ExprKind<'hir> {
|
||||||
let mut incomplete_lit = String::new();
|
let mut incomplete_lit = String::new();
|
||||||
let lit_pieces =
|
let lit_pieces =
|
||||||
|
@ -411,6 +415,18 @@ fn expand_format_args<'hir>(
|
||||||
|
|
||||||
let arguments = fmt.arguments.all_args();
|
let arguments = fmt.arguments.all_args();
|
||||||
|
|
||||||
|
if allow_const && arguments.is_empty() && argmap.is_empty() {
|
||||||
|
// Generate:
|
||||||
|
// <core::fmt::Arguments>::new_const(lit_pieces)
|
||||||
|
let new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||||
|
macsp,
|
||||||
|
hir::LangItem::FormatArguments,
|
||||||
|
sym::new_const,
|
||||||
|
));
|
||||||
|
let new_args = ctx.arena.alloc_from_iter([lit_pieces]);
|
||||||
|
return hir::ExprKind::Call(new, new_args);
|
||||||
|
}
|
||||||
|
|
||||||
// If the args array contains exactly all the original arguments once,
|
// If the args array contains exactly all the original arguments once,
|
||||||
// in order, we can use a simple array instead of a `match` construction.
|
// in order, we can use a simple array instead of a `match` construction.
|
||||||
// However, if there's a yield point in any argument except the first one,
|
// However, if there's a yield point in any argument except the first one,
|
||||||
|
|
|
@ -984,6 +984,7 @@ symbols! {
|
||||||
never_type_fallback,
|
never_type_fallback,
|
||||||
new,
|
new,
|
||||||
new_binary,
|
new_binary,
|
||||||
|
new_const,
|
||||||
new_debug,
|
new_debug,
|
||||||
new_display,
|
new_display,
|
||||||
new_lower_exp,
|
new_lower_exp,
|
||||||
|
|
|
@ -392,8 +392,31 @@ enum FlagV1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Arguments<'a> {
|
impl<'a> Arguments<'a> {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "fmt_internals", issue = "none")]
|
||||||
|
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
|
||||||
|
pub const fn new_const(pieces: &'a [&'static str]) -> Self {
|
||||||
|
if pieces.len() > 1 {
|
||||||
|
panic!("invalid args");
|
||||||
|
}
|
||||||
|
Arguments { pieces, fmt: None, args: &[] }
|
||||||
|
}
|
||||||
|
|
||||||
/// When using the format_args!() macro, this function is used to generate the
|
/// When using the format_args!() macro, this function is used to generate the
|
||||||
/// Arguments structure.
|
/// Arguments structure.
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
|
||||||
|
pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
|
||||||
|
if pieces.len() < args.len() || pieces.len() > args.len() + 1 {
|
||||||
|
panic!("invalid args");
|
||||||
|
}
|
||||||
|
Arguments { pieces, fmt: None, args }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
|
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
|
||||||
|
@ -417,8 +440,7 @@ impl<'a> Arguments<'a> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
|
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
|
||||||
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
|
pub fn new_v1_formatted(
|
||||||
pub const fn new_v1_formatted(
|
|
||||||
pieces: &'a [&'static str],
|
pieces: &'a [&'static str],
|
||||||
args: &'a [ArgumentV1<'a>],
|
args: &'a [ArgumentV1<'a>],
|
||||||
fmt: &'a [rt::v1::Argument],
|
fmt: &'a [rt::v1::Argument],
|
||||||
|
|
|
@ -111,7 +111,7 @@ pub const fn panic(expr: &'static str) -> ! {
|
||||||
// truncation and padding (even though none is used here). Using
|
// truncation and padding (even though none is used here). Using
|
||||||
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
|
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
|
||||||
// output binary, saving up to a few kilobytes.
|
// output binary, saving up to a few kilobytes.
|
||||||
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
|
panic_fmt(fmt::Arguments::new_const(&[expr]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize.
|
/// 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) -> ! {
|
||||||
#[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
|
#[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
pub fn panic_nounwind(expr: &'static str) -> ! {
|
pub fn panic_nounwind(expr: &'static str) -> ! {
|
||||||
panic_nounwind_fmt(fmt::Arguments::new_v1(&[expr], &[]));
|
panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: `Arguments::<'a>::new_v1` is not yet stable as a const fn
|
error: `Arguments::<'a>::new_const` is not yet stable as a const fn
|
||||||
--> $DIR/issue-64453.rs:4:31
|
--> $DIR/issue-64453.rs:4:31
|
||||||
|
|
|
|
||||||
LL | static settings_dir: String = format!("");
|
LL | static settings_dir: String = format!("");
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
const fn failure() {
|
const fn failure() {
|
||||||
panic!("{:?}", 0);
|
panic!("{:?}", 0);
|
||||||
//~^ ERROR cannot call non-const formatting macro in constant functions
|
//~^ ERROR cannot call non-const formatting macro in constant functions
|
||||||
|
//~| ERROR cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn print() {
|
const fn print() {
|
||||||
println!("{:?}", 0);
|
println!("{:?}", 0);
|
||||||
//~^ ERROR cannot call non-const formatting macro in constant functions
|
//~^ ERROR cannot call non-const formatting macro in constant functions
|
||||||
//~| ERROR `Arguments::<'a>::new_v1` is not yet stable as a const fn
|
//~| ERROR cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
|
||||||
//~| ERROR cannot call non-const fn `_print` in constant functions
|
//~| ERROR cannot call non-const fn `_print` in constant functions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,17 @@ LL | panic!("{:?}", 0);
|
||||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
= 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)
|
= 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)
|
||||||
|
|
||||||
|
error[E0015]: cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
|
||||||
|
--> $DIR/format.rs:2:5
|
||||||
|
|
|
||||||
|
LL | panic!("{:?}", 0);
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
|
= 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)
|
||||||
|
|
||||||
error[E0015]: cannot call non-const formatting macro in constant functions
|
error[E0015]: cannot call non-const formatting macro in constant functions
|
||||||
--> $DIR/format.rs:7:22
|
--> $DIR/format.rs:8:22
|
||||||
|
|
|
|
||||||
LL | println!("{:?}", 0);
|
LL | println!("{:?}", 0);
|
||||||
| ^
|
| ^
|
||||||
|
@ -16,17 +25,17 @@ LL | println!("{:?}", 0);
|
||||||
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
= 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)
|
= 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)
|
||||||
|
|
||||||
error: `Arguments::<'a>::new_v1` is not yet stable as a const fn
|
error[E0015]: cannot call non-const fn `Arguments::<'_>::new_v1` in constant functions
|
||||||
--> $DIR/format.rs:7:5
|
--> $DIR/format.rs:8:5
|
||||||
|
|
|
|
||||||
LL | println!("{:?}", 0);
|
LL | println!("{:?}", 0);
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
= 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)
|
= 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)
|
||||||
|
|
||||||
error[E0015]: cannot call non-const fn `_print` in constant functions
|
error[E0015]: cannot call non-const fn `_print` in constant functions
|
||||||
--> $DIR/format.rs:7:5
|
--> $DIR/format.rs:8:5
|
||||||
|
|
|
|
||||||
LL | println!("{:?}", 0);
|
LL | println!("{:?}", 0);
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -63,19 +72,19 @@ LL | panic!("{:?}", 0);
|
||||||
= 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)
|
= 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)
|
||||||
|
|
||||||
note: erroneous constant used
|
note: erroneous constant used
|
||||||
--> $DIR/format.rs:7:14
|
--> $DIR/format.rs:8:14
|
||||||
|
|
|
|
||||||
LL | println!("{:?}", 0);
|
LL | println!("{:?}", 0);
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
note: erroneous constant used
|
note: erroneous constant used
|
||||||
--> $DIR/format.rs:7:14
|
--> $DIR/format.rs:8:14
|
||||||
|
|
|
|
||||||
LL | println!("{:?}", 0);
|
LL | println!("{:?}", 0);
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
note: erroneous constant used
|
note: erroneous constant used
|
||||||
--> $DIR/format.rs:7:22
|
--> $DIR/format.rs:8:22
|
||||||
|
|
|
|
||||||
LL | println!("{:?}", 0);
|
LL | println!("{:?}", 0);
|
||||||
| ^
|
| ^
|
||||||
|
@ -83,13 +92,13 @@ LL | println!("{:?}", 0);
|
||||||
= 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)
|
= 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)
|
||||||
|
|
||||||
note: erroneous constant used
|
note: erroneous constant used
|
||||||
--> $DIR/format.rs:7:22
|
--> $DIR/format.rs:8:22
|
||||||
|
|
|
|
||||||
LL | println!("{:?}", 0);
|
LL | println!("{:?}", 0);
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
= 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)
|
= 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)
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 5 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0015`.
|
For more information about this error, try `rustc --explain E0015`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue