diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 490258f9c09bb..c695b2eb4dee1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,10 +46,9 @@ jobs: - name: x86_64-gnu-llvm-8 os: ubuntu-latest-xl env: {} - - name: x86_64-gnu-tools - env: - CI_ONLY_WHEN_SUBMODULES_CHANGED: 1 + - name: x86_64-gnu os: ubuntu-latest-xl + env: {} timeout-minutes: 600 runs-on: "${{ matrix.os }}" steps: diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b33cb3ad8e839..78ab5c7b809e5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -97,6 +97,7 @@ #![feature(exact_size_is_empty)] #![feature(exclusive_range_pattern)] #![feature(extend_one)] +#![feature(fmt_as_str)] #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(fundamental)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 2f744618d6936..806234ea364c4 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -101,9 +101,21 @@ macro_rules! vec { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable(fmt_as_str)] macro_rules! format { ($($arg:tt)*) => {{ - let res = $crate::fmt::format($crate::__export::format_args!($($arg)*)); - res + // NOTE: `format_args!` borrows from temporaries. This means that + // `match` is necessary to extend the lifetime of the temporaries until after + // the `Arguments` is no longer used. The same pattern is used + // inside `format_args!` itself. + let r = match $crate::__export::format_args!($($arg)*) { + // HACK: We hope that constant propagation will make LLVM optimize out + // this match. + args => match args.as_str() { + Some(s) => $crate::borrow::ToOwned::to_owned(s), + None => $crate::fmt::format(args), + } + }; + r }} } diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index ea7e65a116836..99ce05813929d 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -279,9 +279,7 @@ jobs: - name: x86_64-gnu-llvm-8 <<: *job-linux-xl - - name: x86_64-gnu-tools - env: - CI_ONLY_WHEN_SUBMODULES_CHANGED: 1 + - name: x86_64-gnu <<: *job-linux-xl try: diff --git a/src/ci/scripts/run-build-from-ci.sh b/src/ci/scripts/run-build-from-ci.sh index c02117f459de0..8515fba1e86aa 100755 --- a/src/ci/scripts/run-build-from-ci.sh +++ b/src/ci/scripts/run-build-from-ci.sh @@ -15,7 +15,9 @@ export SRC=. # the environment rustup self uninstall -y || true if [ -z "${IMAGE+x}" ]; then - src/ci/run.sh + if ! src/ci/run.sh; then + cat build/x86_64-unknown-linux-gnu/test/codegen/issue-75742-format_without_fmt_args/issue-75742-format_without_fmt_args.ll + fi else src/ci/docker/run.sh "${IMAGE}" fi diff --git a/src/test/codegen/issue-75742-format_without_fmt_args.rs b/src/test/codegen/issue-75742-format_without_fmt_args.rs new file mode 100644 index 0000000000000..3201688fb0301 --- /dev/null +++ b/src/test/codegen/issue-75742-format_without_fmt_args.rs @@ -0,0 +1,39 @@ +// min-llvm-version: 10.0.0 +// compile-flags: -C opt-level=3 +#![crate_type = "rlib"] +#![feature(format_args_capture)] + +// Make sure allocation not happen when result of `format!` is unused and +// there are no formatting arguments. + +// CHECK-LABEL: @format_wo_fmt_args +// CHECK-NEXT: {{"_ZN[^:]+"}}: +// CHECK-NEXT: ret +#[no_mangle] +pub fn format_wo_fmt_args() { + format!(""); + format!("a long story"); + format!("a long story {{"); +} + +// CHECK-LABEL: @format_wo_fmt_args_ret +// CHECK-NOT: Arguments +#[no_mangle] +pub fn format_wo_fmt_args_ret() -> String { + format!("a long story") +} + +// CHECK-LABEL: @format_w_fmt_args_ret_1 +// CHECK: alloc::fmt::format +#[no_mangle] +pub fn format_w_fmt_args_ret_1(n: usize) -> String { + format!("a long story: {}", n) +} + +// CHECK-LABEL: @format_w_fmt_args_ret_2 +// CHECK: core::fmt::ArgumentV1::from_usize +// CHECK: alloc::fmt::format +#[no_mangle] +pub fn format_w_fmt_args_ret_2(n: usize, width: usize) -> String { + format!("a long story {n:width$}") +} diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 7b0a00282fbb0..dd708a3fdcf72 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -30,35 +30,48 @@ ({ - let res = - ((::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])) - as - Arguments)) - as String); - (res as String) + let r = + (match ((::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])) + as Arguments) { + args => + (match ((args as Arguments).as_str() as + Option<&str>) { + Some(s) => + ((::alloc::borrow::ToOwned::to_owned as + for<'r> fn(&'r str) -> ::Owned {::to_owned})((s + as + &str)) + as String), + None => + ((::alloc::fmt::format as + for<'r> fn(Arguments<'r>) -> String {format})((args + as + Arguments)) + as String), + } as String), + } as String); + (r as String) } as String); } as ()) pub type Foo = [i32; (3 as usize)]; diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs index 3e803f3b6d8b2..8ccb8f0050685 100644 --- a/src/test/ui/borrowck/issue-64453.rs +++ b/src/test/ui/borrowck/issue-64453.rs @@ -4,6 +4,8 @@ struct Value; static settings_dir: String = format!(""); //~^ ERROR calls in statics are limited to constant functions //~| ERROR calls in statics are limited to constant functions +//~| ERROR calls in statics are limited to constant functions +//~| ERROR calls in statics are limited to constant functions fn from_string(_: String) -> Value { Value diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index fba801983cf4e..38cbb7fc9585a 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of static item `settings_dir` - --> $DIR/issue-64453.rs:14:37 + --> $DIR/issue-64453.rs:16:37 | LL | let settings_data = from_string(settings_dir); | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait @@ -20,7 +20,23 @@ LL | static settings_dir: String = format!(""); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0015, E0507. For more information about an error, try `rustc --explain E0015`.