diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 653116e1fe00d..ed35da87e0abb 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -5,6 +5,7 @@ use rustc_ast::visit::Visitor; use rustc_ast::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_session::config::FmtDebug; use rustc_span::symbol::{Ident, kw}; use rustc_span::{Span, Symbol, sym}; @@ -24,6 +25,28 @@ impl<'hir> LoweringContext<'_, 'hir> { expand_format_args(self, sp, &fmt, allow_const) } + /// Wraps given `ExprKind` in an inline const block. + /// + /// Caller must ensure it's safe and sound to do so. + fn wrap_in_const_context( + &mut self, + sp: Span, + kind: hir::ExprKind<'hir>, + ) -> hir::ExprKind<'hir> { + let expr = hir::Expr { hir_id: self.next_id(), kind, span: self.lower_span(sp) }; + let const_node_id = self.next_node_id(); + let parent_def_id = self.current_def_id_parent; + let def_id = + self.create_def(parent_def_id, const_node_id, kw::Empty, DefKind::InlineConst, sp); + let hir_id = self.lower_node_id(const_node_id); + let const_block = self.with_new_scopes(sp, |this| hir::ConstBlock { + def_id, + hir_id, + body: this.with_def_id_parent(def_id, |this| this.lower_body(|_| (&[], expr))), + }); + hir::ExprKind::ConstBlock(const_block) + } + /// Try to convert a literal into an interned string fn try_inline_lit(&self, lit: token::Lit) -> Option { match LitKind::from_token_lit(lit) { @@ -464,14 +487,14 @@ fn expand_format_args<'hir>( if allow_const && arguments.is_empty() && argmap.is_empty() { // Generate: - // ::new_const(lit_pieces) + // const { ::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); + return ctx.wrap_in_const_context(macsp, hir::ExprKind::Call(new, new_args)); } // If the args array contains exactly all the original arguments once, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 4cbcfb07795bd..4f2228aaae789 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -333,7 +333,7 @@ pub struct Arguments<'a> { #[unstable(feature = "fmt_internals", issue = "none")] impl<'a> Arguments<'a> { #[inline] - #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] + #[rustc_const_stable(feature = "const_fmt_arguments_new", since = "CURRENT_RUSTC_VERSION")] pub const fn new_const(pieces: &'a [&'static str; N]) -> Self { const { assert!(N <= 1) }; Arguments { pieces, fmt: None, args: &[] } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index b21618e28a48e..86909d37d6890 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -120,7 +120,6 @@ #![feature(const_char_encode_utf16)] #![feature(const_eval_select)] #![feature(const_exact_div)] -#![feature(const_fmt_arguments_new)] #![feature(const_hash)] #![feature(const_heap)] #![feature(const_index_range_slice_index)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index aa0646846e43e..a517414f704d2 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1038,7 +1038,7 @@ pub(crate) mod builtin { /// /// This macro will be removed once `format_args` is allowed in const contexts. #[unstable(feature = "const_format_args", issue = "none")] - #[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)] + #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] #[macro_export] macro_rules! const_format_args { diff --git a/tests/codegen/issues/issue-128709-format-without-args.rs b/tests/codegen/issues/issue-128709-format-without-args.rs new file mode 100644 index 0000000000000..c9a63822eff24 --- /dev/null +++ b/tests/codegen/issues/issue-128709-format-without-args.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -C no-prepopulate-passes -C opt-level=0 + +#![crate_type = "lib"] + +// String formating macros without any arguments should compile +// to a `memcpy` followed by a call to a library function. + +#[no_mangle] +pub fn code() { + // CHECK-LABEL: @code + // CHECK-NOT: getelementptr + // CHECK-NOT: store + // CHECK-NOT: ; call core::fmt::Arguments::new_const + // CHECK: call void @llvm.memcpy + // CHECK-NEXT: ; call std::io::stdio::_print + println!("hello world"); +} diff --git a/tests/ui/borrowck/issue-64453.rs b/tests/ui/borrowck/issue-64453.rs index 33d55be5812e7..5f1f35d6ca9bb 100644 --- a/tests/ui/borrowck/issue-64453.rs +++ b/tests/ui/borrowck/issue-64453.rs @@ -3,7 +3,6 @@ struct Value; static settings_dir: String = format!(""); //~^ ERROR cannot call non-const fn -//~| ERROR is not yet stable as a const fn from_string(_: String) -> Value { Value diff --git a/tests/ui/borrowck/issue-64453.stderr b/tests/ui/borrowck/issue-64453.stderr index e671817633be4..98b05ead64918 100644 --- a/tests/ui/borrowck/issue-64453.stderr +++ b/tests/ui/borrowck/issue-64453.stderr @@ -1,12 +1,3 @@ -error: `Arguments::<'a>::new_const` is not yet stable as a const fn - --> $DIR/issue-64453.rs:4:31 - | -LL | static settings_dir: String = format!(""); - | ^^^^^^^^^^^ - | - = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable - = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0015]: cannot call non-const fn `format` in statics --> $DIR/issue-64453.rs:4:31 | @@ -18,7 +9,7 @@ LL | static settings_dir: String = format!(""); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0507]: cannot move out of static item `settings_dir` - --> $DIR/issue-64453.rs:14:37 + --> $DIR/issue-64453.rs:13:37 | LL | let settings_data = from_string(settings_dir); | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait @@ -28,7 +19,7 @@ help: consider cloning the value if the performance cost is acceptable LL | let settings_data = from_string(settings_dir.clone()); | ++++++++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0015, E0507. For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-format-arguments.rs b/tests/ui/consts/const-format-arguments.rs new file mode 100644 index 0000000000000..7e6e5371d6df5 --- /dev/null +++ b/tests/ui/consts/const-format-arguments.rs @@ -0,0 +1,5 @@ +pub fn main() { + const A: std::fmt::Arguments = std::fmt::Arguments::new_const(&[&"hola"]); + //~^ use of unstable library feature + //~| temporary value dropped while borrowed +} diff --git a/tests/ui/consts/const-format-arguments.stderr b/tests/ui/consts/const-format-arguments.stderr new file mode 100644 index 0000000000000..a88e4fd44daf8 --- /dev/null +++ b/tests/ui/consts/const-format-arguments.stderr @@ -0,0 +1,23 @@ +error[E0658]: use of unstable library feature 'fmt_internals' + --> $DIR/const-format-arguments.rs:3:36 + | +LL | const A: std::fmt::Arguments = std::fmt::Arguments::new_const(&[&"hola"]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(fmt_internals)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0716]: temporary value dropped while borrowed + --> $DIR/const-format-arguments.rs:3:68 + | +LL | const A: std::fmt::Arguments = std::fmt::Arguments::new_const(&[&"hola"]); + | --------------------------------^^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | using this value as a constant requires that borrow lasts for `'static` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0658, E0716. +For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs index b8b9e07b3bd60..cdefebc87d675 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Znext-solver #![allow(incomplete_features)] -#![feature(const_fmt_arguments_new)] #![feature(const_trait_impl, effects)] #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr index 9e6348d37ed5e..49f380c1a2b57 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-79450.stderr @@ -1,5 +1,5 @@ error[E0015]: cannot call non-const fn `_print` in constant functions - --> $DIR/issue-79450.rs:11:9 + --> $DIR/issue-79450.rs:10:9 | LL | println!("lul"); | ^^^^^^^^^^^^^^^