summaryrefslogtreecommitdiffstats
path: root/src/test/ui/asm/named-asm-labels.rs
blob: 160dbf617c4f6ade89881b7f04c7edd352f0e45b (plain)
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
// needs-asm-support
// ignore-nvptx64
// ignore-spirv
// ignore-wasm32

// 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, asm_const)]

use std::arch::{asm, global_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

        // Multiple lines
        asm!("foo1: nop", "nop"); //~ ERROR avoid using named labels
        asm!("foo2: foo3: nop", "nop");
        //~^ 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
        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
        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

        // Raw strings
        asm!(
            r"
            blah2: nop
            blah3: nop
            "
        );
        //~^^^^ 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
        asm!("def: nop\ndef: nop"); //~ ERROR avoid using named labels
        asm!("def: nop; def: nop"); //~ 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");

        // Test include_str in asm
        asm!(include_str!("named-asm-labels.s")); //~ 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 { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noreturn)) } //~ 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 { asm!(".Laaa: nop; ret;", options(noreturn)) } //~ ERROR avoid using named labels
}

pub fn normal() {
    fn _local1() {}

    #[naked]
    pub extern "C" fn bbb() {
        fn _very_local() {}

        unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) } //~ 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() {
            asm!("ret;", options(noreturn));
        }

        unsafe {
            asm!("closure3: nop"); //~ ERROR avoid using named labels
        }
    };
}

// Don't trigger on global asm
global_asm!("aaaaaaaa: nop");