From e0af3c61cd5b90e53c720246f40bf47e97429aa2 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 16 Jul 2024 15:43:40 -0500 Subject: [PATCH 01/10] When an archive fails to build, print the path Currently the output on failure is as follows: Compiling block-buffer v0.10.4 Compiling crypto-common v0.1.6 Compiling digest v0.10.7 Compiling sha2 v0.10.8 Compiling xz2 v0.1.7 error: failed to build archive: No such file or directory error: could not compile `bootstrap` (lib) due to 1 previous error Print which file is being constructed to give some hint about what is going on. --- compiler/rustc_codegen_llvm/src/back/archive.rs | 4 +++- compiler/rustc_codegen_ssa/messages.ftl | 5 ++--- compiler/rustc_codegen_ssa/src/back/archive.rs | 4 +++- compiler/rustc_codegen_ssa/src/back/link.rs | 3 ++- compiler/rustc_codegen_ssa/src/errors.rs | 2 ++ 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index a354f3d353610..eca0ead8666b0 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -101,7 +101,9 @@ impl<'a> ArchiveBuilder for LlvmArchiveBuilder<'a> { fn build(mut self: Box, output: &Path) -> bool { match self.build_with_llvm(output) { Ok(any_members) => any_members, - Err(e) => self.sess.dcx().emit_fatal(ArchiveBuildFailure { error: e }), + Err(error) => { + self.sess.dcx().emit_fatal(ArchiveBuildFailure { path: output.to_owned(), error }) + } } } } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 000fe2e3ce0f5..57d789aef80ca 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -4,8 +4,7 @@ codegen_ssa_add_native_library = failed to add native library {$library_path}: { codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error} -codegen_ssa_archive_build_failure = - failed to build archive: {$error} +codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error} codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering @@ -198,7 +197,7 @@ codegen_ssa_read_file = failed to read file: {$message} codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer -codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib: {$error} +codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib at `{$path}`: {$error} codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`) diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index c99118f5156d1..31b437555f440 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -220,7 +220,9 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> { let sess = self.sess; match self.build_inner(output) { Ok(any_members) => any_members, - Err(e) => sess.dcx().emit_fatal(ArchiveBuildFailure { error: e }), + Err(error) => { + sess.dcx().emit_fatal(ArchiveBuildFailure { path: output.to_owned(), error }) + } } } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1f627353d54e1..b6ca9476ecd73 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2911,7 +2911,8 @@ fn add_static_crate( false }), ) { - sess.dcx().emit_fatal(errors::RlibArchiveBuildFailure { error }); + sess.dcx() + .emit_fatal(errors::RlibArchiveBuildFailure { path: cratepath.clone(), error }); } if archive.build(&dst) { link_upstream(&dst); diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index e9d31db92541b..138e53f2106f6 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -497,6 +497,7 @@ pub struct UnableToWriteDebuggerVisualizer { #[derive(Diagnostic)] #[diag(codegen_ssa_rlib_archive_build_failure)] pub struct RlibArchiveBuildFailure { + pub path: PathBuf, pub error: Error, } @@ -554,6 +555,7 @@ pub struct UnsupportedLinkSelfContained; #[diag(codegen_ssa_archive_build_failure)] // Public for rustc_codegen_llvm::back::archive pub struct ArchiveBuildFailure { + pub path: PathBuf, pub error: std::io::Error, } From eb3c9327b1f56fbd391673698f60a4ba8425dae0 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Mon, 29 Jul 2024 13:06:06 -0400 Subject: [PATCH 02/10] rewrite cross-lang-lto-clang to rmake --- .../run-make-support/src/assertion_helpers.rs | 32 +++++++++- src/tools/run-make-support/src/command.rs | 33 +++++++++- src/tools/run-make-support/src/lib.rs | 3 +- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/cross-lang-lto-clang/Makefile | 25 -------- tests/run-make/cross-lang-lto-clang/rmake.rs | 61 +++++++++++++++++++ 6 files changed, 126 insertions(+), 29 deletions(-) delete mode 100644 tests/run-make/cross-lang-lto-clang/Makefile create mode 100644 tests/run-make/cross-lang-lto-clang/rmake.rs diff --git a/src/tools/run-make-support/src/assertion_helpers.rs b/src/tools/run-make-support/src/assertion_helpers.rs index 4b5b349431db9..6d256fc594d8e 100644 --- a/src/tools/run-make-support/src/assertion_helpers.rs +++ b/src/tools/run-make-support/src/assertion_helpers.rs @@ -3,7 +3,7 @@ use std::panic; use std::path::Path; -use crate::fs; +use crate::{fs, regex}; /// Assert that `actual` is equal to `expected`. #[track_caller] @@ -47,6 +47,36 @@ pub fn assert_not_contains, N: AsRef>(haystack: H, needle: N) } } +/// Assert that `haystack` contains the regex pattern `needle`. +#[track_caller] +pub fn assert_contains_regex, N: AsRef>(haystack: H, needle: N) { + let haystack = haystack.as_ref(); + let needle = needle.as_ref(); + let re = regex::Regex::new(needle).unwrap(); + if !re.is_match(haystack) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was not found in haystack"); + } +} + +/// Assert that `haystack` does not contain the regex pattern `needle`. +#[track_caller] +pub fn assert_not_contains_regex, N: AsRef>(haystack: H, needle: N) { + let haystack = haystack.as_ref(); + let needle = needle.as_ref(); + let re = regex::Regex::new(needle).unwrap(); + if re.is_match(haystack) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was unexpectedly found in haystack"); + } +} + /// Assert that all files in `dir1` exist and have the same content in `dir2` pub fn assert_dirs_are_equal(dir1: impl AsRef, dir2: impl AsRef) { let dir2 = dir2.as_ref(); diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index fb94ff996f0d6..dd7c0e32cf129 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -7,7 +7,10 @@ use std::{ffi, panic}; use build_helper::drop_bomb::DropBomb; use crate::util::handle_failed_output; -use crate::{assert_contains, assert_equals, assert_not_contains}; +use crate::{ + assert_contains, assert_contains_regex, assert_equals, assert_not_contains, + assert_not_contains_regex, +}; /// This is a custom command wrapper that simplifies working with commands and makes it easier to /// ensure that we check the exit status of executed processes. @@ -191,6 +194,13 @@ impl CompletedProcess { self } + /// Checks that `stdout` does not contain the regex pattern `unexpected`. + #[track_caller] + pub fn assert_stdout_not_contains_regex>(&self, unexpected: S) -> &Self { + assert_not_contains_regex(&self.stdout_utf8(), unexpected); + self + } + /// Checks that `stdout` contains `expected`. #[track_caller] pub fn assert_stdout_contains>(&self, expected: S) -> &Self { @@ -198,6 +208,13 @@ impl CompletedProcess { self } + /// Checks that `stdout` contains the regex pattern `expected`. + #[track_caller] + pub fn assert_stdout_contains_regex>(&self, expected: S) -> &Self { + assert_contains_regex(&self.stdout_utf8(), expected); + self + } + /// Checks that trimmed `stderr` matches trimmed `expected`. #[track_caller] pub fn assert_stderr_equals>(&self, expected: S) -> &Self { @@ -212,6 +229,13 @@ impl CompletedProcess { self } + /// Checks that `stderr` contains the regex pattern `expected`. + #[track_caller] + pub fn assert_stderr_contains_regex>(&self, expected: S) -> &Self { + assert_contains_regex(&self.stderr_utf8(), expected); + self + } + /// Checks that `stderr` does not contain `unexpected`. #[track_caller] pub fn assert_stderr_not_contains>(&self, unexpected: S) -> &Self { @@ -219,6 +243,13 @@ impl CompletedProcess { self } + /// Checks that `stderr` does not contain the regex pattern `unexpected`. + #[track_caller] + pub fn assert_stderr_not_contains_regex>(&self, unexpected: S) -> &Self { + assert_not_contains_regex(&self.stdout_utf8(), unexpected); + self + } + #[track_caller] pub fn assert_exit_code(&self, code: i32) -> &Self { assert!(self.output.status.code() == Some(code)); diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 085120764b463..6dfe7a8bcf7ad 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -84,7 +84,8 @@ pub use path_helpers::{ pub use scoped_run::{run_in_tmpdir, test_while_readonly}; pub use assertion_helpers::{ - assert_contains, assert_dirs_are_equal, assert_equals, assert_not_contains, + assert_contains, assert_contains_regex, assert_dirs_are_equal, assert_equals, + assert_not_contains, assert_not_contains_regex, }; pub use string::{ diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 7284feadf9cdd..817259ee92166 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,7 +1,6 @@ run-make/branch-protection-check-IBT/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile -run-make/cross-lang-lto-clang/Makefile run-make/cross-lang-lto-pgo-smoketest/Makefile run-make/cross-lang-lto-upstream-rlibs/Makefile run-make/cross-lang-lto/Makefile diff --git a/tests/run-make/cross-lang-lto-clang/Makefile b/tests/run-make/cross-lang-lto-clang/Makefile deleted file mode 100644 index acf49c8f5c85d..0000000000000 --- a/tests/run-make/cross-lang-lto-clang/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# needs-force-clang-based-tests - -# This test makes sure that cross-language inlining actually works by checking -# the generated machine code. - -include ../tools.mk - -all: cpp-executable rust-executable - -cpp-executable: - $(RUSTC) -Clinker-plugin-lto=on -o $(TMPDIR)/librustlib-xlto.a -Copt-level=2 -Ccodegen-units=1 ./rustlib.rs - $(CLANG) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3 - # Make sure we don't find a call instruction to the function we expect to - # always be inlined. - "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined" - # As a sanity check, make sure we do find a call instruction to a - # non-inlined function - "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined" - -rust-executable: - $(CLANG) ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2 - (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o) - $(RUSTC) -Clinker-plugin-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=$(CLANG) -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain - "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined" - "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined" diff --git a/tests/run-make/cross-lang-lto-clang/rmake.rs b/tests/run-make/cross-lang-lto-clang/rmake.rs new file mode 100644 index 0000000000000..114b2d355793f --- /dev/null +++ b/tests/run-make/cross-lang-lto-clang/rmake.rs @@ -0,0 +1,61 @@ +// This test checks that cross-language inlining actually works by checking +// the generated machine code. +// See https://github.com/rust-lang/rust/pull/57514 + +//@ needs-force-clang-based-tests +// FIXME(#126180): This test doesn't actually run anywhere, because the only +// CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests. + +use run_make_support::{clang, env_var, llvm_ar, llvm_objdump, rustc, static_lib_name}; + +fn main() { + rustc() + .linker_plugin_lto("on") + .output(static_lib_name("rustlib-xlto")) + .opt_level("2") + .codegen_units(1) + .input("rustlib.rs") + .run(); + clang() + .lto("thin") + .use_ld("lld") + .arg("-lrustlib-xlto") + .out_exe("cmain") + .input("cmain.c") + .arg("-O3") + .run(); + // Make sure we don't find a call instruction to the function we expect to + // always be inlined. + llvm_objdump() + .arg("-d") + .input("cmain") + .run() + .assert_stdout_not_contains_regex("call.*rust_always_inlined"); + // As a sanity check, make sure we do find a call instruction to a + // non-inlined function + llvm_objdump() + .arg("-d") + .input("cmain") + .run() + .assert_stdout_contains_regex("call.*rust_never_inlined"); + clang().input("clib.c").lto("thin").arg("-c").out_exe("clib.o").arg("-O2").run(); + llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run(); + rustc() + .linker_plugin_lto("on") + .opt_level("2") + .linker(&env_var("CLANG")) + .link_arg("-fuse-ld=lld") + .input("main.rs") + .output("rsmain") + .run(); + llvm_objdump() + .arg("-d") + .input("rsmain") + .run() + .assert_stdout_not_contains_regex("call.*c_always_inlined"); + llvm_objdump() + .arg("-d") + .input("rsmain") + .run() + .assert_stdout_contains_regex("call.*c_never_inlined"); +} From 918cdcc9c542eea0d7d3d4517dead7ae9a704e3e Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Tue, 30 Jul 2024 19:36:28 +0800 Subject: [PATCH 03/10] More detailed note to deprecate ONCE_INIT --- library/std/src/sync/once.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 9d969af8c6d84..5e0694e8de2db 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -70,7 +70,7 @@ pub(crate) enum ExclusiveState { #[stable(feature = "rust1", since = "1.0.0")] #[deprecated( since = "1.38.0", - note = "the `new` function is now preferred", + note = "the `Once::new()` function is now preferred", suggestion = "Once::new()" )] pub const ONCE_INIT: Once = Once::new(); From b7e90fe2c6c8461609b2abb6cba5e1b06b5522a1 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Mon, 29 Jul 2024 14:08:43 -0400 Subject: [PATCH 04/10] rewrite cross-lang-lto-pgo-smoketest to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/cross-lang-lto-clang/_Makefile | 29 +++++ .../{Makefile => _Makefile} | 4 + .../cross-lang-lto-pgo-smoketest/rmake.rs | 111 ++++++++++++++++++ 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/cross-lang-lto-clang/_Makefile rename tests/run-make/cross-lang-lto-pgo-smoketest/{Makefile => _Makefile} (94%) create mode 100644 tests/run-make/cross-lang-lto-pgo-smoketest/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 817259ee92166..6039f38123791 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,7 +1,6 @@ run-make/branch-protection-check-IBT/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile -run-make/cross-lang-lto-pgo-smoketest/Makefile run-make/cross-lang-lto-upstream-rlibs/Makefile run-make/cross-lang-lto/Makefile run-make/dep-info-doesnt-run-much/Makefile diff --git a/tests/run-make/cross-lang-lto-clang/_Makefile b/tests/run-make/cross-lang-lto-clang/_Makefile new file mode 100644 index 0000000000000..b039328b0f9e8 --- /dev/null +++ b/tests/run-make/cross-lang-lto-clang/_Makefile @@ -0,0 +1,29 @@ +# FIXME(Oneirical): This is already implemented as an rmake.rs file, but due to #126180, +# the rmake.rs is not ran on CI. Once the rmake test has been proven to work, remove this +# Makefile. + +# needs-force-clang-based-tests + +# This test makes sure that cross-language inlining actually works by checking +# the generated machine code. + +include ../tools.mk + +all: cpp-executable rust-executable + +cpp-executable: + $(RUSTC) -Clinker-plugin-lto=on -o $(TMPDIR)/librustlib-xlto.a -Copt-level=2 -Ccodegen-units=1 ./rustlib.rs + $(CLANG) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3 + # Make sure we don't find a call instruction to the function we expect to + # always be inlined. + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined" + # As a sanity check, make sure we do find a call instruction to a + # non-inlined function + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined" + +rust-executable: + $(CLANG) ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2 + (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o) + $(RUSTC) -Clinker-plugin-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=$(CLANG) -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined" + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined" diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile b/tests/run-make/cross-lang-lto-pgo-smoketest/_Makefile similarity index 94% rename from tests/run-make/cross-lang-lto-pgo-smoketest/Makefile rename to tests/run-make/cross-lang-lto-pgo-smoketest/_Makefile index 738e23f9c6614..737f066b4da03 100644 --- a/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile +++ b/tests/run-make/cross-lang-lto-pgo-smoketest/_Makefile @@ -1,3 +1,7 @@ +# FIXME(Oneirical): This is already implemented as an rmake.rs file, but due to #126180, +# the rmake.rs is not ran on CI. Once the rmake test has been proven to work, remove this +# Makefile. + # needs-force-clang-based-tests # FIXME(#126180): This test doesn't actually run anywhere, because the only diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/rmake.rs b/tests/run-make/cross-lang-lto-pgo-smoketest/rmake.rs new file mode 100644 index 0000000000000..e4d8879607fd8 --- /dev/null +++ b/tests/run-make/cross-lang-lto-pgo-smoketest/rmake.rs @@ -0,0 +1,111 @@ +// This test makes sure that cross-language inlining can be used in conjunction +// with profile-guided optimization. The test only tests that the whole workflow +// can be executed without anything crashing. It does not test whether PGO or +// xLTO have any specific effect on the generated code. +// See https://github.com/rust-lang/rust/pull/61036 + +//@ needs-force-clang-based-tests +// FIXME(#126180): This test doesn't actually run anywhere, because the only +// CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests. + +//FIXME(Oneirical): There was a strange workaround for MSVC on this test +// which added -C panic=abort to every RUSTC call. It was justified as follows: +// LLVM doesn't support instrumenting binaries that use SEH: +// https://bugs.llvm.org/show_bug.cgi?id=41279 +// Things work fine with -Cpanic=abort though. + +use run_make_support::{ + clang, env_var, has_extension, has_prefix, llvm_ar, llvm_profdata, rfs, run, rustc, + shallow_find_files, static_lib_name, +}; + +fn main() { + rustc() + .linker_plugin_lto("on") + .output(static_lib_name("rustlib-xlto")) + .opt_level("3") + .codegen_units(1) + .input("rustlib.rs") + .arg("-Cprofile-generate=cpp-profdata") + .run(); + clang() + .lto("thin") + .arg("-fprofile-generate=cpp-profdata") + .use_ld("lld") + .arg("-lrustlib-xlto") + .out_exe("cmain") + .input("cmain.c") + .arg("-O3") + .run(); + run("cmain"); + // Postprocess the profiling data so it can be used by the compiler + let profraw_files = shallow_find_files("cpp-profdata", |path| { + has_prefix(path, "default") && has_extension(path, "profraw") + }); + let profraw_file = profraw_files.get(0).unwrap(); + llvm_profdata().merge().output("cpp-profdata/merged.profdata").input(profraw_file).run(); + rustc() + .linker_plugin_lto("on") + .profile_use("cpp-profdata/merged.profdata") + .output(static_lib_name("rustlib-xlto")) + .opt_level("3") + .codegen_units(1) + .input("rustlib.rs") + .run(); + clang() + .lto("thin") + .arg("-fprofile-use=cpp-profdata/merged.profdata") + .use_ld("lld") + .arg("-lrustlib-xlto") + .out_exe("cmain") + .input("cmain.c") + .arg("-O3") + .run(); + + clang() + .input("clib.c") + .arg("-fprofile-generate=rs-profdata") + .lto("thin") + .arg("-c") + .out_exe("clib.o") + .arg("-O3") + .run(); + llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run(); + rustc() + .linker_plugin_lto("on") + .opt_level("3") + .codegen_units(1) + .arg("-Cprofile-generate=rs-profdata") + .linker(&env_var("CLANG")) + .link_arg("-fuse-ld=lld") + .input("main.rs") + .output("rsmain") + .run(); + run("rsmain"); + // Postprocess the profiling data so it can be used by the compiler + let profraw_files = shallow_find_files("rs-profdata", |path| { + has_prefix(path, "default") && has_extension(path, "profraw") + }); + let profraw_file = profraw_files.get(0).unwrap(); + llvm_profdata().merge().output("rs-profdata/merged.profdata").input(profraw_file).run(); + clang() + .input("clib.c") + .arg("-fprofile-use=rs-profdata/merged.profdata") + .arg("-c") + .lto("thin") + .out_exe("clib.o") + .arg("-O3") + .run(); + rfs::remove_file(static_lib_name("xyz")); + llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run(); + rustc() + .linker_plugin_lto("on") + .opt_level("3") + .codegen_units(1) + .arg("-Cprofile-use=rs-profdata/merged.profdata") + .linker(&env_var("CLANG")) + .link_arg("-fuse-ld=lld") + .input("main.rs") + .output("rsmain") + .run(); +} From 4feb949617c9a24f8750d8a69197f086b0005cee Mon Sep 17 00:00:00 2001 From: binarycat Date: Wed, 24 Jul 2024 14:05:58 -0400 Subject: [PATCH 05/10] migrate fmt-write-bloat to rmake --- src/tools/run-make-support/src/env.rs | 7 +++ src/tools/run-make-support/src/lib.rs | 1 + src/tools/run-make-support/src/symbols.rs | 43 +++++++++++++++++++ .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/fmt-write-bloat/Makefile | 25 ----------- tests/run-make/fmt-write-bloat/rmake.rs | 35 +++++++++++++++ 6 files changed, 86 insertions(+), 26 deletions(-) create mode 100644 src/tools/run-make-support/src/symbols.rs delete mode 100644 tests/run-make/fmt-write-bloat/Makefile create mode 100644 tests/run-make/fmt-write-bloat/rmake.rs diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs index f52524e7d54cd..e6460fb93d3e9 100644 --- a/src/tools/run-make-support/src/env.rs +++ b/src/tools/run-make-support/src/env.rs @@ -17,3 +17,10 @@ pub fn env_var_os(name: &str) -> OsString { None => panic!("failed to retrieve environment variable {name:?}"), } } + +/// Check if `NO_DEBUG_ASSERTIONS` is set (usually this may be set in CI jobs). +#[track_caller] +#[must_use] +pub fn no_debug_assertions() -> bool { + std::env::var_os("NO_DEBUG_ASSERTIONS").is_some() +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 085120764b463..36ea6125f2780 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -21,6 +21,7 @@ pub mod run; pub mod scoped_run; pub mod string; pub mod targets; +pub mod symbols; // Internally we call our fs-related support module as `fs`, but re-export its content as `rfs` // to tests to avoid colliding with commonly used `use std::fs;`. diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/symbols.rs new file mode 100644 index 0000000000000..52119ba4991a8 --- /dev/null +++ b/src/tools/run-make-support/src/symbols.rs @@ -0,0 +1,43 @@ +use object::{self, Object, ObjectSymbol, SymbolIterator}; +use std::path::Path; + +/// Iterate through the symbols in an object file. +/// +/// Uses a callback because `SymbolIterator` does not own its data. +/// +/// Panics if `path` is not a valid object file readable by the current user. +pub fn with_symbol_iter(path: P, func: F) -> R +where + P: AsRef, + F: FnOnce(&mut SymbolIterator<'_, '_>) -> R, +{ + let raw_bytes = crate::fs::read(path); + let f = object::File::parse(raw_bytes.as_slice()).expect("unable to parse file"); + let mut iter = f.symbols(); + func(&mut iter) +} + +/// Check an object file's symbols for substrings. +/// +/// Returns `true` if any of the symbols found in the object file at +/// `path` contain a substring listed in `substrings`. +/// +/// Panics if `path` is not a valid object file readable by the current user. +pub fn any_symbol_contains(path: impl AsRef, substrings: &[&str]) -> bool { + with_symbol_iter(path, |syms| { + for sym in syms { + for substring in substrings { + if sym + .name_bytes() + .unwrap() + .windows(substring.len()) + .any(|x| x == substring.as_bytes()) + { + eprintln!("{:?} contains {}", sym, substring); + return true; + } + } + } + false + }) +} diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index a84b89ff4a113..db06040de2b3a 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -10,7 +10,6 @@ run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile run-make/emit-to-stdout/Makefile run-make/extern-fn-reachable/Makefile -run-make/fmt-write-bloat/Makefile run-make/foreign-double-unwind/Makefile run-make/foreign-exceptions/Makefile run-make/incr-add-rust-src-component/Makefile diff --git a/tests/run-make/fmt-write-bloat/Makefile b/tests/run-make/fmt-write-bloat/Makefile deleted file mode 100644 index 70e04b9af51fe..0000000000000 --- a/tests/run-make/fmt-write-bloat/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -include ../tools.mk - -# ignore-windows - -ifeq ($(shell $(RUSTC) -vV | grep 'host: $(TARGET)'),) - -# Don't run this test when cross compiling. -all: - -else - -NM = nm - -PANIC_SYMS = panic_bounds_check Debug - -# Allow for debug_assert!() in debug builds of std. -ifdef NO_DEBUG_ASSERTIONS -PANIC_SYMS += panicking panic_fmt pad_integral Display Debug -endif - -all: main.rs - $(RUSTC) $< -O - $(NM) $(call RUN_BINFILE,main) | $(CGREP) -v $(PANIC_SYMS) - -endif diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs new file mode 100644 index 0000000000000..120c1cbccdd3c --- /dev/null +++ b/tests/run-make/fmt-write-bloat/rmake.rs @@ -0,0 +1,35 @@ +//! Before #78122, writing any `fmt::Arguments` would trigger the inclusion of `usize` formatting +//! and padding code in the resulting binary, because indexing used in `fmt::write` would generate +//! code using `panic_bounds_check`, which prints the index and length. +//! +//! These bounds checks are not necessary, as `fmt::Arguments` never contains any out-of-bounds +//! indexes. The test is a `run-make` test, because it needs to check the result after linking. A +//! codegen or assembly test doesn't check the parts that will be pulled in from `core` by the +//! linker. +//! +//! In this test, we try to check that the `usize` formatting and padding code are not present in +//! the final binary by checking that panic symbols such as `panic_bounds_check` are **not** +//! present. +//! +//! Some CI jobs try to run faster by disabling debug assertions (through setting +//! `NO_DEBUG_ASSERTIONS=1`). If debug assertions are disabled, then we can check for the absence of +//! additional `usize` formatting and padding related symbols. + +// Reason: This test is `ignore-windows` because the `no_std` test (using `#[link(name = "c")])` +// doesn't link on windows. +//@ ignore-windows +//@ ignore-cross-compile + +use run_make_support::{env::no_debug_assertions, rustc, symbols::any_symbol_contains}; + +fn main() { + rustc().input("main.rs").opt().run(); + // panic machinery identifiers, these should not appear in the final binary + let mut panic_syms = vec!["panic_bounds_check", "Debug"]; + if no_debug_assertions() { + // if debug assertions are allowed, we need to allow these, + // otherwise, add them to the list of symbols to deny. + panic_syms.extend_from_slice(&["panicking", "panic_fmt", "pad_integral", "Display"]); + } + assert!(!any_symbol_contains("main", &panic_syms)); +} From ebd6718218642b8b63584214e35f7d69d24ae845 Mon Sep 17 00:00:00 2001 From: binarycat Date: Tue, 30 Jul 2024 13:33:25 -0400 Subject: [PATCH 06/10] tidy this commit cannot easily be squashed, since there is already a PR based on the previous commit. --- src/tools/run-make-support/src/symbols.rs | 3 ++- tests/run-make/fmt-write-bloat/rmake.rs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/symbols.rs index 52119ba4991a8..fd0c866bcc927 100644 --- a/src/tools/run-make-support/src/symbols.rs +++ b/src/tools/run-make-support/src/symbols.rs @@ -1,6 +1,7 @@ -use object::{self, Object, ObjectSymbol, SymbolIterator}; use std::path::Path; +use object::{self, Object, ObjectSymbol, SymbolIterator}; + /// Iterate through the symbols in an object file. /// /// Uses a callback because `SymbolIterator` does not own its data. diff --git a/tests/run-make/fmt-write-bloat/rmake.rs b/tests/run-make/fmt-write-bloat/rmake.rs index 120c1cbccdd3c..4ae226ec0e234 100644 --- a/tests/run-make/fmt-write-bloat/rmake.rs +++ b/tests/run-make/fmt-write-bloat/rmake.rs @@ -20,7 +20,9 @@ //@ ignore-windows //@ ignore-cross-compile -use run_make_support::{env::no_debug_assertions, rustc, symbols::any_symbol_contains}; +use run_make_support::env::no_debug_assertions; +use run_make_support::rustc; +use run_make_support::symbols::any_symbol_contains; fn main() { rustc().input("main.rs").opt().run(); From e7f89a7eea766af95604405d666e089a42cd4b48 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Sat, 13 Jul 2024 20:14:22 +0800 Subject: [PATCH 07/10] derive(SmartPointer): rewrite bounds in where and generic bounds --- .../src/deriving/smart_ptr.rs | 244 ++++++++++++++++-- .../deriving-smart-pointer-expanded.rs | 22 ++ .../deriving-smart-pointer-expanded.stdout | 44 ++++ .../smart-pointer-bounds-issue-127647.rs | 78 ++++++ 4 files changed, 371 insertions(+), 17 deletions(-) create mode 100644 tests/ui/deriving/deriving-smart-pointer-expanded.rs create mode 100644 tests/ui/deriving/deriving-smart-pointer-expanded.stdout create mode 100644 tests/ui/deriving/smart-pointer-bounds-issue-127647.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs index bbc7cd3962720..02555bd799c42 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs @@ -1,14 +1,18 @@ use std::mem::swap; +use ast::ptr::P; use ast::HasAttrs; +use rustc_ast::mut_visit::MutVisitor; +use rustc_ast::visit::BoundKind; use rustc_ast::{ self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem, - TraitBoundModifiers, VariantData, + TraitBoundModifiers, VariantData, WherePredicate, }; use rustc_attr as attr; +use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use smallvec::{smallvec, SmallVec}; use thin_vec::{thin_vec, ThinVec}; @@ -141,33 +145,239 @@ pub fn expand_deriving_smart_ptr( alt_self_params[pointee_param_idx] = GenericArg::Type(s_ty.clone()); let alt_self_type = cx.ty_path(cx.path_all(span, false, vec![name_ident], alt_self_params)); + // # Add `Unsize<__S>` bound to `#[pointee]` at the generic parameter location + // // Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it. let mut impl_generics = generics.clone(); + let pointee_ty_ident = generics.params[pointee_param_idx].ident; + let mut self_bounds; { - let p = &mut impl_generics.params[pointee_param_idx]; + let pointee = &mut impl_generics.params[pointee_param_idx]; + self_bounds = pointee.bounds.clone(); let arg = GenericArg::Type(s_ty.clone()); let unsize = cx.path_all(span, true, path!(span, core::marker::Unsize), vec![arg]); - p.bounds.push(cx.trait_bound(unsize, false)); + pointee.bounds.push(cx.trait_bound(unsize, false)); let mut attrs = thin_vec![]; - swap(&mut p.attrs, &mut attrs); - p.attrs = attrs.into_iter().filter(|attr| !attr.has_name(sym::pointee)).collect(); + swap(&mut pointee.attrs, &mut attrs); + // Drop `#[pointee]` attribute since it should not be recognized outside `derive(SmartPointer)` + pointee.attrs = attrs.into_iter().filter(|attr| !attr.has_name(sym::pointee)).collect(); } - // Add the `__S: ?Sized` extra parameter to the impl block. + // # Rewrite generic parameter bounds + // For each bound `U: ..` in `struct`, make a new bound with `__S` in place of `#[pointee]` + // Example: + // ``` + // struct< + // U: Trait, + // #[pointee] T: Trait, + // V: Trait> ... + // ``` + // ... generates this `impl` generic parameters + // ``` + // impl< + // U: Trait + Trait<__S>, + // T: Trait + Unsize<__S>, // (**) + // __S: Trait<__S> + ?Sized, // (*) + // V: Trait + Trait<__S>> ... + // ``` + // The new bound marked with (*) has to be done separately. + // See next section + for (idx, (params, orig_params)) in + impl_generics.params.iter_mut().zip(&generics.params).enumerate() + { + // Default type parameters are rejected for `impl` block. + // We should drop them now. + match &mut params.kind { + ast::GenericParamKind::Const { default, .. } => *default = None, + ast::GenericParamKind::Type { default } => *default = None, + ast::GenericParamKind::Lifetime => {} + } + // We CANNOT rewrite `#[pointee]` type parameter bounds. + // This has been set in stone. (**) + // So we skip over it. + // Otherwise, we push extra bounds involving `__S`. + if idx != pointee_param_idx { + for bound in &orig_params.bounds { + let mut bound = bound.clone(); + let mut substitution = TypeSubstitution { + from_name: pointee_ty_ident.name, + to_ty: &s_ty, + rewritten: false, + }; + substitution.visit_param_bound(&mut bound, BoundKind::Bound); + if substitution.rewritten { + // We found use of `#[pointee]` somewhere, + // so we make a new bound using `__S` in place of `#[pointee]` + params.bounds.push(bound); + } + } + } + } + + // # Insert `__S` type parameter + // + // We now insert `__S` with the missing bounds marked with (*) above. + // We should also write the bounds from `#[pointee]` to `__S` as required by `Unsize<__S>`. let sized = cx.path_global(span, path!(span, core::marker::Sized)); - let bound = GenericBound::Trait( - cx.poly_trait_ref(span, sized), - TraitBoundModifiers { - polarity: ast::BoundPolarity::Maybe(span), - constness: ast::BoundConstness::Never, - asyncness: ast::BoundAsyncness::Normal, - }, - ); - let extra_param = cx.typaram(span, Ident::new(sym::__S, span), vec![bound], None); - impl_generics.params.push(extra_param); + // For some reason, we are not allowed to write `?Sized` bound twice like `__S: ?Sized + ?Sized`. + if !contains_maybe_sized_bound(&self_bounds) + && !contains_maybe_sized_bound_on_pointee( + &generics.where_clause.predicates, + pointee_ty_ident.name, + ) + { + self_bounds.push(GenericBound::Trait( + cx.poly_trait_ref(span, sized), + TraitBoundModifiers { + polarity: ast::BoundPolarity::Maybe(span), + constness: ast::BoundConstness::Never, + asyncness: ast::BoundAsyncness::Normal, + }, + )); + } + { + let mut substitution = + TypeSubstitution { from_name: pointee_ty_ident.name, to_ty: &s_ty, rewritten: false }; + for bound in &mut self_bounds { + substitution.visit_param_bound(bound, BoundKind::Bound); + } + } + + // # Rewrite `where` clauses + // + // Move on to `where` clauses. + // Example: + // ``` + // struct MyPointer<#[pointee] T, ..> + // where + // U: Trait + Trait, + // Companion: Trait, + // T: Trait, + // { .. } + // ``` + // ... will have a impl prelude like so + // ``` + // impl<..> .. + // where + // U: Trait + Trait, + // U: Trait<__S>, + // Companion: Trait, + // Companion<__S>: Trait<__S>, + // T: Trait, + // __S: Trait<__S>, + // ``` + // + // We should also write a few new `where` bounds from `#[pointee] T` to `__S` + // as well as any bound that indirectly involves the `#[pointee] T` type. + for bound in &generics.where_clause.predicates { + if let ast::WherePredicate::BoundPredicate(bound) = bound { + let mut substitution = TypeSubstitution { + from_name: pointee_ty_ident.name, + to_ty: &s_ty, + rewritten: false, + }; + let mut predicate = ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { + span: bound.span, + bound_generic_params: bound.bound_generic_params.clone(), + bounded_ty: bound.bounded_ty.clone(), + bounds: bound.bounds.clone(), + }); + substitution.visit_where_predicate(&mut predicate); + if substitution.rewritten { + impl_generics.where_clause.predicates.push(predicate); + } + } + } + + let extra_param = cx.typaram(span, Ident::new(sym::__S, span), self_bounds, None); + impl_generics.params.insert(pointee_param_idx + 1, extra_param); // Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`. let gen_args = vec![GenericArg::Type(alt_self_type.clone())]; add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone()); add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args.clone()); } + +fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool { + for bound in predicates { + if let ast::WherePredicate::BoundPredicate(bound) = bound + && bound.bounded_ty.kind.is_simple_path().is_some_and(|name| name == pointee) + { + for bound in &bound.bounds { + if is_maybe_sized_bound(bound) { + return true; + } + } + } + } + false +} + +fn is_maybe_sized_bound(bound: &GenericBound) -> bool { + if let GenericBound::Trait( + trait_ref, + TraitBoundModifiers { polarity: ast::BoundPolarity::Maybe(_), .. }, + ) = bound + { + is_sized_marker(&trait_ref.trait_ref.path) + } else { + false + } +} + +fn contains_maybe_sized_bound(bounds: &[GenericBound]) -> bool { + bounds.iter().any(is_maybe_sized_bound) +} + +fn path_segment_is_exact_match(path_segments: &[ast::PathSegment], syms: &[Symbol]) -> bool { + path_segments.iter().zip(syms).all(|(segment, &symbol)| segment.ident.name == symbol) +} + +fn is_sized_marker(path: &ast::Path) -> bool { + const CORE_UNSIZE: [Symbol; 3] = [sym::core, sym::marker, sym::Sized]; + const STD_UNSIZE: [Symbol; 3] = [sym::std, sym::marker, sym::Sized]; + if path.segments.len() == 4 && path.is_global() { + path_segment_is_exact_match(&path.segments[1..], &CORE_UNSIZE) + || path_segment_is_exact_match(&path.segments[1..], &STD_UNSIZE) + } else if path.segments.len() == 3 { + path_segment_is_exact_match(&path.segments, &CORE_UNSIZE) + || path_segment_is_exact_match(&path.segments, &STD_UNSIZE) + } else { + *path == sym::Sized + } +} + +struct TypeSubstitution<'a> { + from_name: Symbol, + to_ty: &'a ast::Ty, + rewritten: bool, +} + +impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> { + fn visit_ty(&mut self, ty: &mut P) { + if let Some(name) = ty.kind.is_simple_path() + && name == self.from_name + { + **ty = self.to_ty.clone(); + self.rewritten = true; + } else { + ast::mut_visit::walk_ty(self, ty); + } + } + + fn visit_where_predicate(&mut self, where_predicate: &mut ast::WherePredicate) { + match where_predicate { + rustc_ast::WherePredicate::BoundPredicate(bound) => { + bound + .bound_generic_params + .flat_map_in_place(|param| self.flat_map_generic_param(param)); + self.visit_ty(&mut bound.bounded_ty); + for bound in &mut bound.bounds { + self.visit_param_bound(bound, BoundKind::Bound) + } + } + rustc_ast::WherePredicate::RegionPredicate(_) + | rustc_ast::WherePredicate::EqPredicate(_) => {} + } + } +} diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.rs b/tests/ui/deriving/deriving-smart-pointer-expanded.rs new file mode 100644 index 0000000000000..b78258c25290e --- /dev/null +++ b/tests/ui/deriving/deriving-smart-pointer-expanded.rs @@ -0,0 +1,22 @@ +//@ check-pass +//@ compile-flags: -Zunpretty=expanded +#![feature(derive_smart_pointer)] +use std::marker::SmartPointer; + +pub trait MyTrait {} + +#[derive(SmartPointer)] +#[repr(transparent)] +struct MyPointer<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +} + +#[derive(core::marker::SmartPointer)] +#[repr(transparent)] +pub struct MyPointer2<'a, Y, Z: MyTrait, #[pointee] T: ?Sized + MyTrait, X: MyTrait = ()> +where + Y: MyTrait, +{ + data: &'a mut T, + x: core::marker::PhantomData, +} diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout b/tests/ui/deriving/deriving-smart-pointer-expanded.stdout new file mode 100644 index 0000000000000..3c7e719818042 --- /dev/null +++ b/tests/ui/deriving/deriving-smart-pointer-expanded.stdout @@ -0,0 +1,44 @@ +#![feature(prelude_import)] +#![no_std] +//@ check-pass +//@ compile-flags: -Zunpretty=expanded +#![feature(derive_smart_pointer)] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +use std::marker::SmartPointer; + +pub trait MyTrait {} + +#[repr(transparent)] +struct MyPointer<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +} +#[automatically_derived] +impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized> + ::core::ops::DispatchFromDyn> for MyPointer<'a, T> { +} +#[automatically_derived] +impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized> + ::core::ops::CoerceUnsized> for MyPointer<'a, T> { +} + +#[repr(transparent)] +pub struct MyPointer2<'a, Y, Z: MyTrait, #[pointee] T: ?Sized + MyTrait, + X: MyTrait = ()> where Y: MyTrait { + data: &'a mut T, + x: core::marker::PhantomData, +} +#[automatically_derived] +impl<'a, Y, Z: MyTrait + MyTrait<__S>, T: ?Sized + MyTrait + + ::core::marker::Unsize<__S>, __S: ?Sized + MyTrait<__S>, X: MyTrait + + MyTrait<__S>> ::core::ops::DispatchFromDyn> + for MyPointer2<'a, Y, Z, T, X> where Y: MyTrait, Y: MyTrait<__S> { +} +#[automatically_derived] +impl<'a, Y, Z: MyTrait + MyTrait<__S>, T: ?Sized + MyTrait + + ::core::marker::Unsize<__S>, __S: ?Sized + MyTrait<__S>, X: MyTrait + + MyTrait<__S>> ::core::ops::CoerceUnsized> for + MyPointer2<'a, Y, Z, T, X> where Y: MyTrait, Y: MyTrait<__S> { +} diff --git a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs b/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs new file mode 100644 index 0000000000000..4cae1b32896fb --- /dev/null +++ b/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs @@ -0,0 +1,78 @@ +//@ check-pass + +#![feature(derive_smart_pointer)] + +#[derive(core::marker::SmartPointer)] +#[repr(transparent)] +pub struct Ptr<'a, #[pointee] T: OnDrop + ?Sized, X> { + data: &'a mut T, + x: core::marker::PhantomData, +} + +pub trait OnDrop { + fn on_drop(&mut self); +} + +#[derive(core::marker::SmartPointer)] +#[repr(transparent)] +pub struct Ptr2<'a, #[pointee] T: ?Sized, X> +where + T: OnDrop, +{ + data: &'a mut T, + x: core::marker::PhantomData, +} + +pub trait MyTrait {} + +#[derive(core::marker::SmartPointer)] +#[repr(transparent)] +pub struct Ptr3<'a, #[pointee] T: ?Sized, X> +where + T: MyTrait, +{ + data: &'a mut T, + x: core::marker::PhantomData, +} + +#[derive(core::marker::SmartPointer)] +#[repr(transparent)] +pub struct Ptr4<'a, #[pointee] T: MyTrait + ?Sized, X> { + data: &'a mut T, + x: core::marker::PhantomData, +} + +#[derive(core::marker::SmartPointer)] +#[repr(transparent)] +pub struct Ptr5<'a, #[pointee] T: ?Sized, X> +where + Ptr5Companion: MyTrait, + Ptr5Companion2: MyTrait, +{ + data: &'a mut T, + x: core::marker::PhantomData, +} + +pub struct Ptr5Companion(core::marker::PhantomData); +pub struct Ptr5Companion2; + +#[derive(core::marker::SmartPointer)] +#[repr(transparent)] +pub struct Ptr6<'a, #[pointee] T: ?Sized, X: MyTrait = (), const PARAM: usize = 0> { + data: &'a mut T, + x: core::marker::PhantomData, +} + +// a reduced example from https://lore.kernel.org/all/20240402-linked-list-v1-1-b1c59ba7ae3b@google.com/ +#[repr(transparent)] +#[derive(core::marker::SmartPointer)] +pub struct ListArc<#[pointee] T, const ID: u64 = 0> +where + T: ListArcSafe + ?Sized, +{ + arc: *const T, +} + +pub trait ListArcSafe {} + +fn main() {} From fe6478cc539cfe17b4f5fc10f46928c6b16e6ef0 Mon Sep 17 00:00:00 2001 From: beetrees Date: Tue, 30 Jul 2024 12:38:06 +0100 Subject: [PATCH 08/10] Match LLVM ABI in `extern "C"` functions for `f128` on Windows --- .../rustc_target/src/abi/call/x86_win64.rs | 10 +++-- library/std/build.rs | 4 +- tests/assembly/x86_64-windows-float-abi.rs | 39 +++++++++++++++++++ 3 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 tests/assembly/x86_64-windows-float-abi.rs diff --git a/compiler/rustc_target/src/abi/call/x86_win64.rs b/compiler/rustc_target/src/abi/call/x86_win64.rs index 90de1a42bc06b..4e19460bd28c2 100644 --- a/compiler/rustc_target/src/abi/call/x86_win64.rs +++ b/compiler/rustc_target/src/abi/call/x86_win64.rs @@ -1,5 +1,5 @@ use crate::abi::call::{ArgAbi, FnAbi, Reg}; -use crate::abi::Abi; +use crate::abi::{Abi, Float, Primitive}; // Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing @@ -18,8 +18,12 @@ pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>) { // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } - Abi::Scalar(_) => { - if a.layout.size.bytes() > 8 { + Abi::Scalar(scalar) => { + // Match what LLVM does for `f128` so that `compiler-builtins` builtins match up + // with what LLVM expects. + if a.layout.size.bytes() > 8 + && !matches!(scalar.primitive(), Primitive::Float(Float::F128)) + { a.make_indirect(); } else { a.extend_integer_width_to(32); diff --git a/library/std/build.rs b/library/std/build.rs index c542ba81eedc1..9b58dd53ba20a 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -94,7 +94,7 @@ fn main() { // Unsupported ("arm64ec", _) => false, // MinGW ABI bugs - ("x86", "windows") => false, + ("x86_64", "windows") => false, // x86 has ABI bugs that show up with optimizations. This should be partially fixed with // the compiler-builtins update. ("x86" | "x86_64", _) => false, @@ -122,6 +122,8 @@ fn main() { ("nvptx64", _) => false, // ABI unsupported ("sparc", _) => false, + // MinGW ABI bugs + ("x86_64", "windows") => false, // 64-bit Linux is about the only platform to have f128 symbols by default (_, "linux") if target_pointer_width == 64 => true, // Same as for f16, except MacOS is also missing f128 symbols. diff --git a/tests/assembly/x86_64-windows-float-abi.rs b/tests/assembly/x86_64-windows-float-abi.rs new file mode 100644 index 0000000000000..1381d492fa593 --- /dev/null +++ b/tests/assembly/x86_64-windows-float-abi.rs @@ -0,0 +1,39 @@ +//@ assembly-output: emit-asm +//@ compile-flags: -O +//@ only-windows +//@ only-x86_64 + +#![feature(f16, f128)] +#![crate_type = "lib"] + +// CHECK-LABEL: second_f16 +// CHECK: movaps %xmm1, %xmm0 +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn second_f16(_: f16, x: f16) -> f16 { + x +} + +// CHECK-LABEL: second_f32 +// CHECK: movaps %xmm1, %xmm0 +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn second_f32(_: f32, x: f32) -> f32 { + x +} + +// CHECK-LABEL: second_f64 +// CHECK: movaps %xmm1, %xmm0 +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn second_f64(_: f64, x: f64) -> f64 { + x +} + +// CHECK-LABEL: second_f128 +// CHECK: movaps %xmm1, %xmm0 +// CHECK-NEXT: retq +#[no_mangle] +pub extern "C" fn second_f128(_: f128, x: f128) -> f128 { + x +} From e65777301b108aed53b54b4625041d6e8631327f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 30 Jul 2024 16:42:53 -0400 Subject: [PATCH 09/10] Remove crate_level_only from ELIDED_LIFETIMES_IN_PATHS --- compiler/rustc_lint_defs/src/builtin.rs | 3 +-- tests/ui/lifetimes/elided-lint-in-mod.rs | 11 +++++++++++ tests/ui/lifetimes/elided-lint-in-mod.stderr | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/ui/lifetimes/elided-lint-in-mod.rs create mode 100644 tests/ui/lifetimes/elided-lint-in-mod.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 246b516076461..a6f6a63fb55d8 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1836,8 +1836,7 @@ declare_lint! { /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions pub ELIDED_LIFETIMES_IN_PATHS, Allow, - "hidden lifetime parameters in types are deprecated", - crate_level_only + "hidden lifetime parameters in types are deprecated" } declare_lint! { diff --git a/tests/ui/lifetimes/elided-lint-in-mod.rs b/tests/ui/lifetimes/elided-lint-in-mod.rs new file mode 100644 index 0000000000000..afe85cb607d40 --- /dev/null +++ b/tests/ui/lifetimes/elided-lint-in-mod.rs @@ -0,0 +1,11 @@ +struct Foo<'a>(&'a ()); + +fn test(_: Foo) {} + +#[deny(elided_lifetimes_in_paths)] +mod w { + fn test2(_: super::Foo) {} + //~^ ERROR hidden lifetime parameters in types are deprecated +} + +fn main() {} diff --git a/tests/ui/lifetimes/elided-lint-in-mod.stderr b/tests/ui/lifetimes/elided-lint-in-mod.stderr new file mode 100644 index 0000000000000..1fee18028c66f --- /dev/null +++ b/tests/ui/lifetimes/elided-lint-in-mod.stderr @@ -0,0 +1,20 @@ +error: hidden lifetime parameters in types are deprecated + --> $DIR/elided-lint-in-mod.rs:7:24 + | +LL | fn test2(_: super::Foo) {} + | -------^^^ + | | + | expected lifetime parameter + | +note: the lint level is defined here + --> $DIR/elided-lint-in-mod.rs:5:8 + | +LL | #[deny(elided_lifetimes_in_paths)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: indicate the anonymous lifetime + | +LL | fn test2(_: super::Foo<'_>) {} + | ++++ + +error: aborting due to 1 previous error + From 449deaf41e9ebc3778b54c5f90a9cf5c77d545be Mon Sep 17 00:00:00 2001 From: Xiangfei Ding Date: Mon, 13 May 2024 03:16:31 +0800 Subject: [PATCH 10/10] PinCoerceUnsized trait into core --- compiler/rustc_span/src/symbol.rs | 1 + library/alloc/src/boxed.rs | 5 +- library/alloc/src/lib.rs | 1 + library/alloc/src/rc.rs | 10 ++++ library/alloc/src/sync.rs | 8 ++- library/alloc/tests/arc.rs | 14 ++++++ library/alloc/tests/boxed.rs | 37 ++++++++++++++ library/alloc/tests/lib.rs | 1 + library/alloc/tests/rc.rs | 17 +++++++ library/core/src/cell.rs | 19 +++++++ library/core/src/pin.rs | 50 ++++++++++++++++++- library/core/src/ptr/non_null.rs | 4 ++ library/core/src/ptr/unique.rs | 4 ++ library/core/tests/pin.rs | 46 +++++++++++++++++ .../src/sys/pal/sgx/abi/usercalls/alloc.rs | 3 ++ 15 files changed, 216 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e8563f50158a5..9bacb60eca98b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -276,6 +276,7 @@ symbols! { Path, PathBuf, Pending, + PinCoerceUnsized, Pointer, Poll, ProcMacro, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index ef40d3b203f48..4b8706a8426e6 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -200,7 +200,7 @@ use core::ops::{ AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver, }; -use core::pin::Pin; +use core::pin::{Pin, PinCoerceUnsized}; use core::ptr::{self, addr_of_mut, NonNull, Unique}; use core::task::{Context, Poll}; use core::{borrow, fmt, slice}; @@ -2724,3 +2724,6 @@ impl core::error::Error for Box { core::error::Error::provide(&**self, request); } } + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Box {} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 28b08ef561143..3e44adf73f045 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -138,6 +138,7 @@ #![feature(maybe_uninit_uninit_array_transpose)] #![feature(panic_internals)] #![feature(pattern)] +#![feature(pin_coerce_unsized_trait)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index bc0874fc13f46..9352af99cdd45 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -256,6 +256,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Rece use core::panic::{RefUnwindSafe, UnwindSafe}; #[cfg(not(no_global_oom_handling))] use core::pin::Pin; +use core::pin::PinCoerceUnsized; use core::ptr::{self, drop_in_place, NonNull}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; @@ -2176,6 +2177,12 @@ impl Deref for Rc { } } +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Rc {} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Weak {} + #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for Rc {} @@ -3689,6 +3696,9 @@ impl Deref for UniqueRc { } } +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for UniqueRc {} + #[unstable(feature = "unique_rc_arc", issue = "112566")] impl DerefMut for UniqueRc { fn deref_mut(&mut self) -> &mut T { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 3ad0dae77dbde..2c0d19b0ada09 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -20,7 +20,7 @@ use core::marker::{PhantomData, Unsize}; use core::mem::{self, align_of_val_raw, ManuallyDrop}; use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; -use core::pin::Pin; +use core::pin::{Pin, PinCoerceUnsized}; use core::ptr::{self, NonNull}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; @@ -2142,6 +2142,12 @@ impl Deref for Arc { } } +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Arc {} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Weak {} + #[unstable(feature = "deref_pure_trait", issue = "87121")] unsafe impl DerefPure for Arc {} diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs index c37a80dca95c8..dc27c578b57ef 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloc/tests/arc.rs @@ -227,3 +227,17 @@ fn make_mut_unsized() { assert_eq!(*data, [11, 21, 31]); assert_eq!(*other_data, [110, 20, 30]); } + +#[allow(unused)] +mod pin_coerce_unsized { + use alloc::sync::Arc; + use core::pin::Pin; + + pub trait MyTrait {} + impl MyTrait for String {} + + // Pin coercion should work for Arc + pub fn pin_arc(arg: Pin>) -> Pin> { + arg + } +} diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index 4cacee0414d7d..faee64b2f6738 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -179,3 +179,40 @@ unsafe impl Allocator for ConstAllocator { self } } + +#[allow(unused)] +mod pin_coerce_unsized { + use alloc::boxed::Box; + use core::pin::Pin; + + trait MyTrait { + fn action(&self) -> &str; + } + impl MyTrait for String { + fn action(&self) -> &str { + &*self + } + } + struct MyStruct; + impl MyTrait for MyStruct { + fn action(&self) -> &str { + "MyStruct" + } + } + + // Pin coercion should work for Box + fn pin_box(arg: Pin>) -> Pin> { + arg + } + + #[test] + fn pin_coerce_unsized_box() { + let my_string = "my string"; + let a_string = Box::pin(String::from(my_string)); + let pin_box_str = pin_box(a_string); + assert_eq!(pin_box_str.as_ref().action(), my_string); + let a_struct = Box::pin(MyStruct); + let pin_box_struct = pin_box(a_struct); + assert_eq!(pin_box_struct.as_ref().action(), "MyStruct"); + } +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 89538f272f069..3d4add6fae452 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -40,6 +40,7 @@ #![feature(drain_keep_rest)] #![feature(local_waker)] #![feature(vec_pop_if)] +#![feature(unique_rc_arc)] #![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs index 499740e738ab0..29dbdcf225eb5 100644 --- a/library/alloc/tests/rc.rs +++ b/library/alloc/tests/rc.rs @@ -205,3 +205,20 @@ fn weak_may_dangle() { // `val` dropped here while still borrowed // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak` } + +#[allow(unused)] +mod pin_coerce_unsized { + use alloc::rc::{Rc, UniqueRc}; + use core::pin::Pin; + + pub trait MyTrait {} + impl MyTrait for String {} + + // Pin coercion should work for Rc + pub fn pin_rc(arg: Pin>) -> Pin> { + arg + } + pub fn pin_unique_rc(arg: Pin>) -> Pin> { + arg + } +} diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 0d66c2b52c84e..d860f3415d982 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -255,6 +255,7 @@ use crate::fmt::{self, Debug, Display}; use crate::marker::{PhantomData, Unsize}; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; +use crate::pin::PinCoerceUnsized; use crate::ptr::{self, NonNull}; mod lazy; @@ -2396,3 +2397,21 @@ fn assert_coerce_unsized( let _: Cell<&dyn Send> = c; let _: RefCell<&dyn Send> = d; } + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for UnsafeCell {} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for SyncUnsafeCell {} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Cell {} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for RefCell {} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl<'b, T: ?Sized> PinCoerceUnsized for Ref<'b, T> {} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl<'b, T: ?Sized> PinCoerceUnsized for RefMut<'b, T> {} diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index d752151d10cc8..0569b8b762433 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1715,10 +1715,56 @@ impl fmt::Pointer for Pin { // for other reasons, though, so we just need to take care not to allow such // impls to land in std. #[stable(feature = "pin", since = "1.33.0")] -impl CoerceUnsized> for Pin where Ptr: CoerceUnsized {} +impl CoerceUnsized> for Pin +where + Ptr: CoerceUnsized + PinCoerceUnsized, + U: PinCoerceUnsized, +{ +} + +#[stable(feature = "pin", since = "1.33.0")] +impl DispatchFromDyn> for Pin +where + Ptr: DispatchFromDyn + PinCoerceUnsized, + U: PinCoerceUnsized, +{ +} + +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +/// Trait that indicates that this is a pointer or a wrapper for one, where +/// unsizing can be performed on the pointee when it is pinned. +/// +/// # Safety +/// +/// If this type implements `Deref`, then the concrete type returned by `deref` +/// and `deref_mut` must not change without a modification. The following +/// operations are not considered modifications: +/// +/// * Moving the pointer. +/// * Performing unsizing coercions on the pointer. +/// * Performing dynamic dispatch with the pointer. +/// * Calling `deref` or `deref_mut` on the pointer. +/// +/// The concrete type of a trait object is the type that the vtable corresponds +/// to. The concrete type of a slice is an array of the same element type and +/// the length specified in the metadata. The concrete type of a sized type +/// is the type itself. +pub unsafe trait PinCoerceUnsized {} + +#[stable(feature = "pin", since = "1.33.0")] +unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a T {} + +#[stable(feature = "pin", since = "1.33.0")] +unsafe impl<'a, T: ?Sized> PinCoerceUnsized for &'a mut T {} + +#[stable(feature = "pin", since = "1.33.0")] +unsafe impl PinCoerceUnsized for Pin {} + +#[stable(feature = "pin", since = "1.33.0")] +unsafe impl PinCoerceUnsized for *const T {} #[stable(feature = "pin", since = "1.33.0")] -impl DispatchFromDyn> for Pin where Ptr: DispatchFromDyn {} +unsafe impl PinCoerceUnsized for *mut T {} /// Constructs a [Pin]<[&mut] T>, by pinning a `value: T` locally. /// diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 4a716a7503964..44db227b79efd 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -3,6 +3,7 @@ use crate::marker::Unsize; use crate::mem::{MaybeUninit, SizedTypeProperties}; use crate::num::NonZero; use crate::ops::{CoerceUnsized, DispatchFromDyn}; +use crate::pin::PinCoerceUnsized; use crate::ptr::Unique; use crate::slice::{self, SliceIndex}; use crate::ub_checks::assert_unsafe_precondition; @@ -1724,6 +1725,9 @@ impl CoerceUnsized> for NonNull where T: Uns #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl DispatchFromDyn> for NonNull where T: Unsize {} +#[stable(feature = "pin", since = "1.33.0")] +unsafe impl PinCoerceUnsized for NonNull {} + #[stable(feature = "nonnull", since = "1.25.0")] impl fmt::Debug for NonNull { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index b74d691e45427..4810ebe01f9bb 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -1,6 +1,7 @@ use crate::fmt; use crate::marker::{PhantomData, Unsize}; use crate::ops::{CoerceUnsized, DispatchFromDyn}; +use crate::pin::PinCoerceUnsized; use crate::ptr::NonNull; /// A wrapper around a raw non-null `*mut T` that indicates that the possessor @@ -166,6 +167,9 @@ impl CoerceUnsized> for Unique where T: Unsiz #[unstable(feature = "ptr_internals", issue = "none")] impl DispatchFromDyn> for Unique where T: Unsize {} +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for Unique {} + #[unstable(feature = "ptr_internals", issue = "none")] impl fmt::Debug for Unique { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs index 6f617c8d0c297..7a6af46a74323 100644 --- a/library/core/tests/pin.rs +++ b/library/core/tests/pin.rs @@ -29,3 +29,49 @@ fn pin_const() { pin_mut_const(); } + +#[allow(unused)] +mod pin_coerce_unsized { + use core::cell::{Cell, RefCell, UnsafeCell}; + use core::pin::Pin; + use core::ptr::NonNull; + + pub trait MyTrait {} + impl MyTrait for String {} + + // These Pins should continue to compile. + // Do note that these instances of Pin types cannot be used + // meaningfully because all methods require a Deref/DerefMut + // bounds on the pointer type and Cell, RefCell and UnsafeCell + // do not implement Deref/DerefMut. + + pub fn cell(arg: Pin>>) -> Pin>> { + arg + } + pub fn ref_cell(arg: Pin>>) -> Pin>> { + arg + } + pub fn unsafe_cell(arg: Pin>>) -> Pin>> { + arg + } + + // These sensible Pin coercions are possible. + pub fn pin_mut_ref(arg: Pin<&mut String>) -> Pin<&mut dyn MyTrait> { + arg + } + pub fn pin_ref(arg: Pin<&String>) -> Pin<&dyn MyTrait> { + arg + } + pub fn pin_ptr(arg: Pin<*const String>) -> Pin<*const dyn MyTrait> { + arg + } + pub fn pin_ptr_mut(arg: Pin<*mut String>) -> Pin<*mut dyn MyTrait> { + arg + } + pub fn pin_non_null(arg: Pin>) -> Pin> { + arg + } + pub fn nesting_pins(arg: Pin>) -> Pin> { + arg + } +} diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index 298095257396a..b8fc1b48fc84c 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -751,6 +751,9 @@ where #[unstable(feature = "sgx_platform", issue = "56975")] impl, U> CoerceUnsized> for UserRef {} +#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")] +unsafe impl PinCoerceUnsized for UserRef {} + #[unstable(feature = "sgx_platform", issue = "56975")] impl Index for UserRef<[T]> where