1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
|
//@ needs-asm-support
//@ ignore-nvptx64
//@ ignore-spirv
// Tests that the use of named labels in the `asm!` macro are linted against
// except for in `#[naked]` fns.
// Using a named label is incorrect as per the RFC because for most cases
// the compiler cannot ensure that inline asm is emitted exactly once per
// codegen unit (except for naked fns) and so the label could be duplicated
// which causes less readable LLVM errors and in the worst cases causes ICEs
// or segfaults based on system dependent behavior and codegen flags.
#![feature(naked_functions)]
use std::arch::{asm, global_asm, naked_asm};
#[no_mangle]
pub static FOO: usize = 42;
fn main() {
unsafe {
// Basic usage
asm!("bar: nop"); //~ ERROR avoid using named labels
// No following asm
asm!("abcd:"); //~ ERROR avoid using named labels
// Multiple labels on one line
asm!("foo: bar1: nop");
//~^ ERROR avoid using named labels
//~^^ ERROR avoid using named labels
// Multiple lines
asm!("foo1: nop", "nop"); //~ ERROR avoid using named labels
asm!("foo2: foo3: nop", "nop");
//~^ ERROR avoid using named labels
//~^^ ERROR avoid using named labels
asm!("nop", "foo4: nop"); //~ ERROR avoid using named labels
asm!("foo5: nop", "foo6: nop");
//~^ ERROR avoid using named labels
//~| ERROR avoid using named labels
// Statement separator
asm!("foo7: nop; foo8: nop");
//~^ ERROR avoid using named labels
//~^^ ERROR avoid using named labels
asm!("foo9: nop; nop"); //~ ERROR avoid using named labels
asm!("nop; foo10: nop"); //~ ERROR avoid using named labels
// Escaped newline
asm!("bar2: nop\n bar3: nop");
//~^ ERROR avoid using named labels
//~^^ ERROR avoid using named labels
asm!("bar4: nop\n nop"); //~ ERROR avoid using named labels
asm!("nop\n bar5: nop"); //~ ERROR avoid using named labels
asm!("nop\n bar6: bar7: nop");
//~^ ERROR avoid using named labels
//~^^ ERROR avoid using named labels
// Raw strings
asm!(
r"
blah2: nop
blah3: nop
"
);
//~^^^^ ERROR avoid using named labels
//~^^^^ ERROR avoid using named labels
asm!(
r###"
nop
nop ; blah4: nop
"###
);
//~^^^ ERROR avoid using named labels
// Non-labels
// should not trigger lint, but may be invalid asm
asm!("ab cd: nop");
// `blah:` does not trigger because labels need to be at the start
// of the statement, and there was already a non-label
asm!("1bar: blah: nop");
// Only `blah1:` should trigger
asm!("blah1: 2bar: nop"); //~ ERROR avoid using named labels
// Duplicate labels
asm!("def: def: nop");
//~^ ERROR avoid using named labels
//~^^ ERROR avoid using named labels
asm!("def: nop\ndef: nop");
//~^ ERROR avoid using named labels
//~^^ ERROR avoid using named labels
asm!("def: nop; def: nop");
//~^ ERROR avoid using named labels
//~^^ ERROR avoid using named labels
// Trying to break parsing
asm!(":");
asm!("\n:\n");
asm!("::::");
// 0x3A is a ':'
asm!("fooo\u{003A} nop"); //~ ERROR avoid using named labels
asm!("foooo\x3A nop"); //~ ERROR avoid using named labels
// 0x0A is a newline
asm!("fooooo:\u{000A} nop"); //~ ERROR avoid using named labels
asm!("foooooo:\x0A nop"); //~ ERROR avoid using named labels
// Intentionally breaking span finding
// equivalent to "ABC: nop"
asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); //~ ERROR avoid using named labels
// Non-label colons - should pass
asm!("mov rax, qword ptr fs:[0]");
// Comments
asm!(
r"
ab: nop // ab: does foo
// cd: nop
"
);
//~^^^^ ERROR avoid using named labels
// Tests usage of colons in non-label positions
asm!(":lo12:FOO"); // this is apparently valid aarch64
// is there an example that is valid x86 for this test?
asm!(":bbb nop");
// non-ascii characters are not allowed in labels, so should not trigger the lint
asm!("Ù: nop");
asm!("testÙ: nop");
asm!("_Ù_: nop");
// Format arguments should be conservatively assumed to be valid characters in labels
// Would emit `test_rax:` or similar
#[allow(asm_sub_register)]
{
asm!("test_{}: nop", in(reg) 10); //~ ERROR avoid using named labels
}
asm!("test_{}: nop", const 10); //~ ERROR avoid using named labels
asm!("test_{}: nop", sym main); //~ ERROR avoid using named labels
asm!("{}_test: nop", const 10); //~ ERROR avoid using named labels
asm!("test_{}_test: nop", const 10); //~ ERROR avoid using named labels
asm!("{}: nop", const 10); //~ ERROR avoid using named labels
asm!("{uwu}: nop", uwu = const 10); //~ ERROR avoid using named labels
asm!("{0}: nop", const 10); //~ ERROR avoid using named labels
asm!("{1}: nop", "/* {0} */", const 10, const 20); //~ ERROR avoid using named labels
// Test include_str in asm
asm!(include_str!("named-asm-labels.s"));
//~^ ERROR avoid using named labels
//~^^ ERROR avoid using named labels
//~^^^ ERROR avoid using named labels
//~^^^^ ERROR avoid using named labels
// Test allowing or warning on the lint instead
#[allow(named_asm_labels)]
{
asm!("allowed: nop"); // Should not emit anything
}
#[warn(named_asm_labels)]
{
asm!("warned: nop"); //~ WARNING avoid using named labels
}
}
}
// Trigger on naked fns too, even though they can't be inlined, reusing a
// label or LTO can cause labels to break
#[naked]
pub extern "C" fn foo() -> i32 {
unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) }
//~^ ERROR avoid using named labels
}
// Make sure that non-naked attributes *do* still let the lint happen
#[no_mangle]
pub extern "C" fn bar() {
unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) }
//~^ ERROR avoid using named labels
}
#[naked]
pub extern "C" fn aaa() {
fn _local() {}
unsafe { naked_asm!(".Laaa: nop; ret;") } //~ ERROR avoid using named labels
}
pub fn normal() {
fn _local1() {}
#[naked]
pub extern "C" fn bbb() {
fn _very_local() {}
unsafe { naked_asm!(".Lbbb: nop; ret;") } //~ ERROR avoid using named labels
}
fn _local2() {}
}
// Make sure that the lint happens within closures
fn closures() {
|| unsafe {
asm!("closure1: nop"); //~ ERROR avoid using named labels
};
move || unsafe {
asm!("closure2: nop"); //~ ERROR avoid using named labels
};
|| {
#[naked]
unsafe extern "C" fn _nested() {
naked_asm!("ret;");
}
unsafe {
asm!("closure3: nop"); //~ ERROR avoid using named labels
}
};
}
// Don't trigger on global asm
global_asm!("aaaaaaaa: nop");
|