Skip to content

Commit e3ee7f7

Browse files
committed
Auto merge of #144768 - jhpratt:rollup-otf1yfj, r=jhpratt
Rollup of 7 pull requests Successful merges: - #143849 (rustdoc: never link to unnamable items) - #144683 (Simplify library dependencies on `compiler-builtins`) - #144691 (Extend `is_case_difference` to handle digit-letter confusables) - #144700 (rustdoc-json: Move `#[macro_export]` from `Other` to it's own variant) - #144751 (Add correct dynamic_lib_extension for aix) - #144757 (Ping Muscraft when emitter change) - #144759 (triagebot: Label `compiler-builtins` T-libs) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 6c02dd4 + 74d5b09 commit e3ee7f7

34 files changed

+440
-99
lines changed

compiler/rustc_errors/src/emitter.rs

Lines changed: 105 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -262,19 +262,11 @@ pub trait Emitter {
262262
format!("help: {msg}")
263263
} else {
264264
// Show the default suggestion text with the substitution
265-
format!(
266-
"help: {}{}: `{}`",
267-
msg,
268-
if self
269-
.source_map()
270-
.is_some_and(|sm| is_case_difference(sm, snippet, part.span,))
271-
{
272-
" (notice the capitalization)"
273-
} else {
274-
""
275-
},
276-
snippet,
277-
)
265+
let confusion_type = self
266+
.source_map()
267+
.map(|sm| detect_confusion_type(sm, snippet, part.span))
268+
.unwrap_or(ConfusionType::None);
269+
format!("help: {}{}: `{}`", msg, confusion_type.label_text(), snippet,)
278270
};
279271
primary_span.push_span_label(part.span, msg);
280272

@@ -2031,12 +2023,12 @@ impl HumanEmitter {
20312023
buffer.append(0, ": ", Style::HeaderMsg);
20322024

20332025
let mut msg = vec![(suggestion.msg.to_owned(), Style::NoStyle)];
2034-
if suggestions
2035-
.iter()
2036-
.take(MAX_SUGGESTIONS)
2037-
.any(|(_, _, _, only_capitalization)| *only_capitalization)
2026+
if let Some(confusion_type) =
2027+
suggestions.iter().take(MAX_SUGGESTIONS).find_map(|(_, _, _, confusion_type)| {
2028+
if confusion_type.has_confusion() { Some(*confusion_type) } else { None }
2029+
})
20382030
{
2039-
msg.push((" (notice the capitalization difference)".into(), Style::NoStyle));
2031+
msg.push((confusion_type.label_text().into(), Style::NoStyle));
20402032
}
20412033
self.msgs_to_buffer(
20422034
&mut buffer,
@@ -3531,24 +3523,107 @@ pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
35313523
}
35323524

35333525
/// Whether the original and suggested code are visually similar enough to warrant extra wording.
3534-
pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
3535-
// FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.
3526+
pub fn detect_confusion_type(sm: &SourceMap, suggested: &str, sp: Span) -> ConfusionType {
35363527
let found = match sm.span_to_snippet(sp) {
35373528
Ok(snippet) => snippet,
35383529
Err(e) => {
35393530
warn!(error = ?e, "Invalid span {:?}", sp);
3540-
return false;
3531+
return ConfusionType::None;
35413532
}
35423533
};
3543-
let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];
3544-
// All the chars that differ in capitalization are confusable (above):
3545-
let confusable = iter::zip(found.chars(), suggested.chars())
3546-
.filter(|(f, s)| f != s)
3547-
.all(|(f, s)| ascii_confusables.contains(&f) || ascii_confusables.contains(&s));
3548-
confusable && found.to_lowercase() == suggested.to_lowercase()
3549-
// FIXME: We sometimes suggest the same thing we already have, which is a
3550-
// bug, but be defensive against that here.
3551-
&& found != suggested
3534+
3535+
let mut has_case_confusion = false;
3536+
let mut has_digit_letter_confusion = false;
3537+
3538+
if found.len() == suggested.len() {
3539+
let mut has_case_diff = false;
3540+
let mut has_digit_letter_confusable = false;
3541+
let mut has_other_diff = false;
3542+
3543+
let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];
3544+
3545+
let digit_letter_confusables = [('0', 'O'), ('1', 'l'), ('5', 'S'), ('8', 'B'), ('9', 'g')];
3546+
3547+
for (f, s) in iter::zip(found.chars(), suggested.chars()) {
3548+
if f != s {
3549+
if f.to_lowercase().to_string() == s.to_lowercase().to_string() {
3550+
// Check for case differences (any character that differs only in case)
3551+
if ascii_confusables.contains(&f) || ascii_confusables.contains(&s) {
3552+
has_case_diff = true;
3553+
} else {
3554+
has_other_diff = true;
3555+
}
3556+
} else if digit_letter_confusables.contains(&(f, s))
3557+
|| digit_letter_confusables.contains(&(s, f))
3558+
{
3559+
// Check for digit-letter confusables (like 0 vs O, 1 vs l, etc.)
3560+
has_digit_letter_confusable = true;
3561+
} else {
3562+
has_other_diff = true;
3563+
}
3564+
}
3565+
}
3566+
3567+
// If we have case differences and no other differences
3568+
if has_case_diff && !has_other_diff && found != suggested {
3569+
has_case_confusion = true;
3570+
}
3571+
if has_digit_letter_confusable && !has_other_diff && found != suggested {
3572+
has_digit_letter_confusion = true;
3573+
}
3574+
}
3575+
3576+
match (has_case_confusion, has_digit_letter_confusion) {
3577+
(true, true) => ConfusionType::Both,
3578+
(true, false) => ConfusionType::Case,
3579+
(false, true) => ConfusionType::DigitLetter,
3580+
(false, false) => ConfusionType::None,
3581+
}
3582+
}
3583+
3584+
/// Represents the type of confusion detected between original and suggested code.
3585+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3586+
pub enum ConfusionType {
3587+
/// No confusion detected
3588+
None,
3589+
/// Only case differences (e.g., "hello" vs "Hello")
3590+
Case,
3591+
/// Only digit-letter confusion (e.g., "0" vs "O", "1" vs "l")
3592+
DigitLetter,
3593+
/// Both case and digit-letter confusion
3594+
Both,
3595+
}
3596+
3597+
impl ConfusionType {
3598+
/// Returns the appropriate label text for this confusion type.
3599+
pub fn label_text(&self) -> &'static str {
3600+
match self {
3601+
ConfusionType::None => "",
3602+
ConfusionType::Case => " (notice the capitalization)",
3603+
ConfusionType::DigitLetter => " (notice the digit/letter confusion)",
3604+
ConfusionType::Both => " (notice the capitalization and digit/letter confusion)",
3605+
}
3606+
}
3607+
3608+
/// Combines two confusion types. If either is `Both`, the result is `Both`.
3609+
/// If one is `Case` and the other is `DigitLetter`, the result is `Both`.
3610+
/// Otherwise, returns the non-`None` type, or `None` if both are `None`.
3611+
pub fn combine(self, other: ConfusionType) -> ConfusionType {
3612+
match (self, other) {
3613+
(ConfusionType::None, other) => other,
3614+
(this, ConfusionType::None) => this,
3615+
(ConfusionType::Both, _) | (_, ConfusionType::Both) => ConfusionType::Both,
3616+
(ConfusionType::Case, ConfusionType::DigitLetter)
3617+
| (ConfusionType::DigitLetter, ConfusionType::Case) => ConfusionType::Both,
3618+
(ConfusionType::Case, ConfusionType::Case) => ConfusionType::Case,
3619+
(ConfusionType::DigitLetter, ConfusionType::DigitLetter) => ConfusionType::DigitLetter,
3620+
}
3621+
}
3622+
3623+
/// Returns true if this confusion type represents any kind of confusion.
3624+
pub fn has_confusion(&self) -> bool {
3625+
*self != ConfusionType::None
3626+
}
35523627
}
35533628

35543629
pub(crate) fn should_show_source_code(

compiler/rustc_errors/src/lib.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub use diagnostic_impls::{
5050
IndicateAnonymousLifetime, SingleLabelManySpans,
5151
};
5252
pub use emitter::ColorConfig;
53-
use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
53+
use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
5454
use rustc_data_structures::AtomicRef;
5555
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
5656
use rustc_data_structures::stable_hasher::StableHasher;
@@ -308,7 +308,7 @@ impl CodeSuggestion {
308308
pub(crate) fn splice_lines(
309309
&self,
310310
sm: &SourceMap,
311-
) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
311+
) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)> {
312312
// For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector
313313
// corresponds to the output snippet's lines, while the second level corresponds to the
314314
// substrings within that line that should be highlighted.
@@ -414,14 +414,15 @@ impl CodeSuggestion {
414414
// We need to keep track of the difference between the existing code and the added
415415
// or deleted code in order to point at the correct column *after* substitution.
416416
let mut acc = 0;
417-
let mut only_capitalization = false;
417+
let mut confusion_type = ConfusionType::None;
418418
for part in &mut substitution.parts {
419419
// If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the
420420
// suggestion and snippet to look as if we just suggested to add
421421
// `"b"`, which is typically much easier for the user to understand.
422422
part.trim_trivial_replacements(sm);
423423

424-
only_capitalization |= is_case_difference(sm, &part.snippet, part.span);
424+
let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
425+
confusion_type = confusion_type.combine(part_confusion);
425426
let cur_lo = sm.lookup_char_pos(part.span.lo());
426427
if prev_hi.line == cur_lo.line {
427428
let mut count =
@@ -511,7 +512,7 @@ impl CodeSuggestion {
511512
if highlights.iter().all(|parts| parts.is_empty()) {
512513
None
513514
} else {
514-
Some((buf, substitution.parts, highlights, only_capitalization))
515+
Some((buf, substitution.parts, highlights, confusion_type))
515516
}
516517
})
517518
.collect()

library/Cargo.lock

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,8 @@ name = "panic_abort"
183183
version = "0.0.0"
184184
dependencies = [
185185
"alloc",
186-
"compiler_builtins",
187-
"core",
188186
"libc",
187+
"rustc-std-workspace-core",
189188
]
190189

191190
[[package]]
@@ -194,9 +193,8 @@ version = "0.0.0"
194193
dependencies = [
195194
"alloc",
196195
"cfg-if",
197-
"compiler_builtins",
198-
"core",
199196
"libc",
197+
"rustc-std-workspace-core",
200198
"unwind",
201199
]
202200

@@ -313,7 +311,6 @@ dependencies = [
313311
"addr2line",
314312
"alloc",
315313
"cfg-if",
316-
"compiler_builtins",
317314
"core",
318315
"dlmalloc",
319316
"fortanix-sgx-abi",
@@ -380,9 +377,8 @@ name = "unwind"
380377
version = "0.0.0"
381378
dependencies = [
382379
"cfg-if",
383-
"compiler_builtins",
384-
"core",
385380
"libc",
381+
"rustc-std-workspace-core",
386382
"unwinding",
387383
]
388384

library/panic_abort/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ bench = false
1212
doc = false
1313

1414
[dependencies]
15-
core = { path = "../core" }
16-
compiler_builtins = { path = "../compiler-builtins/compiler-builtins" }
15+
core = { path = "../rustc-std-workspace-core", package = "rustc-std-workspace-core" }
1716

1817
[target.'cfg(target_os = "android")'.dependencies]
1918
libc = { version = "0.2", default-features = false }

library/panic_unwind/Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ doc = false
1313

1414
[dependencies]
1515
alloc = { path = "../alloc" }
16-
core = { path = "../core" }
17-
unwind = { path = "../unwind" }
18-
compiler_builtins = { path = "../compiler-builtins/compiler-builtins" }
1916
cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
17+
core = { path = "../rustc-std-workspace-core", package = "rustc-std-workspace-core" }
18+
unwind = { path = "../unwind" }
2019

2120
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
2221
libc = { version = "0.2", default-features = false }

library/rustc-std-workspace-core/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ on crates.io will draw a dependency edge to `libcore`, the version defined in
1111
this repository. That should draw all the dependency edges to ensure Cargo
1212
builds crates successfully!
1313

14+
`rustc-std-workspace-core` also ensures `compiler-builtins` is in the crate
15+
graph. This crate is used by other crates in `library/`, other than `std` and
16+
`alloc`, so the `compiler-builtins` setup only needs to be configured in a
17+
single place. (Otherwise these crates would just need to depend on `core` and
18+
`compiler-builtins` separately.)
19+
1420
Note that crates on crates.io need to depend on this crate with the name `core`
1521
for everything to work correctly. To do that they can use:
1622

library/std/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
1818
panic_unwind = { path = "../panic_unwind", optional = true }
1919
panic_abort = { path = "../panic_abort" }
2020
core = { path = "../core", public = true }
21-
compiler_builtins = { path = "../compiler-builtins/compiler-builtins" }
2221
unwind = { path = "../unwind" }
2322
hashbrown = { version = "0.15", default-features = false, features = [
2423
'rustc-dep-of-std',

library/std/src/sys/pal/uefi/helpers.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -444,17 +444,17 @@ impl<'a> DevicePathNode<'a> {
444444

445445
impl<'a> PartialEq for DevicePathNode<'a> {
446446
fn eq(&self, other: &Self) -> bool {
447-
let self_len = self.length();
448-
let other_len = other.length();
449-
450-
self_len == other_len
451-
&& unsafe {
452-
compiler_builtins::mem::memcmp(
453-
self.protocol.as_ptr().cast(),
454-
other.protocol.as_ptr().cast(),
455-
usize::from(self_len),
456-
) == 0
457-
}
447+
// Compare as a single buffer rather than by field since it optimizes better.
448+
//
449+
// SAFETY: `Protocol` is followed by a buffer of `length - sizeof::<Protocol>()`. `Protocol`
450+
// has no padding so it is sound to interpret as a slice.
451+
unsafe {
452+
let s1 =
453+
slice::from_raw_parts(self.protocol.as_ptr().cast::<u8>(), self.length().into());
454+
let s2 =
455+
slice::from_raw_parts(other.protocol.as_ptr().cast::<u8>(), other.length().into());
456+
s1 == s2
457+
}
458458
}
459459
}
460460

library/unwind/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ bench = false
1414
doc = false
1515

1616
[dependencies]
17-
core = { path = "../core" }
18-
compiler_builtins = { path = "../compiler-builtins/compiler-builtins" }
1917
cfg-if = "1.0"
18+
core = { path = "../rustc-std-workspace-core", package = "rustc-std-workspace-core" }
2019

2120
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
2221
libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false }

0 commit comments

Comments
 (0)