Skip to content

Commit 6b0a5c0

Browse files
authored
Rollup merge of rust-lang#143037 - androm3da:bcain/hexagon_regspan_label, r=Amanieu
Make named asm_labels lint not trigger on hexagon register spans Fixes rust-lang#143021
2 parents cb8a5cc + 7cc7480 commit 6b0a5c0

File tree

4 files changed

+156
-0
lines changed

4 files changed

+156
-0
lines changed

compiler/rustc_lint/src/builtin.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2875,6 +2875,71 @@ enum AsmLabelKind {
28752875
Binary,
28762876
}
28772877

2878+
/// Checks if a potential label is actually a Hexagon register span notation.
2879+
///
2880+
/// Hexagon assembly uses register span notation like `r1:0`, `V5:4.w`, `p1:0` etc.
2881+
/// These follow the pattern: `[letter][digit(s)]:[digit(s)][optional_suffix]`
2882+
///
2883+
/// Returns `true` if the string matches a valid Hexagon register span pattern.
2884+
pub fn is_hexagon_register_span(possible_label: &str) -> bool {
2885+
// Extract the full register span from the context
2886+
if let Some(colon_idx) = possible_label.find(':') {
2887+
let after_colon = &possible_label[colon_idx + 1..];
2888+
is_hexagon_register_span_impl(&possible_label[..colon_idx], after_colon)
2889+
} else {
2890+
false
2891+
}
2892+
}
2893+
2894+
/// Helper function for use within the lint when we have statement context.
2895+
fn is_hexagon_register_span_context(
2896+
possible_label: &str,
2897+
statement: &str,
2898+
colon_idx: usize,
2899+
) -> bool {
2900+
// Extract what comes after the colon in the statement
2901+
let after_colon_start = colon_idx + 1;
2902+
if after_colon_start >= statement.len() {
2903+
return false;
2904+
}
2905+
2906+
// Get the part after the colon, up to the next whitespace or special character
2907+
let after_colon_full = &statement[after_colon_start..];
2908+
let after_colon = after_colon_full
2909+
.chars()
2910+
.take_while(|&c| c.is_ascii_alphanumeric() || c == '.')
2911+
.collect::<String>();
2912+
2913+
is_hexagon_register_span_impl(possible_label, &after_colon)
2914+
}
2915+
2916+
/// Core implementation for checking hexagon register spans.
2917+
fn is_hexagon_register_span_impl(before_colon: &str, after_colon: &str) -> bool {
2918+
if before_colon.len() < 1 || after_colon.is_empty() {
2919+
return false;
2920+
}
2921+
2922+
let mut chars = before_colon.chars();
2923+
let start = chars.next().unwrap();
2924+
2925+
// Must start with a letter (r, V, p, etc.)
2926+
if !start.is_ascii_alphabetic() {
2927+
return false;
2928+
}
2929+
2930+
let rest = &before_colon[1..];
2931+
2932+
// Check if the part after the first letter is all digits and non-empty
2933+
if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_digit()) {
2934+
return false;
2935+
}
2936+
2937+
// Check if after colon starts with digits (may have suffix like .w, .h)
2938+
let digits_after = after_colon.chars().take_while(|c| c.is_ascii_digit()).collect::<String>();
2939+
2940+
!digits_after.is_empty()
2941+
}
2942+
28782943
impl<'tcx> LateLintPass<'tcx> for AsmLabels {
28792944
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
28802945
if let hir::Expr {
@@ -2957,6 +3022,14 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels {
29573022
break 'label_loop;
29583023
}
29593024

3025+
// Check for Hexagon register span notation (e.g., "r1:0", "V5:4", "V3:2.w")
3026+
// This is valid Hexagon assembly syntax, not a label
3027+
if matches!(cx.tcx.sess.asm_arch, Some(InlineAsmArch::Hexagon))
3028+
&& is_hexagon_register_span_context(possible_label, statement, idx)
3029+
{
3030+
break 'label_loop;
3031+
}
3032+
29603033
for c in chars {
29613034
// Inside a template format arg, any character is permitted for the
29623035
// purposes of label detection because we assume that it can be

compiler/rustc_lint/src/tests.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use rustc_span::{Symbol, create_default_session_globals_then};
44

5+
use crate::builtin::is_hexagon_register_span;
56
use crate::levels::parse_lint_and_tool_name;
67

78
#[test]
@@ -27,3 +28,29 @@ fn parse_lint_multiple_path() {
2728
)
2829
});
2930
}
31+
32+
#[test]
33+
fn test_hexagon_register_span_patterns() {
34+
// Valid Hexagon register span patterns
35+
assert!(is_hexagon_register_span("r1:0"));
36+
assert!(is_hexagon_register_span("r15:14"));
37+
assert!(is_hexagon_register_span("V5:4"));
38+
assert!(is_hexagon_register_span("V3:2"));
39+
assert!(is_hexagon_register_span("V5:4.w"));
40+
assert!(is_hexagon_register_span("V3:2.h"));
41+
assert!(is_hexagon_register_span("r99:98"));
42+
assert!(is_hexagon_register_span("V123:122.whatever"));
43+
44+
// Invalid patterns - these should be treated as potential labels
45+
assert!(!is_hexagon_register_span("label1"));
46+
assert!(!is_hexagon_register_span("foo:"));
47+
assert!(!is_hexagon_register_span(":0"));
48+
assert!(!is_hexagon_register_span("r:0")); // missing digits before colon
49+
assert!(!is_hexagon_register_span("r1:")); // missing digits after colon
50+
assert!(!is_hexagon_register_span("r1:a")); // non-digit after colon
51+
assert!(!is_hexagon_register_span("1:0")); // starts with digit, not letter
52+
assert!(!is_hexagon_register_span("r1")); // no colon
53+
assert!(!is_hexagon_register_span("r")); // too short
54+
assert!(!is_hexagon_register_span("")); // empty
55+
assert!(!is_hexagon_register_span("ra:0")); // letter in first digit group
56+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//@ add-core-stubs
2+
//@ compile-flags: --target hexagon-unknown-linux-musl -C target-feature=+hvx-length128b
3+
//@ needs-llvm-components: hexagon
4+
//@ ignore-backends: gcc
5+
6+
#![feature(no_core, asm_experimental_arch)]
7+
#![crate_type = "lib"]
8+
#![no_core]
9+
10+
extern crate minicore;
11+
use minicore::*;
12+
13+
fn test_register_spans() {
14+
unsafe {
15+
// These are valid Hexagon register span notations, not labels
16+
// Should NOT trigger the named labels lint
17+
18+
// General register pairs
19+
asm!("r1:0 = memd(r29+#0)", lateout("r0") _, lateout("r1") _);
20+
asm!("r3:2 = combine(#1, #0)", lateout("r2") _, lateout("r3") _);
21+
asm!("r15:14 = memd(r30+#8)", lateout("r14") _, lateout("r15") _);
22+
asm!("memd(r29+#0) = r5:4", in("r4") 0u32, in("r5") 0u32);
23+
24+
// These patterns look like register spans but test different edge cases
25+
// All should NOT trigger the lint as they match valid hexagon register syntax patterns
26+
asm!("V5:4 = vaddw(v1:0, v1:0)", options(nostack)); // Uppercase V register pair
27+
asm!("v1:0.w = vsub(v1:0.w,v1:0.w):sat", options(nostack)); // Lowercase v with suffix
28+
29+
// Mixed with actual labels should still trigger for the labels
30+
asm!("label1: r7:6 = combine(#2, #3)"); //~ ERROR avoid using named labels
31+
32+
// Regular labels should still trigger
33+
asm!("hexagon_label: nop"); //~ ERROR avoid using named labels
34+
}
35+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error: avoid using named labels in inline assembly
2+
--> $DIR/hexagon-register-pairs.rs:30:15
3+
|
4+
LL | asm!("label1: r7:6 = combine(#2, #3)");
5+
| ^^^^^^
6+
|
7+
= help: only local labels of the form `<number>:` should be used in inline asm
8+
= 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
9+
= note: `#[deny(named_asm_labels)]` on by default
10+
11+
error: avoid using named labels in inline assembly
12+
--> $DIR/hexagon-register-pairs.rs:33:15
13+
|
14+
LL | asm!("hexagon_label: nop");
15+
| ^^^^^^^^^^^^^
16+
|
17+
= help: only local labels of the form `<number>:` should be used in inline asm
18+
= 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
19+
20+
error: aborting due to 2 previous errors
21+

0 commit comments

Comments
 (0)