diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 297df7c2c9765..5180162ae47d6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1207,13 +1207,26 @@ fn maybe_strip_file_name(mut path: PathBuf) -> PathBuf { if path.file_name().map_or(0, |name| name.len()) > MAX_FILENAME_LENGTH { let filename = path.file_name().unwrap().to_string_lossy(); let hash_len = 64 / 4; // Hash64 is 64 bits encoded in hex - let stripped_len = filename.len() - MAX_FILENAME_LENGTH + hash_len; + let hyphen_len = 1; // the '-' we insert between hash and suffix + + // number of bytes of suffix we can keep so that "hash-" fits + let allowed_suffix = MAX_FILENAME_LENGTH.saturating_sub(hash_len + hyphen_len); + + // number of bytes to remove from the start + let stripped_bytes = filename.len().saturating_sub(allowed_suffix); + + // Find the next character boundary at or after `stripped_bytes` so slicing is valid. + let split_at = filename + .char_indices() + .find(|(i, _)| *i >= stripped_bytes) + .map(|(i, _)| i) + .unwrap_or(filename.len()); let mut hasher = StableHasher::new(); - filename[..stripped_len].hash(&mut hasher); + filename[..split_at].hash(&mut hasher); let hash = hasher.finish::(); - path.set_file_name(format!("{:x}-{}", hash, &filename[stripped_len..])); + path.set_file_name(format!("{:x}-{}", hash, &filename[split_at..])); } path } diff --git a/tests/run-make/lto-long-filenames/rmake.rs b/tests/run-make/lto-long-filenames/rmake.rs index 9e0ba63e9f5b8..98ce54e5efc82 100644 --- a/tests/run-make/lto-long-filenames/rmake.rs +++ b/tests/run-make/lto-long-filenames/rmake.rs @@ -9,8 +9,6 @@ //@ ignore-cross-compile -use std::fs; - use run_make_support::{rfs, rustc}; // This test make sure we don't get such following error: diff --git a/tests/run-make/lto-long-filenames_cn/rmake.rs b/tests/run-make/lto-long-filenames_cn/rmake.rs new file mode 100644 index 0000000000000..f129b686012dc --- /dev/null +++ b/tests/run-make/lto-long-filenames_cn/rmake.rs @@ -0,0 +1,19 @@ +//@ ignore-cross-compile + +use run_make_support::{rfs, rustc}; + +// This test make sure we don't crash when lto creates output files with long names. +// cn characters can be multi-byte and thus trigger the long filename reduction code more easily. +// we need to make sure that the code is properly generating names at char boundaries. +// as reported in issue #147975 +fn main() { + let lto_flags = ["-Clto", "-Clto=yes", "-Clto=off", "-Clto=thin", "-Clto=fat"]; + for prefix_len in 0..4 { + let prefix: String = std::iter::repeat("_").take(prefix_len).collect(); + let main_file = format!("{}28_找出字符串中第一个匹配项的下标.rs", prefix); + rfs::write(&main_file, "fn main() {}\n"); + for flag in lto_flags { + rustc().input(&main_file).arg(flag).run(); + } + } +}