about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_transform')
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs31
1 files changed, 29 insertions, 2 deletions
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index cdb0ed761cf..a98901a6688 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -195,10 +195,37 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> {
         &self,
         _: &CallSite<'tcx>,
         callee_body: &Body<'tcx>,
-        _: &CodegenFnAttrs,
+        callee_attrs: &CodegenFnAttrs,
         _: bool,
     ) -> Result<(), &'static str> {
-        if let Some(_) = callee_body.tainted_by_errors { Err("body has errors") } else { Ok(()) }
+        if callee_body.tainted_by_errors.is_some() {
+            return Err("body has errors");
+        }
+
+        let caller_attrs = self.tcx().codegen_fn_attrs(self.caller_def_id());
+        if callee_attrs.instruction_set != caller_attrs.instruction_set
+            && callee_body
+                .basic_blocks
+                .iter()
+                .any(|bb| matches!(bb.terminator().kind, TerminatorKind::InlineAsm { .. }))
+        {
+            // During the attribute checking stage we allow a callee with no
+            // instruction_set assigned to count as compatible with a function that does
+            // assign one. However, during this stage we require an exact match when any
+            // inline-asm is detected. LLVM will still possibly do an inline later on
+            // if the no-attribute function ends up with the same instruction set anyway.
+            Err("cannot move inline-asm across instruction sets")
+        } else if callee_body
+            .basic_blocks
+            .iter()
+            .any(|bb| matches!(bb.terminator().kind, TerminatorKind::TailCall { .. }))
+        {
+            // FIXME(explicit_tail_calls): figure out how exactly functions containing tail
+            // calls can be inlined (and if they even should)
+            Err("can't inline functions with tail calls")
+        } else {
+            Ok(())
+        }
     }
 
     fn inline_limit_for_block(&self) -> Option<usize> {