about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_codegen_llvm/asm.rs8
-rw-r--r--src/librustc_codegen_llvm/builder.rs16
-rw-r--r--src/librustc_codegen_llvm/diagnostics.rs22
-rw-r--r--src/librustc_codegen_llvm/llvm/ffi.rs3
-rw-r--r--src/librustc_codegen_llvm/mir/statement.rs6
-rw-r--r--src/rustllvm/RustWrapper.cpp5
-rw-r--r--src/test/ui/inline-asm-bad-constraint.rs47
-rw-r--r--src/test/ui/inline-asm-bad-constraint.stderr21
8 files changed, 122 insertions, 6 deletions
diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs
index 5d27f8eab3e..f1bb41bceba 100644
--- a/src/librustc_codegen_llvm/asm.rs
+++ b/src/librustc_codegen_llvm/asm.rs
@@ -30,7 +30,7 @@ pub fn codegen_inline_asm(
     ia: &hir::InlineAsm,
     outputs: Vec<PlaceRef<'ll, 'tcx>>,
     mut inputs: Vec<&'ll Value>
-) {
+) -> bool {
     let mut ext_constraints = vec![];
     let mut output_types = vec![];
 
@@ -97,6 +97,10 @@ pub fn codegen_inline_asm(
         ia.alignstack,
         dialect
     );
+    if r.is_none() {
+        return false;
+    }
+    let r = r.unwrap();
 
     // Again, based on how many outputs we have
     let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
@@ -117,6 +121,8 @@ pub fn codegen_inline_asm(
         llvm::LLVMSetMetadata(r, kind,
             llvm::LLVMMDNodeInContext(bx.cx.llcx, &val, 1));
     }
+
+    return true;
 }
 
 pub fn codegen_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index e3526a5a2ee..77de88997e4 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -737,7 +737,7 @@ impl Builder<'a, 'll, 'tcx> {
     pub fn inline_asm_call(&self, asm: *const c_char, cons: *const c_char,
                          inputs: &[&'ll Value], output: &'ll Type,
                          volatile: bool, alignstack: bool,
-                         dia: AsmDialect) -> &'ll Value {
+                         dia: AsmDialect) -> Option<&'ll Value> {
         self.count_insn("inlineasm");
 
         let volatile = if volatile { llvm::True }
@@ -753,9 +753,17 @@ impl Builder<'a, 'll, 'tcx> {
         debug!("Asm Output Type: {:?}", output);
         let fty = Type::func(&argtys[..], output);
         unsafe {
-            let v = llvm::LLVMRustInlineAsm(
-                fty, asm, cons, volatile, alignstack, dia);
-            self.call(v, inputs, None)
+            // Ask LLVM to verify that the constraints are well-formed.
+            let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons);
+            debug!("Constraint verification result: {:?}", constraints_ok);
+            if constraints_ok == llvm::True {
+                let v = llvm::LLVMRustInlineAsm(
+                    fty, asm, cons, volatile, alignstack, dia);
+                Some(self.call(v, inputs, None))
+            } else {
+                // LLVM has detected an issue with our constaints, bail out
+                None
+            }
         }
     }
 
diff --git a/src/librustc_codegen_llvm/diagnostics.rs b/src/librustc_codegen_llvm/diagnostics.rs
index 94776f17c79..242b7a1a119 100644
--- a/src/librustc_codegen_llvm/diagnostics.rs
+++ b/src/librustc_codegen_llvm/diagnostics.rs
@@ -47,4 +47,26 @@ unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok!
 ```
 "##,
 
+E0668: r##"
+Malformed inline assembly rejected by LLVM.
+
+LLVM checks the validity of the constraints and the assembly string passed to
+it. This error implies that LLVM seems something wrong with the inline
+assembly call.
+
+In particular, it can happen if you forgot the closing bracket of a register
+constraint (see issue #51430):
+```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
+#![feature(asm)]
+
+fn main() {
+    let rax: u64;
+    unsafe {
+        asm!("" :"={rax"(rax));
+        println!("Accumulator is: {}", rax);
+    }
+}
+```
+"##,
+
 }
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 845f2fa9f45..8485db4210c 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -1208,6 +1208,9 @@ extern "C" {
                              AlignStack: Bool,
                              Dialect: AsmDialect)
                              -> &Value;
+    pub fn LLVMRustInlineAsmVerify(Ty: &Type,
+                             Constraints: *const c_char)
+                             -> Bool;
 
     pub fn LLVMRustDebugMetadataVersion() -> u32;
     pub fn LLVMRustVersionMajor() -> u32;
diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs
index b4eb7615f98..6bd41bfe16f 100644
--- a/src/librustc_codegen_llvm/mir/statement.rs
+++ b/src/librustc_codegen_llvm/mir/statement.rs
@@ -86,7 +86,11 @@ impl FunctionCx<'a, 'll, 'tcx> {
                     self.codegen_operand(&bx, input).immediate()
                 }).collect();
 
-                asm::codegen_inline_asm(&bx, asm, outputs, input_vals);
+                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
             }
             mir::StatementKind::FakeRead(..) |
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 9b9c908ea52..f1ab1d4ddfa 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -426,6 +426,11 @@ extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString,
                              HasSideEffects, IsAlignStack, fromRust(Dialect)));
 }
 
+extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty,
+                                          char *Constraints) {
+  return InlineAsm::Verify(unwrap<FunctionType>(Ty), Constraints);
+}
+
 extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm) {
   unwrap(M)->appendModuleInlineAsm(StringRef(Asm));
 }
diff --git a/src/test/ui/inline-asm-bad-constraint.rs b/src/test/ui/inline-asm-bad-constraint.rs
new file mode 100644
index 00000000000..654f230741e
--- /dev/null
+++ b/src/test/ui/inline-asm-bad-constraint.rs
@@ -0,0 +1,47 @@
+// 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 invalid inline assembly constraints.
+
+#![feature(asm)]
+
+extern "C" {
+    fn foo(a: usize);
+}
+
+fn main() {
+    bad_register_constraint();
+    bad_input();
+    wrong_size_output();
+}
+
+// Issue #54130
+fn bad_register_constraint() {
+    let rax: u64;
+    unsafe {
+        asm!("" :"={rax"(rax)) //~ ERROR E0668
+    };
+    println!("Accumulator is: {}", rax);
+}
+
+// Issue #54376
+fn bad_input() {
+    unsafe {
+        asm!("callq $0" : : "0"(foo)) //~ ERROR E0668
+    };
+}
+
+fn wrong_size_output() {
+    let rax: u64 = 0;
+    unsafe {
+        asm!("addb $1, $0" : "={rax}"((0i32, rax))); //~ ERROR E0668
+    }
+    println!("rax: {}", rax);
+}
diff --git a/src/test/ui/inline-asm-bad-constraint.stderr b/src/test/ui/inline-asm-bad-constraint.stderr
new file mode 100644
index 00000000000..ce1f274749f
--- /dev/null
+++ b/src/test/ui/inline-asm-bad-constraint.stderr
@@ -0,0 +1,21 @@
+error[E0668]: malformed inline assembly
+  --> $DIR/inline-asm-bad-constraint.rs:29:9
+   |
+LL |         asm!("" :"={rax"(rax)) //~ ERROR E0668
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0668]: malformed inline assembly
+  --> $DIR/inline-asm-bad-constraint.rs:37:9
+   |
+LL |         asm!("callq $0" : : "0"(foo)) //~ ERROR E0668
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0668]: malformed inline assembly
+  --> $DIR/inline-asm-bad-constraint.rs:44:9
+   |
+LL |         asm!("addb $1, $0" : "={rax}"((0i32, rax))); //~ ERROR E0668
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0668`.