Skip to content

Commit f42c510

Browse files
committed
Auto merge of #54747 - levex:inline-asm-bad-operands, r=nagisa
codegen_llvm: verify that inline assembly operands are scalars Another set of inline assembly fixes. This time let's emit an error message when the operand value cannot be coerced into the operand constraint. Two questions: 1) Should I reuse `E0668` which was introduced in #54568 or just use `E0669` as it stands because they do mean different things, but maybe that's not too user-friendly. Just a thought. 2) The `try_fold` returns the operand which failed to be converted into a scalar value, any suggestions on how to use that in the error message? Thanks!
2 parents 5af0bb8 + 3d7476e commit f42c510

File tree

4 files changed

+122
-7
lines changed

4 files changed

+122
-7
lines changed

src/librustc_codegen_llvm/diagnostics.rs

+11
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,15 @@ fn main() {
6969
```
7070
"##,
7171

72+
E0669: r##"
73+
Cannot convert inline assembly operand to a single LLVM value.
74+
75+
This error usually happens when trying to pass in a value to an input inline
76+
assembly operand that is actually a pair of values. In particular, this can
77+
happen when trying to pass in a slice, for instance a `&str`. In Rust, these
78+
values are represented internally as a pair of values, the pointer and its
79+
length. When passed as an input operand, this pair of values can not be
80+
coerced into a register and thus we must fail with an error.
81+
"##,
82+
7283
}

src/librustc_codegen_llvm/mir/statement.rs

+21-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use builder::Builder;
1515

1616
use super::FunctionCx;
1717
use super::LocalRef;
18+
use super::OperandValue;
1819

1920
impl FunctionCx<'a, 'll, 'tcx> {
2021
pub fn codegen_statement(&mut self,
@@ -82,14 +83,27 @@ impl FunctionCx<'a, 'll, 'tcx> {
8283
self.codegen_place(&bx, output)
8384
}).collect();
8485

85-
let input_vals = inputs.iter().map(|input| {
86-
self.codegen_operand(&bx, input).immediate()
87-
}).collect();
86+
let input_vals = inputs.iter()
87+
.try_fold(Vec::with_capacity(inputs.len()), |mut acc, input| {
88+
let op = self.codegen_operand(&bx, input);
89+
if let OperandValue::Immediate(_) = op.val {
90+
acc.push(op.immediate());
91+
Ok(acc)
92+
} else {
93+
Err(op)
94+
}
95+
});
8896

89-
let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
90-
if !res {
91-
span_err!(bx.sess(), statement.source_info.span, E0668,
92-
"malformed inline assembly");
97+
if input_vals.is_err() {
98+
span_err!(bx.sess(), statement.source_info.span, E0669,
99+
"invalid value for constraint in inline assembly");
100+
} else {
101+
let input_vals = input_vals.unwrap();
102+
let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
103+
if !res {
104+
span_err!(bx.sess(), statement.source_info.span, E0668,
105+
"malformed inline assembly");
106+
}
93107
}
94108
bx
95109
}

src/test/ui/inline-asm-bad-operand.rs

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that the compiler will catch passing invalid values to inline assembly
12+
// operands.
13+
14+
#![feature(asm)]
15+
16+
#[repr(C)]
17+
struct MyPtr(usize);
18+
19+
fn main() {
20+
issue_37433();
21+
issue_37437();
22+
issue_40187();
23+
issue_54067();
24+
}
25+
26+
fn issue_37433() {
27+
unsafe {
28+
asm!("" :: "r"("")); //~ ERROR E0669
29+
}
30+
31+
unsafe {
32+
let target = MyPtr(0);
33+
asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
34+
}
35+
}
36+
37+
fn issue_37437() {
38+
let hello: &str = "hello";
39+
// this should fail...
40+
unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
41+
// but this should succeed.
42+
unsafe { asm!("" :: "r"(hello.as_ptr())) };
43+
}
44+
45+
fn issue_40187() {
46+
let arr: [u8; 1] = [0; 1];
47+
unsafe {
48+
asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
49+
}
50+
}
51+
52+
fn issue_54067() {
53+
let addr: Option<u32> = Some(123);
54+
unsafe {
55+
asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
56+
}
57+
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0669]: invalid value for constraint in inline assembly
2+
--> $DIR/inline-asm-bad-operand.rs:28:9
3+
|
4+
LL | asm!("" :: "r"("")); //~ ERROR E0669
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
7+
error[E0669]: invalid value for constraint in inline assembly
8+
--> $DIR/inline-asm-bad-operand.rs:33:9
9+
|
10+
LL | asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error[E0669]: invalid value for constraint in inline assembly
14+
--> $DIR/inline-asm-bad-operand.rs:40:14
15+
|
16+
LL | unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
17+
| ^^^^^^^^^^^^^^^^^^^^^^
18+
19+
error[E0669]: invalid value for constraint in inline assembly
20+
--> $DIR/inline-asm-bad-operand.rs:48:9
21+
|
22+
LL | asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
25+
error[E0669]: invalid value for constraint in inline assembly
26+
--> $DIR/inline-asm-bad-operand.rs:55:9
27+
|
28+
LL | asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
31+
error: aborting due to 5 previous errors
32+
33+
For more information about this error, try `rustc --explain E0669`.

0 commit comments

Comments
 (0)