about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_codegen_llvm/diagnostics.rs11
-rw-r--r--src/librustc_codegen_llvm/mir/statement.rs28
-rw-r--r--src/test/ui/inline-asm-bad-operand.rs57
-rw-r--r--src/test/ui/inline-asm-bad-operand.stderr33
4 files changed, 122 insertions, 7 deletions
diff --git a/src/librustc_codegen_llvm/diagnostics.rs b/src/librustc_codegen_llvm/diagnostics.rs
index 242b7a1a119..5721938c9c0 100644
--- a/src/librustc_codegen_llvm/diagnostics.rs
+++ b/src/librustc_codegen_llvm/diagnostics.rs
@@ -69,4 +69,15 @@ fn main() {
 ```
 "##,
 
+E0669: r##"
+Cannot convert inline assembly operand to a single LLVM value.
+
+This error usually happens when trying to pass in a value to an input inline
+assembly operand that is actually a pair of values. In particular, this can
+happen when trying to pass in a slice, for instance a `&str`. In Rust, these
+values are represented internally as a pair of values, the pointer and its
+length. When passed as an input operand, this pair of values can not be
+coerced into a register and thus we must fail with an error.
+"##,
+
 }
diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs
index 6bd41bfe16f..93be0074f6e 100644
--- a/src/librustc_codegen_llvm/mir/statement.rs
+++ b/src/librustc_codegen_llvm/mir/statement.rs
@@ -15,6 +15,7 @@ use builder::Builder;
 
 use super::FunctionCx;
 use super::LocalRef;
+use super::OperandValue;
 
 impl FunctionCx<'a, 'll, 'tcx> {
     pub fn codegen_statement(&mut self,
@@ -82,14 +83,27 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     self.codegen_place(&bx, output)
                 }).collect();
 
-                let input_vals = inputs.iter().map(|input| {
-                    self.codegen_operand(&bx, input).immediate()
-                }).collect();
+                let input_vals = inputs.iter()
+                    .try_fold(Vec::with_capacity(inputs.len()), |mut acc, input| {
+                        let op = self.codegen_operand(&bx, input);
+                        if let OperandValue::Immediate(_) = op.val {
+                            acc.push(op.immediate());
+                            Ok(acc)
+                        } else {
+                            Err(op)
+                        }
+                });
 
-                let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
-                if !res {
-                    span_err!(bx.sess(), statement.source_info.span, E0668,
-                              "malformed inline assembly");
+                if input_vals.is_err() {
+                   span_err!(bx.sess(), statement.source_info.span, E0669,
+                             "invalid value for constraint in inline assembly");
+                } else {
+                    let input_vals = input_vals.unwrap();
+                    let res = asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
+                    if !res {
+                        span_err!(bx.sess(), statement.source_info.span, E0668,
+                                  "malformed inline assembly");
+                    }
                 }
                 bx
             }
diff --git a/src/test/ui/inline-asm-bad-operand.rs b/src/test/ui/inline-asm-bad-operand.rs
new file mode 100644
index 00000000000..37021f38cac
--- /dev/null
+++ b/src/test/ui/inline-asm-bad-operand.rs
@@ -0,0 +1,57 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the compiler will catch passing invalid values to inline assembly
+// operands.
+
+#![feature(asm)]
+
+#[repr(C)]
+struct MyPtr(usize);
+
+fn main() {
+    issue_37433();
+    issue_37437();
+    issue_40187();
+    issue_54067();
+}
+
+fn issue_37433() {
+    unsafe {
+        asm!("" :: "r"("")); //~ ERROR E0669
+    }
+
+    unsafe {
+        let target = MyPtr(0);
+        asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
+    }
+}
+
+fn issue_37437() {
+    let hello: &str = "hello";
+    // this should fail...
+    unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
+    // but this should succeed.
+    unsafe { asm!("" :: "r"(hello.as_ptr())) };
+}
+
+fn issue_40187() {
+    let arr: [u8; 1] = [0; 1];
+    unsafe {
+        asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
+    }
+}
+
+fn issue_54067() {
+    let addr: Option<u32> = Some(123);
+    unsafe {
+        asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
+    }
+}
diff --git a/src/test/ui/inline-asm-bad-operand.stderr b/src/test/ui/inline-asm-bad-operand.stderr
new file mode 100644
index 00000000000..6971215a95f
--- /dev/null
+++ b/src/test/ui/inline-asm-bad-operand.stderr
@@ -0,0 +1,33 @@
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:28:9
+   |
+LL |         asm!("" :: "r"("")); //~ ERROR E0669
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:33:9
+   |
+LL |         asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:40:14
+   |
+LL |     unsafe { asm!("" :: "i"(hello)) }; //~ ERROR E0669
+   |              ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:48:9
+   |
+LL |         asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0669]: invalid value for constraint in inline assembly
+  --> $DIR/inline-asm-bad-operand.rs:55:9
+   |
+LL |         asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0669`.