From 468f9358f3f73db9a0ea6dc1a94320177718061a Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 21 Jul 2024 09:43:06 +0100 Subject: [PATCH 01/15] std::thread: available_parallelism implementation for vxWorks proposal. --- library/std/src/sys/pal/unix/thread.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 619f4e4121e73..0f496a39173a0 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -462,8 +462,18 @@ pub fn available_parallelism() -> io::Result> { Ok(NonZero::new_unchecked(sinfo.cpu_count as usize)) } + } else if #[cfg(target_os = "vxworks")] { + // Note: there is also `vxCpuConfiguredGet`, closer to _SC_NPROCESSORS_CONF + // expectations than the actual cores availability. + extern "C" { + fn vxCpuEnabledGet() -> libc::cpuset_t; + } + + // always fetches a valid bitmask + let set = unsafe { vxCpuEnabledGet() }; + Ok(NonZero::new_unchecked(set.count_ones() as usize)) } else { - // FIXME: implement on vxWorks, Redox, l4re + // FIXME: implement on Redox, l4re Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform")) } } From c2523c954360b5e96fcbbac554573c87d3cf6dcc Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 3 Aug 2024 14:56:16 +0000 Subject: [PATCH 02/15] Use object in run-make/symbols-visibility --- tests/run-make/symbol-visibility/rmake.rs | 76 ++++++++++------------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/tests/run-make/symbol-visibility/rmake.rs b/tests/run-make/symbol-visibility/rmake.rs index b37ff44f4ead6..488b0886ed7de 100644 --- a/tests/run-make/symbol-visibility/rmake.rs +++ b/tests/run-make/symbol-visibility/rmake.rs @@ -4,12 +4,8 @@ // are exported, and that generics are only shown if explicitely requested. // See https://github.com/rust-lang/rust/issues/37530 -//@ ignore-windows-msvc - -//FIXME(Oneirical): This currently uses llvm-nm for symbol detection. However, -// the custom Rust-based solution of #128314 may prove to be an interesting alternative. - -use run_make_support::{bin_name, dynamic_lib_name, is_darwin, is_windows, llvm_nm, regex, rustc}; +use run_make_support::object::read::Object; +use run_make_support::{bin_name, dynamic_lib_name, is_msvc, object, regex, rfs, rustc}; fn main() { let cdylib_name = dynamic_lib_name("a_cdylib"); @@ -64,16 +60,15 @@ fn main() { ); // FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032 - // if is_windows() { - // // Check that an executable does not export any dynamic symbols - // symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib") - //, false); - // symbols_check( - // &exe_name, - // SymbolCheckType::StrSymbol("public_rust_function_from_exe"), - // false, - // ); - // } + if is_msvc() { + // Check that an executable does not export any dynamic symbols + symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false); + symbols_check( + &exe_name, + SymbolCheckType::StrSymbol("public_rust_function_from_exe"), + false, + ); + } // Check the combined case, where we generate a cdylib and an rlib in the same // compilation session: @@ -131,44 +126,37 @@ fn main() { ); // FIXME(nbdd0121): This is broken in MinGW, see https://github.com/rust-lang/rust/pull/95604#issuecomment-1101564032 - // if is_windows() { - // // Check that an executable does not export any dynamic symbols - // symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib") - //, false); - // symbols_check( - // &exe_name, - // SymbolCheckType::StrSymbol("public_rust_function_from_exe"), - // false, - // ); - // } + if is_msvc() { + // Check that an executable does not export any dynamic symbols + symbols_check(&exe_name, SymbolCheckType::StrSymbol("public_c_function_from_rlib"), false); + symbols_check( + &exe_name, + SymbolCheckType::StrSymbol("public_rust_function_from_exe"), + false, + ); + } } #[track_caller] fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bool) { - let mut nm = llvm_nm(); - if is_windows() { - nm.arg("--extern-only"); - } else if is_darwin() { - nm.arg("--extern-only").arg("--defined-only"); - } else { - nm.arg("--dynamic"); + let binary_data = rfs::read(path); + let file = object::File::parse(&*binary_data).unwrap(); + let mut found: u64 = 0; + for export in file.exports().unwrap() { + let name = std::str::from_utf8(export.name()).unwrap(); + if has_symbol(name, symbol_check_type) { + found += 1; + } } - let out = nm.input(path).run().stdout_utf8(); - assert_eq!( - out.lines() - .filter(|&line| !line.contains("__imp_") && has_symbol(line, symbol_check_type)) - .count() - == 1, - exists_once - ); + assert_eq!(found, exists_once as u64); } -fn has_symbol(line: &str, symbol_check_type: SymbolCheckType) -> bool { +fn has_symbol(name: &str, symbol_check_type: SymbolCheckType) -> bool { if let SymbolCheckType::StrSymbol(expected) = symbol_check_type { - line.contains(expected) + !name.contains("__imp_") && name.contains(expected) } else { let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap(); - regex.is_match(line) + regex.is_match(name) } } From 36a805939e6e9d4bdff03c28bc1ad9dbd36bdb95 Mon Sep 17 00:00:00 2001 From: Christopher Swenson Date: Sat, 3 Aug 2024 08:49:38 -0700 Subject: [PATCH 03/15] Remove unnecessary constants from flt2dec dragon The "dragon" `flt2dec` algorithm uses multi-precision multiplication by (sometimes large) powers of 10. It has precomputed some values to help with these calculations. BUT: * There is no need to store powers of 10 and 2 * powers of 10: it is trivial to compute the second from the first. * We can save a chunk of memory by storing powers of 5 instead of powers of 10 for the large powers (and just shifting by 2 as appropriate). * This also slightly speeds up the routines (by ~1-3%) since the intermediate products are smaller and the shift is cheap. In this PR, we remove the unnecessary constants and do the necessary adjustments. Relevant benchmarks before (on my Threadripper 3970X, x86_64-unknown-linux-gnu): ``` num::flt2dec::bench_big_shortest 137.92/iter +/- 2.24 num::flt2dec::strategy::dragon::bench_big_exact_12 2135.28/iter +/- 38.90 num::flt2dec::strategy::dragon::bench_big_exact_3 904.95/iter +/- 10.58 num::flt2dec::strategy::dragon::bench_big_exact_inf 47230.33/iter +/- 320.84 num::flt2dec::strategy::dragon::bench_big_shortest 3915.05/iter +/- 51.37 ``` and after: ``` num::flt2dec::bench_big_shortest 137.40/iter +/- 2.03 num::flt2dec::strategy::dragon::bench_big_exact_12 2101.10/iter +/- 25.63 num::flt2dec::strategy::dragon::bench_big_exact_3 873.86/iter +/- 4.20 num::flt2dec::strategy::dragon::bench_big_exact_inf 47468.19/iter +/- 374.45 num::flt2dec::strategy::dragon::bench_big_shortest 3877.01/iter +/- 45.74 ``` --- .../core/src/num/flt2dec/strategy/dragon.rs | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/library/core/src/num/flt2dec/strategy/dragon.rs b/library/core/src/num/flt2dec/strategy/dragon.rs index 751edd3c79383..f8db6370653ab 100644 --- a/library/core/src/num/flt2dec/strategy/dragon.rs +++ b/library/core/src/num/flt2dec/strategy/dragon.rs @@ -12,48 +12,51 @@ use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS}; static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]; -static TWOPOW10: [Digit; 10] = - [2, 20, 200, 2000, 20000, 200000, 2000000, 20000000, 200000000, 2000000000]; - -// precalculated arrays of `Digit`s for 10^(2^n) -static POW10TO16: [Digit; 2] = [0x6fc10000, 0x2386f2]; -static POW10TO32: [Digit; 4] = [0, 0x85acef81, 0x2d6d415b, 0x4ee]; -static POW10TO64: [Digit; 7] = [0, 0, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03]; -static POW10TO128: [Digit; 14] = [ - 0, 0, 0, 0, 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da, - 0xa6337f19, 0xe91f2603, 0x24e, +// precalculated arrays of `Digit`s for 5^(2^n). +static POW5TO16: [Digit; 2] = [0x86f26fc1, 0x23]; +static POW5TO32: [Digit; 3] = [0x85acef81, 0x2d6d415b, 0x4ee]; +static POW5TO64: [Digit; 5] = [0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03]; +static POW5TO128: [Digit; 10] = [ + 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, 0xbccdb0da, 0xa6337f19, + 0xe91f2603, 0x24e, ]; -static POW10TO256: [Digit; 27] = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, - 0xd595d80f, 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17, - 0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x553f7, +static POW5TO256: [Digit; 19] = [ + 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0xd595d80f, 0x26b2716e, + 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7, + 0xf46eeddc, 0x5fdcefce, 0x553f7, ]; #[doc(hidden)] pub fn mul_pow10(x: &mut Big, n: usize) -> &mut Big { debug_assert!(n < 512); + // Save ourself the left shift for the smallest cases. + if n < 8 { + return x.mul_small(POW10[n & 7]); + } + // Multiply by the powers of 5 and shift the 2s in at the end. + // This keeps the intermediate products smaller and faster. if n & 7 != 0 { - x.mul_small(POW10[n & 7]); + x.mul_small(POW10[n & 7] >> (n & 7)); } if n & 8 != 0 { - x.mul_small(POW10[8]); + x.mul_small(POW10[8] >> 8); } if n & 16 != 0 { - x.mul_digits(&POW10TO16); + x.mul_digits(&POW5TO16); } if n & 32 != 0 { - x.mul_digits(&POW10TO32); + x.mul_digits(&POW5TO32); } if n & 64 != 0 { - x.mul_digits(&POW10TO64); + x.mul_digits(&POW5TO64); } if n & 128 != 0 { - x.mul_digits(&POW10TO128); + x.mul_digits(&POW5TO128); } if n & 256 != 0 { - x.mul_digits(&POW10TO256); + x.mul_digits(&POW5TO256); } - x + x.mul_pow2(n) } fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big { @@ -62,7 +65,7 @@ fn div_2pow10(x: &mut Big, mut n: usize) -> &mut Big { x.div_rem_small(POW10[largest]); n -= largest; } - x.div_rem_small(TWOPOW10[n]); + x.div_rem_small(POW10[n] << 1); x } From f28d1570912c37fad69439bac7fce40d46e8ef3a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 3 Aug 2024 16:04:37 +0000 Subject: [PATCH 04/15] Update rmake.rs --- tests/run-make/symbol-visibility/rmake.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-make/symbol-visibility/rmake.rs b/tests/run-make/symbol-visibility/rmake.rs index 488b0886ed7de..997eaf793d261 100644 --- a/tests/run-make/symbol-visibility/rmake.rs +++ b/tests/run-make/symbol-visibility/rmake.rs @@ -144,7 +144,7 @@ fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bo let mut found: u64 = 0; for export in file.exports().unwrap() { let name = std::str::from_utf8(export.name()).unwrap(); - if has_symbol(name, symbol_check_type) { + if !name.contains("__imp_") && has_symbol(name, symbol_check_type) { found += 1; } } @@ -153,7 +153,7 @@ fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bo fn has_symbol(name: &str, symbol_check_type: SymbolCheckType) -> bool { if let SymbolCheckType::StrSymbol(expected) = symbol_check_type { - !name.contains("__imp_") && name.contains(expected) + name.contains(expected) } else { let regex = regex::Regex::new(r#"_ZN.*h.*E\|_R[a-zA-Z0-9_]+"#).unwrap(); regex.is_match(name) From b94a9c1b123026463fd6e1c71c74d9308cdf4f26 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 3 Aug 2024 22:08:39 +0000 Subject: [PATCH 05/15] Remove skipping symbols with the `__imp_` prefix --- tests/run-make/symbol-visibility/rmake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-make/symbol-visibility/rmake.rs b/tests/run-make/symbol-visibility/rmake.rs index 997eaf793d261..f84e63ef74e8d 100644 --- a/tests/run-make/symbol-visibility/rmake.rs +++ b/tests/run-make/symbol-visibility/rmake.rs @@ -144,7 +144,7 @@ fn symbols_check(path: &str, symbol_check_type: SymbolCheckType, exists_once: bo let mut found: u64 = 0; for export in file.exports().unwrap() { let name = std::str::from_utf8(export.name()).unwrap(); - if !name.contains("__imp_") && has_symbol(name, symbol_check_type) { + if has_symbol(name, symbol_check_type) { found += 1; } } From f9d7e4c0a96f17a25e8246a22195ad86d796fb5d Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 3 Aug 2024 16:59:29 +0000 Subject: [PATCH 06/15] Remove cygpath from run-make-support --- .../src/external_deps/c_build.rs | 4 +-- .../run-make-support/src/external_deps/cc.rs | 10 +++--- .../src/external_deps/cygpath.rs | 35 ------------------- .../run-make-support/src/external_deps/mod.rs | 3 -- 4 files changed, 5 insertions(+), 47 deletions(-) delete mode 100644 src/tools/run-make-support/src/external_deps/cygpath.rs diff --git a/src/tools/run-make-support/src/external_deps/c_build.rs b/src/tools/run-make-support/src/external_deps/c_build.rs index 15e02d04393ce..fb22780eaa0cf 100644 --- a/src/tools/run-make-support/src/external_deps/c_build.rs +++ b/src/tools/run-make-support/src/external_deps/c_build.rs @@ -1,6 +1,5 @@ use std::path::PathBuf; -use super::cygpath::get_windows_path; use crate::artifact_names::{dynamic_lib_name, static_lib_name}; use crate::external_deps::cc::{cc, cxx}; use crate::external_deps::llvm::llvm_ar; @@ -44,8 +43,7 @@ pub fn build_native_dynamic_lib(lib_name: &str) -> PathBuf { }; let obj_file = if is_msvc() { format!("{lib_name}.obj") } else { format!("{lib_name}.o") }; if is_msvc() { - let mut out_arg = "-out:".to_owned(); - out_arg.push_str(&get_windows_path(&lib_path)); + let out_arg = format!("-out:{lib_path}"); cc().input(&obj_file).args(&["-link", "-dll", &out_arg]).run(); } else if is_darwin() { cc().out_exe(&lib_path).input(&obj_file).args(&["-dynamiclib", "-Wl,-dylib"]).run(); diff --git a/src/tools/run-make-support/src/external_deps/cc.rs b/src/tools/run-make-support/src/external_deps/cc.rs index 39ac3efef3948..36cef15781f13 100644 --- a/src/tools/run-make-support/src/external_deps/cc.rs +++ b/src/tools/run-make-support/src/external_deps/cc.rs @@ -1,7 +1,5 @@ use std::path::Path; -// FIXME(jieyouxu): can we get rid of the `cygpath` external dependency? -use super::cygpath::get_windows_path; use crate::command::Command; use crate::{env_var, is_msvc, is_windows, uname}; @@ -97,12 +95,12 @@ impl Cc { if is_msvc() { path.set_extension("exe"); - let fe_path = get_windows_path(&path); + let fe_path = path.clone(); path.set_extension(""); path.set_extension("obj"); - let fo_path = get_windows_path(path); - self.cmd.arg(format!("-Fe:{fe_path}")); - self.cmd.arg(format!("-Fo:{fo_path}")); + let fo_path = path; + self.cmd.arg(format!("-Fe:{}", fe_path.to_str().unwrap())); + self.cmd.arg(format!("-Fo:{}", fo_path.to_str().unwrap())); } else { self.cmd.arg("-o"); self.cmd.arg(name); diff --git a/src/tools/run-make-support/src/external_deps/cygpath.rs b/src/tools/run-make-support/src/external_deps/cygpath.rs deleted file mode 100644 index 07d8e840a63a8..0000000000000 --- a/src/tools/run-make-support/src/external_deps/cygpath.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::panic; -use std::path::Path; - -use crate::command::Command; -use crate::util::handle_failed_output; - -/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is -/// available on the platform! -/// -/// # FIXME -/// -/// FIXME(jieyouxu): we should consider not depending on `cygpath`. -/// -/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style -/// > pathnames and vice versa. -/// > -/// > [irrelevant entries omitted...] -/// > -/// > `-w, --windows print Windows form of NAMEs (C:\WINNT)` -/// > -/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*. -#[track_caller] -#[must_use] -pub fn get_windows_path>(path: P) -> String { - let caller = panic::Location::caller(); - let mut cygpath = Command::new("cygpath"); - cygpath.arg("-w"); - cygpath.arg(path.as_ref()); - let output = cygpath.run(); - if !output.status().success() { - handle_failed_output(&cygpath, output, caller.line()); - } - // cygpath -w can attach a newline - output.stdout_utf8().trim().to_string() -} diff --git a/src/tools/run-make-support/src/external_deps/mod.rs b/src/tools/run-make-support/src/external_deps/mod.rs index a2dc426f3f229..f7c84724d0e07 100644 --- a/src/tools/run-make-support/src/external_deps/mod.rs +++ b/src/tools/run-make-support/src/external_deps/mod.rs @@ -9,6 +9,3 @@ pub mod llvm; pub mod python; pub mod rustc; pub mod rustdoc; - -// Library-internal external dependency. -mod cygpath; From 249afea2ff4a1e3cfbe5f40c42c6f84938ee3143 Mon Sep 17 00:00:00 2001 From: bohan Date: Sun, 4 Aug 2024 15:38:11 +0800 Subject: [PATCH 07/15] docs(resolve): more explain about `target` --- compiler/rustc_resolve/src/imports.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 0fa5cde9424b5..c7af21027b8d3 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -48,6 +48,7 @@ pub(crate) enum ImportKind<'a> { /// `source` in `use prefix::source as target`. source: Ident, /// `target` in `use prefix::source as target`. + /// It will directly use `source` when the format is `use prefix::source`. target: Ident, /// Bindings to which `source` refers to. source_bindings: PerNS, Determinacy>>>, From 69de294c311cd38c85f3f143fb4cf997518e8bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 4 Aug 2024 21:25:49 +0200 Subject: [PATCH 08/15] tests: more crashes --- tests/crashes/128094.rs | 14 ++++++++++++++ tests/crashes/128176.rs | 13 +++++++++++++ tests/crashes/128190.rs | 7 +++++++ tests/crashes/128327.rs | 5 +++++ tests/crashes/128346.rs | 13 +++++++++++++ tests/crashes/128621-2.rs | 16 ++++++++++++++++ tests/crashes/128621.rs | 19 +++++++++++++++++++ 7 files changed, 87 insertions(+) create mode 100644 tests/crashes/128094.rs create mode 100644 tests/crashes/128176.rs create mode 100644 tests/crashes/128190.rs create mode 100644 tests/crashes/128327.rs create mode 100644 tests/crashes/128346.rs create mode 100644 tests/crashes/128621-2.rs create mode 100644 tests/crashes/128621.rs diff --git a/tests/crashes/128094.rs b/tests/crashes/128094.rs new file mode 100644 index 0000000000000..105a1c84a6565 --- /dev/null +++ b/tests/crashes/128094.rs @@ -0,0 +1,14 @@ +//@ known-bug: rust-lang/rust#128094 +//@ compile-flags: -Zmir-opt-level=5 --edition=2018 + +pub enum Request { + TestSome(T), +} + +pub async fn handle_event(event: Request) { + async move { + static instance: Request = Request { bar: 17 }; + &instance + } + .await; +} diff --git a/tests/crashes/128176.rs b/tests/crashes/128176.rs new file mode 100644 index 0000000000000..70fada4f0fec2 --- /dev/null +++ b/tests/crashes/128176.rs @@ -0,0 +1,13 @@ +//@ known-bug: rust-lang/rust#128176 + +#![feature(generic_const_exprs)] +#![feature(object_safe_for_dispatch)] +trait X { + type Y; +} + +const _: () = { + fn f2<'a>(arg: Box = &'a ()>>) {} +}; + +fn main() {} diff --git a/tests/crashes/128190.rs b/tests/crashes/128190.rs new file mode 100644 index 0000000000000..0fa7027ae6091 --- /dev/null +++ b/tests/crashes/128190.rs @@ -0,0 +1,7 @@ +//@ known-bug: rust-lang/rust#128190 + +fn a(&self) { + 15 +} + +reuse a as b { struct S; } diff --git a/tests/crashes/128327.rs b/tests/crashes/128327.rs new file mode 100644 index 0000000000000..a63f758c317cf --- /dev/null +++ b/tests/crashes/128327.rs @@ -0,0 +1,5 @@ +//@ known-bug: rust-lang/rust#128327 + +use std::ops::Deref; +struct Apple((Apple, <&'static [f64] as Deref>::Target(Banana ? Citron))); +fn main(){} diff --git a/tests/crashes/128346.rs b/tests/crashes/128346.rs new file mode 100644 index 0000000000000..93d9c40a544e9 --- /dev/null +++ b/tests/crashes/128346.rs @@ -0,0 +1,13 @@ +//@ known-bug: rust-lang/rust#128346 + +macro_rules! one_rep { + ( $($a:ident)* ) => { + A( + const ${concat($a, Z)}: i32 = 3; + )* + }; +} + +fn main() { + one_rep!(A B C); +} diff --git a/tests/crashes/128621-2.rs b/tests/crashes/128621-2.rs new file mode 100644 index 0000000000000..b1cdaf94984a8 --- /dev/null +++ b/tests/crashes/128621-2.rs @@ -0,0 +1,16 @@ +//@ known-bug: rust-lang/rust#128621 + +#![feature(ptr_metadata)] +use std::{ops::FnMut, ptr::Pointee}; + +pub type EmplacerFn<'a, T> = dyn for<'b> FnMut(::Metadata) + 'a; + +pub struct Emplacer<'a, T>(EmplacerFn<'a, T>); + +impl<'a, T> Emplacer<'a, T> { + pub unsafe fn from_fn<'b>(emplacer_fn: &'b mut EmplacerFn<'a, T>) -> &'b mut Self { + unsafe { &mut *((emplacer_fn as *mut EmplacerFn<'a, T>) as *mut Self) } + } +} + +pub fn main() {} diff --git a/tests/crashes/128621.rs b/tests/crashes/128621.rs new file mode 100644 index 0000000000000..0a02352236dbb --- /dev/null +++ b/tests/crashes/128621.rs @@ -0,0 +1,19 @@ +//@ known-bug: rust-lang/rust#128621 + +trait Trait { + type Associated; +} + +impl Trait for i32 { + type Associated = i64; +} + +trait Generic {} + +type TraitObject = dyn Generic<::Associated>; + +struct Wrap(TraitObject); + +fn cast(x: *mut TraitObject) { + x as *mut Wrap; +} From 249d686c7005ebb4d05234e9db6d29c2923296e2 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 31 Jul 2024 15:25:13 -0700 Subject: [PATCH 09/15] rustdoc: Rename `SelfTy` to `ReceiverTy` `SelfTy` makes it sound like it is literally the `Self` type, whereas in fact it may be `&Self` or other types. Plus, I want to use the name `SelfTy` for a new variant of `clean::Type`. Having both causes resolution conflicts or at least confusion. --- src/librustdoc/clean/types.rs | 10 +++++----- src/librustdoc/html/format.rs | 2 +- src/librustdoc/html/render/mod.rs | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 7d5a16bc7e3d5..32e795e565ed2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -34,7 +34,7 @@ use thin_vec::ThinVec; use {rustc_ast as ast, rustc_hir as hir}; pub(crate) use self::ItemKind::*; -pub(crate) use self::SelfTy::*; +pub(crate) use self::ReceiverTy::*; pub(crate) use self::Type::{ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath, RawPointer, Slice, Tuple, @@ -1384,8 +1384,8 @@ pub(crate) struct FnDecl { } impl FnDecl { - pub(crate) fn self_type(&self) -> Option { - self.inputs.values.get(0).and_then(|v| v.to_self()) + pub(crate) fn receiver_type(&self) -> Option { + self.inputs.values.get(0).and_then(|v| v.to_receiver()) } } @@ -1404,14 +1404,14 @@ pub(crate) struct Argument { } #[derive(Clone, PartialEq, Debug)] -pub(crate) enum SelfTy { +pub(crate) enum ReceiverTy { SelfValue, SelfBorrowed(Option, Mutability), SelfExplicit(Type), } impl Argument { - pub(crate) fn to_self(&self) -> Option { + pub(crate) fn to_receiver(&self) -> Option { if self.name != kw::SelfLower { return None; } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index bb5ac303ffd63..6476c8bd7c0d3 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1452,7 +1452,7 @@ impl clean::FnDecl { let last_input_index = self.inputs.values.len().checked_sub(1); for (i, input) in self.inputs.values.iter().enumerate() { - if let Some(selfty) = input.to_self() { + if let Some(selfty) = input.to_receiver() { match selfty { clean::SelfValue => { write!(f, "self")?; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 9617f0d9a1f25..b7bcda2a604cf 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -58,7 +58,7 @@ use serde::{Serialize, Serializer}; pub(crate) use self::context::*; pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc}; -use crate::clean::{self, ItemId, RenderedLink, SelfTy}; +use crate::clean::{self, ItemId, ReceiverTy, RenderedLink}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; @@ -1372,21 +1372,21 @@ fn render_deref_methods( fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool { let self_type_opt = match *item.kind { - clean::MethodItem(ref method, _) => method.decl.self_type(), - clean::TyMethodItem(ref method) => method.decl.self_type(), + clean::MethodItem(ref method, _) => method.decl.receiver_type(), + clean::TyMethodItem(ref method) => method.decl.receiver_type(), _ => None, }; if let Some(self_ty) = self_type_opt { let (by_mut_ref, by_box, by_value) = match self_ty { - SelfTy::SelfBorrowed(_, mutability) - | SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => { + ReceiverTy::SelfBorrowed(_, mutability) + | ReceiverTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => { (mutability == Mutability::Mut, false, false) } - SelfTy::SelfExplicit(clean::Type::Path { path }) => { + ReceiverTy::SelfExplicit(clean::Type::Path { path }) => { (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false) } - SelfTy::SelfValue => (false, false, true), + ReceiverTy::SelfValue => (false, false, true), _ => (false, false, false), }; From 664b3ffbe932d93677ac7dff52252e02aee60ef9 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 31 Jul 2024 16:45:05 -0700 Subject: [PATCH 10/15] rustdoc: Create `SelfTy` to replace `Generic(kw::SelfUpper)` Rustdoc often has to special-case `Self` because it is, well, a special type of generic parameter (although it also behaves as an alias in concrete impls). Instead of spreading this special-casing throughout the code base, create a new variant of the `clean::Type` enum that is for `Self` types. This is a refactoring that has almost no impact on rustdoc's behavior, except that `&Self`, `(Self,)`, `&[Self]`, and other similar occurrences of `Self` no longer link to the wrapping type (reference primitive, tuple primitive, etc.) as regular generics do. I felt this made more sense since users would expect `Self` to link to the containing trait or aliased type (though those are usually expanded), not the primitive that is wrapping it. For an example of the change, see the docs for `std::alloc::Allocator::by_ref`. --- src/librustdoc/clean/inline.rs | 16 +++++----------- src/librustdoc/clean/mod.rs | 11 ++++++----- src/librustdoc/clean/simplify.rs | 1 - src/librustdoc/clean/types.rs | 10 +++++++--- src/librustdoc/clean/utils.rs | 2 +- src/librustdoc/html/format.rs | 1 + src/librustdoc/html/render/search_index.rs | 15 ++++++++++++--- src/librustdoc/json/conversions.rs | 4 +++- 8 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d92bc8456649f..f8953f0ebcfb5 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::symbol::{sym, Symbol}; use thin_vec::{thin_vec, ThinVec}; use {rustc_ast as ast, rustc_hir as hir}; @@ -792,11 +792,7 @@ fn build_macro( fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics { for pred in &mut g.where_predicates { match *pred { - clean::WherePredicate::BoundPredicate { - ty: clean::Generic(ref s), - ref mut bounds, - .. - } if *s == kw::SelfUpper => { + clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } => { bounds.retain(|bound| match bound { clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => { trait_.def_id() != trait_did @@ -812,13 +808,13 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: clean::WherePredicate::BoundPredicate { ty: clean::QPath(box clean::QPathData { - self_type: clean::Generic(ref s), + self_type: clean::Generic(_), trait_: Some(trait_), .. }), bounds, .. - } => !(bounds.is_empty() || *s == kw::SelfUpper && trait_.def_id() == trait_did), + } => !bounds.is_empty() && trait_.def_id() != trait_did, _ => true, }); g @@ -832,9 +828,7 @@ fn separate_supertrait_bounds( ) -> (clean::Generics, Vec) { let mut ty_bounds = Vec::new(); g.where_predicates.retain(|pred| match *pred { - clean::WherePredicate::BoundPredicate { ty: clean::Generic(ref s), ref bounds, .. } - if *s == kw::SelfUpper => - { + clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => { ty_bounds.extend(bounds.iter().cloned()); false } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 324b633e8ea7e..cffadc7c10a91 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1351,11 +1351,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( let self_arg_ty = tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder(); if self_arg_ty == self_ty { - item.decl.inputs.values[0].type_ = Generic(kw::SelfUpper); + item.decl.inputs.values[0].type_ = SelfTy; } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { if ty == self_ty { match item.decl.inputs.values[0].type_ { - BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper), + BorrowedRef { ref mut type_, .. } => **type_ = SelfTy, _ => unreachable!(), } } @@ -1439,9 +1439,8 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( if trait_.def_id() != assoc_item.container_id(tcx) { return true; } - match *self_type { - Generic(ref s) if *s == kw::SelfUpper => {} - _ => return true, + if *self_type != SelfTy { + return true; } match &assoc.args { GenericArgs::AngleBracketed { args, constraints } => { @@ -2228,6 +2227,8 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Param(ref p) => { if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) { ImplTrait(bounds) + } else if p.name == kw::SelfUpper { + SelfTy } else { Generic(p.name) } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 739f6eb8cc89d..1d81ae3eb8ba7 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -145,7 +145,6 @@ pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generi // should be handled when cleaning associated types. generics.where_predicates.retain(|pred| { if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred - && *param != rustc_span::symbol::kw::SelfUpper && bounds.iter().any(|b| b.is_sized_bound(cx)) { sized_params.insert(*param); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 32e795e565ed2..82f1312364a5b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -37,7 +37,7 @@ pub(crate) use self::ItemKind::*; pub(crate) use self::ReceiverTy::*; pub(crate) use self::Type::{ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath, - RawPointer, Slice, Tuple, + RawPointer, SelfTy, Slice, Tuple, }; use crate::clean::cfg::Cfg; use crate::clean::clean_middle_path; @@ -1477,6 +1477,8 @@ pub(crate) enum Type { DynTrait(Vec, Option), /// A type parameter. Generic(Symbol), + /// The `Self` type. + SelfTy, /// A primitive (aka, builtin) type. Primitive(PrimitiveType), /// A function pointer: `extern "ABI" fn(...) -> ...` @@ -1571,6 +1573,8 @@ impl Type { // If both sides are generic, this returns true. (_, Type::Generic(_)) => true, (Type::Generic(_), _) => false, + // `Self` only matches itself. + (Type::SelfTy, Type::SelfTy) => true, // Paths account for both the path itself and its generics. (Type::Path { path: a }, Type::Path { path: b }) => { a.def_id() == b.def_id() @@ -1642,7 +1646,7 @@ impl Type { pub(crate) fn is_self_type(&self) -> bool { match *self { - Generic(name) => name == kw::SelfUpper, + SelfTy => true, _ => false, } } @@ -1700,7 +1704,7 @@ impl Type { Type::Pat(..) => PrimitiveType::Pat, RawPointer(..) => PrimitiveType::RawPointer, QPath(box QPathData { ref self_type, .. }) => return self_type.def_id(cache), - Generic(_) | Infer | ImplTrait(_) => return None, + Generic(_) | SelfTy | Infer | ImplTrait(_) => return None, }; Primitive(t).def_id(cache) } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 2dd3041ab4c61..68266f3506a01 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -468,7 +468,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { match path.res { Res::PrimTy(p) => Primitive(PrimitiveType::from(p)), Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } if path.segments.len() == 1 => { - Generic(kw::SelfUpper) + Type::SelfTy } Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name), _ => { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6476c8bd7c0d3..0fe535ade9b2a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1006,6 +1006,7 @@ fn fmt_type<'cx>( match *t { clean::Generic(name) => f.write_str(name.as_str()), + clean::SelfTy => f.write_str("Self"), clean::Type::Path { ref path } => { // Paths like `T::Output` and `Self::Output` should be rendered with all segments. let did = path.def_id(); diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index b3f4d82e054b8..fc3d6c99b809f 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -797,7 +797,11 @@ fn get_index_type_id( } } // Not supported yet - clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None, + clean::Type::Pat(..) + | clean::Generic(_) + | clean::SelfTy + | clean::ImplTrait(_) + | clean::Infer => None, } } @@ -848,13 +852,18 @@ fn simplify_fn_type<'tcx, 'a>( (false, arg) }; + let as_arg_s = |t: &Type| match *t { + Type::Generic(arg_s) => Some(arg_s), + Type::SelfTy => Some(kw::SelfUpper), + _ => None, + }; // If this argument is a type parameter and not a trait bound or a type, we need to look // for its bounds. - if let Type::Generic(arg_s) = *arg { + if let Some(arg_s) = as_arg_s(arg) { // First we check if the bounds are in a `where` predicate... let mut type_bounds = Vec::new(); for where_pred in generics.where_predicates.iter().filter(|g| match g { - WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s, + WherePredicate::BoundPredicate { ty, .. } => *ty == *arg, _ => false, }) { let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]); diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index b56244f2d3b6d..b97d710c007ce 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -578,7 +578,7 @@ impl FromWithTcx for Type { fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { use clean::Type::{ Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath, - RawPointer, Slice, Tuple, + RawPointer, SelfTy, Slice, Tuple, }; match ty { @@ -588,6 +588,8 @@ impl FromWithTcx for Type { traits: bounds.into_tcx(tcx), }), Generic(s) => Type::Generic(s.to_string()), + // FIXME: add dedicated variant to json Type? + SelfTy => Type::Generic("Self".to_owned()), Primitive(p) => Type::Primitive(p.as_sym().to_string()), BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), Tuple(t) => Type::Tuple(t.into_tcx(tcx)), From 4e348fa803723a38553138d9795cb2c6b7fb964a Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 31 Jul 2024 17:06:32 -0700 Subject: [PATCH 11/15] rustdoc: Stop treating `Self` as a generic in search index We already have special-cased code to handle inlining `Self` as the type or trait it refers to, and this was just causing glitches like the search `A -> B` yielding blanket `Into` impls. --- src/librustdoc/html/render/search_index.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index fc3d6c99b809f..e4d948b8c9c1a 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -852,14 +852,9 @@ fn simplify_fn_type<'tcx, 'a>( (false, arg) }; - let as_arg_s = |t: &Type| match *t { - Type::Generic(arg_s) => Some(arg_s), - Type::SelfTy => Some(kw::SelfUpper), - _ => None, - }; // If this argument is a type parameter and not a trait bound or a type, we need to look // for its bounds. - if let Some(arg_s) = as_arg_s(arg) { + if let Type::Generic(arg_s) = *arg { // First we check if the bounds are in a `where` predicate... let mut type_bounds = Vec::new(); for where_pred in generics.where_predicates.iter().filter(|g| match g { From e452e3def69deca6a671b6067b1faf14b4cf83f2 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 31 Jul 2024 17:17:14 -0700 Subject: [PATCH 12/15] Use `match` instead of sequence of `if let`s This is much more readable and idiomatic, and also may help performance since `match`es usually use switches while `if`s may not. I also fixed an incorrect comment. --- src/librustdoc/html/render/search_index.rs | 477 +++++++++++---------- 1 file changed, 243 insertions(+), 234 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index e4d948b8c9c1a..8a2f31f7413e1 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -854,34 +854,70 @@ fn simplify_fn_type<'tcx, 'a>( // If this argument is a type parameter and not a trait bound or a type, we need to look // for its bounds. - if let Type::Generic(arg_s) = *arg { - // First we check if the bounds are in a `where` predicate... - let mut type_bounds = Vec::new(); - for where_pred in generics.where_predicates.iter().filter(|g| match g { - WherePredicate::BoundPredicate { ty, .. } => *ty == *arg, - _ => false, - }) { - let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]); - for bound in bounds.iter() { - if let Some(path) = bound.get_trait_path() { - let ty = Type::Path { path }; - simplify_fn_type( - self_, - generics, - &ty, - tcx, - recurse + 1, - &mut type_bounds, - rgen, - is_return, - cache, - ); + match *arg { + Type::Generic(arg_s) => { + // First we check if the bounds are in a `where` predicate... + let mut type_bounds = Vec::new(); + for where_pred in generics.where_predicates.iter().filter(|g| match g { + WherePredicate::BoundPredicate { ty, .. } => *ty == *arg, + _ => false, + }) { + let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]); + for bound in bounds.iter() { + if let Some(path) = bound.get_trait_path() { + let ty = Type::Path { path }; + simplify_fn_type( + self_, + generics, + &ty, + tcx, + recurse + 1, + &mut type_bounds, + rgen, + is_return, + cache, + ); + } + } + } + // Otherwise we check if the trait bounds are "inlined" like `T: Option`... + if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { + for bound in bound.get_bounds().unwrap_or(&[]) { + if let Some(path) = bound.get_trait_path() { + let ty = Type::Path { path }; + simplify_fn_type( + self_, + generics, + &ty, + tcx, + recurse + 1, + &mut type_bounds, + rgen, + is_return, + cache, + ); + } } } + if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) { + res.push(RenderType { + id: Some(RenderTypeId::Index(*idx)), + generics: None, + bindings: None, + }); + } else { + let idx = -isize::try_from(rgen.len() + 1).unwrap(); + rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds)); + res.push(RenderType { + id: Some(RenderTypeId::Index(idx)), + generics: None, + bindings: None, + }); + } } - // Otherwise we check if the trait bounds are "inlined" like `T: Option`... - if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) { - for bound in bound.get_bounds().unwrap_or(&[]) { + Type::ImplTrait(ref bounds) => { + let mut type_bounds = Vec::new(); + for bound in bounds { if let Some(path) = bound.get_trait_path() { let ty = Type::Path { path }; simplify_fn_type( @@ -897,84 +933,22 @@ fn simplify_fn_type<'tcx, 'a>( ); } } - } - if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) { - res.push(RenderType { - id: Some(RenderTypeId::Index(*idx)), - generics: None, - bindings: None, - }); - } else { - let idx = -isize::try_from(rgen.len() + 1).unwrap(); - rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds)); - res.push(RenderType { - id: Some(RenderTypeId::Index(idx)), - generics: None, - bindings: None, - }); - } - } else if let Type::ImplTrait(ref bounds) = *arg { - let mut type_bounds = Vec::new(); - for bound in bounds { - if let Some(path) = bound.get_trait_path() { - let ty = Type::Path { path }; - simplify_fn_type( - self_, - generics, - &ty, - tcx, - recurse + 1, - &mut type_bounds, - rgen, - is_return, - cache, - ); + if is_return && !type_bounds.is_empty() { + // In return position, `impl Trait` is a unique thing. + res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None }); + } else { + // In parameter position, `impl Trait` is the same as an unnamed generic parameter. + let idx = -isize::try_from(rgen.len() + 1).unwrap(); + rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds)); + res.push(RenderType { + id: Some(RenderTypeId::Index(idx)), + generics: None, + bindings: None, + }); } } - if is_return && !type_bounds.is_empty() { - // In parameter position, `impl Trait` is a unique thing. - res.push(RenderType { id: None, generics: Some(type_bounds), bindings: None }); - } else { - // In parameter position, `impl Trait` is the same as an unnamed generic parameter. - let idx = -isize::try_from(rgen.len() + 1).unwrap(); - rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds)); - res.push(RenderType { - id: Some(RenderTypeId::Index(idx)), - generics: None, - bindings: None, - }); - } - } else if let Type::Slice(ref ty) = *arg { - let mut ty_generics = Vec::new(); - simplify_fn_type( - self_, - generics, - &ty, - tcx, - recurse + 1, - &mut ty_generics, - rgen, - is_return, - cache, - ); - res.push(get_index_type(arg, ty_generics, rgen)); - } else if let Type::Array(ref ty, _) = *arg { - let mut ty_generics = Vec::new(); - simplify_fn_type( - self_, - generics, - &ty, - tcx, - recurse + 1, - &mut ty_generics, - rgen, - is_return, - cache, - ); - res.push(get_index_type(arg, ty_generics, rgen)); - } else if let Type::Tuple(ref tys) = *arg { - let mut ty_generics = Vec::new(); - for ty in tys { + Type::Slice(ref ty) => { + let mut ty_generics = Vec::new(); simplify_fn_type( self_, generics, @@ -986,15 +960,14 @@ fn simplify_fn_type<'tcx, 'a>( is_return, cache, ); + res.push(get_index_type(arg, ty_generics, rgen)); } - res.push(get_index_type(arg, ty_generics, rgen)); - } else if let Type::BareFunction(ref bf) = *arg { - let mut ty_generics = Vec::new(); - for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) { + Type::Array(ref ty, _) => { + let mut ty_generics = Vec::new(); simplify_fn_type( self_, generics, - ty, + &ty, tcx, recurse + 1, &mut ty_generics, @@ -1002,62 +975,11 @@ fn simplify_fn_type<'tcx, 'a>( is_return, cache, ); + res.push(get_index_type(arg, ty_generics, rgen)); } - // The search index, for simplicity's sake, represents fn pointers and closures - // the same way: as a tuple for the parameters, and an associated type for the - // return type. - let mut ty_output = Vec::new(); - simplify_fn_type( - self_, - generics, - &bf.decl.output, - tcx, - recurse + 1, - &mut ty_output, - rgen, - is_return, - cache, - ); - let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)]; - res.push(RenderType { - id: get_index_type_id(&arg, rgen), - bindings: Some(ty_bindings), - generics: Some(ty_generics), - }); - } else if let Type::BorrowedRef { lifetime: _, mutability, ref type_ } = *arg { - let mut ty_generics = Vec::new(); - if mutability.is_mut() { - ty_generics.push(RenderType { - id: Some(RenderTypeId::Mut), - generics: None, - bindings: None, - }); - } - simplify_fn_type( - self_, - generics, - &type_, - tcx, - recurse + 1, - &mut ty_generics, - rgen, - is_return, - cache, - ); - res.push(get_index_type(arg, ty_generics, rgen)); - } else { - // This is not a type parameter. So for example if we have `T, U: Option`, and we're - // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't. - // - // So in here, we can add it directly and look for its own type parameters (so for `Option`, - // we will look for them but not for `T`). - let mut ty_generics = Vec::new(); - let mut ty_constraints = Vec::new(); - if let Some(arg_generics) = arg.generic_args() { - for ty in arg_generics.into_iter().filter_map(|param| match param { - clean::GenericArg::Type(ty) => Some(ty), - _ => None, - }) { + Type::Tuple(ref tys) => { + let mut ty_generics = Vec::new(); + for ty in tys { simplify_fn_type( self_, generics, @@ -1070,94 +992,181 @@ fn simplify_fn_type<'tcx, 'a>( cache, ); } - for constraint in arg_generics.constraints() { - simplify_fn_constraint( + res.push(get_index_type(arg, ty_generics, rgen)); + } + Type::BareFunction(ref bf) => { + let mut ty_generics = Vec::new(); + for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) { + simplify_fn_type( self_, generics, - &constraint, + ty, tcx, recurse + 1, - &mut ty_constraints, + &mut ty_generics, rgen, is_return, cache, ); } + // The search index, for simplicity's sake, represents fn pointers and closures + // the same way: as a tuple for the parameters, and an associated type for the + // return type. + let mut ty_output = Vec::new(); + simplify_fn_type( + self_, + generics, + &bf.decl.output, + tcx, + recurse + 1, + &mut ty_output, + rgen, + is_return, + cache, + ); + let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)]; + res.push(RenderType { + id: get_index_type_id(&arg, rgen), + bindings: Some(ty_bindings), + generics: Some(ty_generics), + }); } - // Every trait associated type on self gets assigned to a type parameter index - // this same one is used later for any appearances of these types - // - // for example, Iterator::next is: - // - // trait Iterator { - // fn next(&mut self) -> Option - // } - // - // Self is technically just Iterator, but we want to pretend it's more like this: - // - // fn next(self: Iterator) -> Option - if is_self - && let Type::Path { path } = arg - && let def_id = path.def_id() - && let Some(trait_) = cache.traits.get(&def_id) - && trait_.items.iter().any(|at| at.is_ty_associated_type()) - { - for assoc_ty in &trait_.items { - if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind - && let Some(name) = assoc_ty.name - { - let idx = -isize::try_from(rgen.len() + 1).unwrap(); - let (idx, stored_bounds) = rgen - .entry(SimplifiedParam::AssociatedType(def_id, name)) - .or_insert_with(|| (idx, Vec::new())); - let idx = *idx; - if stored_bounds.is_empty() { - // Can't just pass stored_bounds to simplify_fn_type, - // because it also accepts rgen as a parameter. - // Instead, have it fill in this local, then copy it into the map afterward. - let mut type_bounds = Vec::new(); - for bound in bounds { - if let Some(path) = bound.get_trait_path() { - let ty = Type::Path { path }; - simplify_fn_type( - self_, - generics, - &ty, - tcx, - recurse + 1, - &mut type_bounds, - rgen, - is_return, - cache, - ); - } - } - let stored_bounds = &mut rgen - .get_mut(&SimplifiedParam::AssociatedType(def_id, name)) - .unwrap() - .1; + Type::BorrowedRef { lifetime: _, mutability, ref type_ } => { + let mut ty_generics = Vec::new(); + if mutability.is_mut() { + ty_generics.push(RenderType { + id: Some(RenderTypeId::Mut), + generics: None, + bindings: None, + }); + } + simplify_fn_type( + self_, + generics, + &type_, + tcx, + recurse + 1, + &mut ty_generics, + rgen, + is_return, + cache, + ); + res.push(get_index_type(arg, ty_generics, rgen)); + } + _ => { + // This is not a type parameter. So for example if we have `T, U: Option`, and we're + // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't. + // + // So in here, we can add it directly and look for its own type parameters (so for `Option`, + // we will look for them but not for `T`). + let mut ty_generics = Vec::new(); + let mut ty_constraints = Vec::new(); + if let Some(arg_generics) = arg.generic_args() { + for ty in arg_generics.into_iter().filter_map(|param| match param { + clean::GenericArg::Type(ty) => Some(ty), + _ => None, + }) { + simplify_fn_type( + self_, + generics, + &ty, + tcx, + recurse + 1, + &mut ty_generics, + rgen, + is_return, + cache, + ); + } + for constraint in arg_generics.constraints() { + simplify_fn_constraint( + self_, + generics, + &constraint, + tcx, + recurse + 1, + &mut ty_constraints, + rgen, + is_return, + cache, + ); + } + } + // Every trait associated type on self gets assigned to a type parameter index + // this same one is used later for any appearances of these types + // + // for example, Iterator::next is: + // + // trait Iterator { + // fn next(&mut self) -> Option + // } + // + // Self is technically just Iterator, but we want to pretend it's more like this: + // + // fn next(self: Iterator) -> Option + if is_self + && let Type::Path { path } = arg + && let def_id = path.def_id() + && let Some(trait_) = cache.traits.get(&def_id) + && trait_.items.iter().any(|at| at.is_ty_associated_type()) + { + for assoc_ty in &trait_.items { + if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &*assoc_ty.kind + && let Some(name) = assoc_ty.name + { + let idx = -isize::try_from(rgen.len() + 1).unwrap(); + let (idx, stored_bounds) = rgen + .entry(SimplifiedParam::AssociatedType(def_id, name)) + .or_insert_with(|| (idx, Vec::new())); + let idx = *idx; if stored_bounds.is_empty() { - *stored_bounds = type_bounds; + // Can't just pass stored_bounds to simplify_fn_type, + // because it also accepts rgen as a parameter. + // Instead, have it fill in this local, then copy it into the map afterward. + let mut type_bounds = Vec::new(); + for bound in bounds { + if let Some(path) = bound.get_trait_path() { + let ty = Type::Path { path }; + simplify_fn_type( + self_, + generics, + &ty, + tcx, + recurse + 1, + &mut type_bounds, + rgen, + is_return, + cache, + ); + } + } + let stored_bounds = &mut rgen + .get_mut(&SimplifiedParam::AssociatedType(def_id, name)) + .unwrap() + .1; + if stored_bounds.is_empty() { + *stored_bounds = type_bounds; + } } + ty_constraints.push(( + RenderTypeId::AssociatedType(name), + vec![RenderType { + id: Some(RenderTypeId::Index(idx)), + generics: None, + bindings: None, + }], + )) } - ty_constraints.push(( - RenderTypeId::AssociatedType(name), - vec![RenderType { - id: Some(RenderTypeId::Index(idx)), - generics: None, - bindings: None, - }], - )) } } - } - let id = get_index_type_id(&arg, rgen); - if id.is_some() || !ty_generics.is_empty() { - res.push(RenderType { - id, - bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) }, - generics: if ty_generics.is_empty() { None } else { Some(ty_generics) }, - }); + let id = get_index_type_id(&arg, rgen); + if id.is_some() || !ty_generics.is_empty() { + res.push(RenderType { + id, + bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) }, + generics: if ty_generics.is_empty() { None } else { Some(ty_generics) }, + }); + } } } } From b4f77df9f8540f48744794c641e12ef66e0e57ba Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 31 Jul 2024 17:33:13 -0700 Subject: [PATCH 13/15] rustdoc: Delete `ReceiverTy` (formerly known as `SelfTy`) It was barely used, and the places that used it are actually clearer without it since they were often undoing some of its work. This also avoids an unnecessary clone of the receiver type and removes a layer of logical indirection in the code. --- src/librustdoc/clean/types.rs | 25 +++---------------------- src/librustdoc/html/format.rs | 27 ++++++++++----------------- src/librustdoc/html/render/mod.rs | 11 +++++------ 3 files changed, 18 insertions(+), 45 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 82f1312364a5b..4850500a1bfae 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -34,7 +34,6 @@ use thin_vec::ThinVec; use {rustc_ast as ast, rustc_hir as hir}; pub(crate) use self::ItemKind::*; -pub(crate) use self::ReceiverTy::*; pub(crate) use self::Type::{ Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath, RawPointer, SelfTy, Slice, Tuple, @@ -1384,7 +1383,7 @@ pub(crate) struct FnDecl { } impl FnDecl { - pub(crate) fn receiver_type(&self) -> Option { + pub(crate) fn receiver_type(&self) -> Option<&Type> { self.inputs.values.get(0).and_then(|v| v.to_receiver()) } } @@ -1403,27 +1402,9 @@ pub(crate) struct Argument { pub(crate) is_const: bool, } -#[derive(Clone, PartialEq, Debug)] -pub(crate) enum ReceiverTy { - SelfValue, - SelfBorrowed(Option, Mutability), - SelfExplicit(Type), -} - impl Argument { - pub(crate) fn to_receiver(&self) -> Option { - if self.name != kw::SelfLower { - return None; - } - if self.type_.is_self_type() { - return Some(SelfValue); - } - match self.type_ { - BorrowedRef { ref lifetime, mutability, ref type_ } if type_.is_self_type() => { - Some(SelfBorrowed(lifetime.clone(), mutability)) - } - _ => Some(SelfExplicit(self.type_.clone())), - } + pub(crate) fn to_receiver(&self) -> Option<&Type> { + if self.name == kw::SelfLower { Some(&self.type_) } else { None } } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 0fe535ade9b2a..b5ab6a35fdb9d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1455,27 +1455,20 @@ impl clean::FnDecl { for (i, input) in self.inputs.values.iter().enumerate() { if let Some(selfty) = input.to_receiver() { match selfty { - clean::SelfValue => { + clean::SelfTy => { write!(f, "self")?; } - clean::SelfBorrowed(Some(ref lt), mutability) => { - write!( - f, - "{amp}{lifetime} {mutability}self", - lifetime = lt.print(), - mutability = mutability.print_with_space(), - )?; - } - clean::SelfBorrowed(None, mutability) => { - write!( - f, - "{amp}{mutability}self", - mutability = mutability.print_with_space(), - )?; + clean::BorrowedRef { lifetime, mutability, type_: box clean::SelfTy } => { + write!(f, "{amp}")?; + match lifetime { + Some(lt) => write!(f, "{lt} ", lt = lt.print())?, + None => {} + } + write!(f, "{mutability}self", mutability = mutability.print_with_space())?; } - clean::SelfExplicit(ref typ) => { + _ => { write!(f, "self: ")?; - typ.print(cx).fmt(f)?; + selfty.print(cx).fmt(f)?; } } } else { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index b7bcda2a604cf..9074e40a53614 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -58,7 +58,7 @@ use serde::{Serialize, Serializer}; pub(crate) use self::context::*; pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc}; -use crate::clean::{self, ItemId, ReceiverTy, RenderedLink}; +use crate::clean::{self, ItemId, RenderedLink}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; @@ -1378,15 +1378,14 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> }; if let Some(self_ty) = self_type_opt { - let (by_mut_ref, by_box, by_value) = match self_ty { - ReceiverTy::SelfBorrowed(_, mutability) - | ReceiverTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => { + let (by_mut_ref, by_box, by_value) = match *self_ty { + clean::Type::BorrowedRef { mutability, .. } => { (mutability == Mutability::Mut, false, false) } - ReceiverTy::SelfExplicit(clean::Type::Path { path }) => { + clean::Type::Path { ref path } => { (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false) } - ReceiverTy::SelfValue => (false, false, true), + clean::Type::SelfTy => (false, false, true), _ => (false, false, false), }; From dac7f20e1308ea17655d17f43dffaca813857300 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 31 Jul 2024 20:13:17 -0700 Subject: [PATCH 14/15] Add test for `Self` not being a generic in search index --- tests/rustdoc-js/self-is-not-generic.js | 22 ++++++++++++++++++++++ tests/rustdoc-js/self-is-not-generic.rs | 11 +++++++++++ 2 files changed, 33 insertions(+) create mode 100644 tests/rustdoc-js/self-is-not-generic.js create mode 100644 tests/rustdoc-js/self-is-not-generic.rs diff --git a/tests/rustdoc-js/self-is-not-generic.js b/tests/rustdoc-js/self-is-not-generic.js new file mode 100644 index 0000000000000..0fdf5b4117d8f --- /dev/null +++ b/tests/rustdoc-js/self-is-not-generic.js @@ -0,0 +1,22 @@ +// exact-check + +const EXPECTED = [ + { + 'query': 'A -> A', + 'others': [ + { 'path': 'self_is_not_generic::Thing', 'name': 'from' } + ], + }, + { + 'query': 'A -> B', + 'others': [ + { 'path': 'self_is_not_generic::Thing', 'name': 'try_from' } + ], + }, + { + 'query': 'Combine -> Combine', + 'others': [ + { 'path': 'self_is_not_generic::Combine', 'name': 'combine' } + ], + } +]; diff --git a/tests/rustdoc-js/self-is-not-generic.rs b/tests/rustdoc-js/self-is-not-generic.rs new file mode 100644 index 0000000000000..d6a96acb73caf --- /dev/null +++ b/tests/rustdoc-js/self-is-not-generic.rs @@ -0,0 +1,11 @@ +pub trait Combine { + fn combine(&self, other: &Self) -> Self; +} + +pub struct Thing; + +impl Combine for Thing { + fn combine(&self, other: &Self) -> Self { + Self + } +} From 70ab51f988ae44afb9f50151b7732ba10c37e4a8 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sun, 4 Aug 2024 07:11:11 +0900 Subject: [PATCH 15/15] Correct the const stabilization of `<[T]>::last_chunk` `<[T]>::first_chunk` became const stable in 1.77, but `<[T]>::last_chunk` was left out. This was fixed in 3488679768d, which reached stable in 1.80, making `<[T]>::last_chunk` const stable as of that version, but it is documented as being const stable as 1.77. While this is what should have happened, the documentation should reflect what actually did happen. --- library/core/src/slice/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 45dc828eb2ed9..b1440214d795a 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -522,7 +522,7 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] + #[rustc_const_stable(feature = "const_slice_last_chunk", since = "1.80.0")] pub const fn last_chunk(&self) -> Option<&[T; N]> { if self.len() < N { None