diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5bbe69c8d65dc..38ec8b40e6c73 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2867,6 +2867,44 @@ enum AsmLabelKind { Binary, } +/// Checks if a potential label is actually a Hexagon register span notation. +/// +/// Hexagon assembly uses register span notation like `r1:0`, `V5:4.w`, `p1:0` etc. +/// These follow the pattern: `[letter][digit(s)]:[digit(s)][optional_suffix]` +/// +/// Returns `true` if the string matches a valid Hexagon register span pattern. +fn is_hexagon_register_span(possible_label: &str) -> bool { + if possible_label.len() < 3 { + return false; + } + + let mut chars = possible_label.chars(); + let start = chars.next().unwrap(); + + // Must start with a letter (r, V, p, etc.) + if !start.is_ascii_alphabetic() { + return false; + } + + let rest = &possible_label[1..]; + let Some(colon_idx) = rest.find(':') else { + return false; + }; + + let (before_colon, after_colon_with_colon) = rest.split_at(colon_idx); + let after_colon = &after_colon_with_colon[1..]; // Skip the ':' + + // Check if before colon is all digits and non-empty + if before_colon.is_empty() || !before_colon.chars().all(|c| c.is_ascii_digit()) { + return false; + } + + // Check if after colon starts with digits (may have suffix like .w, .h) + let digits_after = after_colon.chars().take_while(|c| c.is_ascii_digit()).collect::(); + + !digits_after.is_empty() +} + impl<'tcx> LateLintPass<'tcx> for AsmLabels { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::Expr { @@ -2940,6 +2978,14 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels { break 'label_loop; } + // Check for Hexagon register span notation (e.g., "r1:0", "V5:4", "V3:2.w") + // This is valid Hexagon assembly syntax, not a label + if matches!(cx.tcx.sess.asm_arch, Some(InlineAsmArch::Hexagon)) + && is_hexagon_register_span(possible_label) + { + break 'label_loop; + } + for c in chars { // Inside a template format arg, any character is permitted for the // puproses of label detection because we assume that it can be diff --git a/tests/ui/asm/hexagon-register-pairs.rs b/tests/ui/asm/hexagon-register-pairs.rs new file mode 100644 index 0000000000000..a1d7148318cbe --- /dev/null +++ b/tests/ui/asm/hexagon-register-pairs.rs @@ -0,0 +1,36 @@ +//@ add-core-stubs +//@ compile-flags: --target hexagon-unknown-linux-musl +//@ needs-llvm-components: hexagon + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +fn test_register_spans() { + unsafe { + // These are valid Hexagon register span notations, not labels + // Should NOT trigger the named labels lint + + // General register pairs + asm!("r1:0 = memd(r29+#0)", lateout("r0") _, lateout("r1") _); + asm!("r3:2 = combine(#1, #0)", lateout("r2") _, lateout("r3") _); + asm!("r15:14 = memd(r30+#8)", lateout("r14") _, lateout("r15") _); + asm!("memd(r29+#0) = r5:4", in("r4") 0u32, in("r5") 0u32); + + // Vector register pairs (hypothetical since we can't actually use them without HVX) + asm!("nop // V5:4 = vadd(V3:2, V1:0)"); // Comment form to avoid actual instruction issues + asm!("nop // V7:6.w = vadd(V5:4.w, V3:2.w)"); // With type suffixes + + // Predicate register pairs + asm!("nop // p1:0 = vcmpb.eq(V1:0, V3:2)"); // Comment form + + // Mixed with actual labels should still trigger for the labels + asm!("label1: r7:6 = combine(#2, #3)"); //~ ERROR avoid using named labels + + // Regular labels should still trigger + asm!("hexagon_label: nop"); //~ ERROR avoid using named labels + } +}