Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2875,6 +2875,71 @@ 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.
pub fn is_hexagon_register_span(possible_label: &str) -> bool {
// Extract the full register span from the context
if let Some(colon_idx) = possible_label.find(':') {
let after_colon = &possible_label[colon_idx + 1..];
is_hexagon_register_span_impl(&possible_label[..colon_idx], after_colon)
} else {
false
}
}

/// Helper function for use within the lint when we have statement context.
fn is_hexagon_register_span_context(
possible_label: &str,
statement: &str,
colon_idx: usize,
) -> bool {
// Extract what comes after the colon in the statement
let after_colon_start = colon_idx + 1;
if after_colon_start >= statement.len() {
return false;
}

// Get the part after the colon, up to the next whitespace or special character
let after_colon_full = &statement[after_colon_start..];
let after_colon = after_colon_full
.chars()
.take_while(|&c| c.is_ascii_alphanumeric() || c == '.')
.collect::<String>();

is_hexagon_register_span_impl(possible_label, &after_colon)
}

/// Core implementation for checking hexagon register spans.
fn is_hexagon_register_span_impl(before_colon: &str, after_colon: &str) -> bool {
if before_colon.len() < 1 || after_colon.is_empty() {
return false;
}

let mut chars = before_colon.chars();
let start = chars.next().unwrap();

// Must start with a letter (r, V, p, etc.)
if !start.is_ascii_alphabetic() {
return false;
}

let rest = &before_colon[1..];

// Check if the part after the first letter is all digits and non-empty
if rest.is_empty() || !rest.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::<String>();

!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 {
Expand Down Expand Up @@ -2957,6 +3022,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_context(possible_label, statement, idx)
{
break 'label_loop;
}

for c in chars {
// Inside a template format arg, any character is permitted for the
// purposes of label detection because we assume that it can be
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_lint/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use rustc_span::{Symbol, create_default_session_globals_then};

use crate::builtin::is_hexagon_register_span;
use crate::levels::parse_lint_and_tool_name;

#[test]
Expand All @@ -27,3 +28,29 @@ fn parse_lint_multiple_path() {
)
});
}

#[test]
fn test_hexagon_register_span_patterns() {
// Valid Hexagon register span patterns
assert!(is_hexagon_register_span("r1:0"));
assert!(is_hexagon_register_span("r15:14"));
assert!(is_hexagon_register_span("V5:4"));
assert!(is_hexagon_register_span("V3:2"));
assert!(is_hexagon_register_span("V5:4.w"));
assert!(is_hexagon_register_span("V3:2.h"));
assert!(is_hexagon_register_span("r99:98"));
assert!(is_hexagon_register_span("V123:122.whatever"));

// Invalid patterns - these should be treated as potential labels
assert!(!is_hexagon_register_span("label1"));
assert!(!is_hexagon_register_span("foo:"));
assert!(!is_hexagon_register_span(":0"));
assert!(!is_hexagon_register_span("r:0")); // missing digits before colon
assert!(!is_hexagon_register_span("r1:")); // missing digits after colon
assert!(!is_hexagon_register_span("r1:a")); // non-digit after colon
assert!(!is_hexagon_register_span("1:0")); // starts with digit, not letter
assert!(!is_hexagon_register_span("r1")); // no colon
assert!(!is_hexagon_register_span("r")); // too short
assert!(!is_hexagon_register_span("")); // empty
assert!(!is_hexagon_register_span("ra:0")); // letter in first digit group
}
37 changes: 37 additions & 0 deletions tests/ui/asm/hexagon-register-pairs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//@ add-minicore
//@ compile-flags: --target hexagon-unknown-linux-musl -C target-feature=+hvx-length128b
//@ needs-llvm-components: hexagon
//@ ignore-backends: gcc

#![feature(no_core, asm_experimental_arch)]
#![crate_type = "lib"]
#![no_core]

//~? WARN unstable feature specified for `-Ctarget-feature`: `hvx-length128b`

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);

// These patterns look like register spans but test different edge cases
// All should NOT trigger the lint as they match valid hexagon register syntax patterns
asm!("V5:4 = vaddw(v1:0, v1:0)", options(nostack)); // Uppercase V register pair
asm!("v1:0.w = vsub(v1:0.w,v1:0.w):sat", options(nostack)); // Lowercase v with suffix

// 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
}
}
25 changes: 25 additions & 0 deletions tests/ui/asm/hexagon-register-pairs.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
warning: unstable feature specified for `-Ctarget-feature`: `hvx-length128b`
|
= note: this feature is not stably supported; its behavior can change in the future

error: avoid using named labels in inline assembly
--> $DIR/hexagon-register-pairs.rs:32:15
|
LL | asm!("label1: r7:6 = combine(#2, #3)");
| ^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
= note: `#[deny(named_asm_labels)]` on by default

error: avoid using named labels in inline assembly
--> $DIR/hexagon-register-pairs.rs:35:15
|
LL | asm!("hexagon_label: nop");
| ^^^^^^^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information

error: aborting due to 2 previous errors; 1 warning emitted

Loading