Skip to content

Commit cfcb853

Browse files
committed
inline: re-introduce some callee body checks
1 parent 3edfb8b commit cfcb853

File tree

3 files changed

+131
-2
lines changed

3 files changed

+131
-2
lines changed

compiler/rustc_mir_transform/src/inline.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,37 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> {
195195
&self,
196196
_: &CallSite<'tcx>,
197197
callee_body: &Body<'tcx>,
198-
_: &CodegenFnAttrs,
198+
callee_attrs: &CodegenFnAttrs,
199199
_: bool,
200200
) -> Result<(), &'static str> {
201-
if let Some(_) = callee_body.tainted_by_errors { Err("body has errors") } else { Ok(()) }
201+
if callee_body.tainted_by_errors.is_some() {
202+
return Err("body has errors");
203+
}
204+
205+
let caller_attrs = self.tcx().codegen_fn_attrs(self.caller_def_id());
206+
if callee_attrs.instruction_set != caller_attrs.instruction_set
207+
&& callee_body
208+
.basic_blocks
209+
.iter()
210+
.any(|bb| matches!(bb.terminator().kind, TerminatorKind::InlineAsm { .. }))
211+
{
212+
// During the attribute checking stage we allow a callee with no
213+
// instruction_set assigned to count as compatible with a function that does
214+
// assign one. However, during this stage we require an exact match when any
215+
// inline-asm is detected. LLVM will still possibly do an inline later on
216+
// if the no-attribute function ends up with the same instruction set anyway.
217+
Err("cannot move inline-asm across instruction sets")
218+
} else if callee_body
219+
.basic_blocks
220+
.iter()
221+
.any(|bb| matches!(bb.terminator().kind, TerminatorKind::TailCall { .. }))
222+
{
223+
// FIXME(explicit_tail_calls): figure out how exactly functions containing tail
224+
// calls can be inlined (and if they even should)
225+
Err("can't inline functions with tail calls")
226+
} else {
227+
Ok(())
228+
}
202229
}
203230

204231
fn inline_limit_for_block(&self) -> Option<usize> {

tests/ui/force-inlining/asm.rs

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//@ build-fail
2+
//@ compile-flags: --crate-type=lib --target thumbv4t-none-eabi
3+
//@ needs-llvm-components: arm
4+
5+
// Checks that forced inlining won't mix asm with incompatible instruction sets.
6+
7+
#![crate_type = "lib"]
8+
#![feature(rustc_attrs)]
9+
#![feature(no_core, lang_items)]
10+
#![no_core]
11+
12+
#[lang = "sized"]
13+
pub trait Sized {}
14+
#[lang = "copy"]
15+
pub trait Copy {}
16+
#[lang = "freeze"]
17+
pub unsafe trait Freeze {}
18+
19+
#[lang = "start"]
20+
fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
21+
0
22+
}
23+
24+
#[rustc_builtin_macro]
25+
#[macro_export]
26+
macro_rules! asm {
27+
("assembly template",
28+
$(operands,)*
29+
$(options($(option),*))?
30+
) => {
31+
/* compiler built-in */
32+
};
33+
}
34+
35+
#[instruction_set(arm::a32)]
36+
#[rustc_force_inline]
37+
fn instruction_set_a32() {}
38+
39+
#[instruction_set(arm::t32)]
40+
#[rustc_force_inline]
41+
fn instruction_set_t32() {}
42+
43+
#[rustc_force_inline]
44+
fn instruction_set_default() {}
45+
46+
#[rustc_force_inline]
47+
fn inline_always_and_using_inline_asm() {
48+
unsafe { asm!("/* do nothing */") };
49+
}
50+
51+
#[instruction_set(arm::t32)]
52+
pub fn t32() {
53+
instruction_set_a32();
54+
//~^ ERROR `instruction_set_a32` could not be inlined into `t32` but is required to be inlined
55+
instruction_set_t32();
56+
instruction_set_default();
57+
inline_always_and_using_inline_asm();
58+
//~^ ERROR `inline_always_and_using_inline_asm` could not be inlined into `t32` but is required to be inlined
59+
}
60+
61+
pub fn default() {
62+
instruction_set_a32();
63+
//~^ ERROR `instruction_set_a32` could not be inlined into `default` but is required to be inlined
64+
instruction_set_t32();
65+
//~^ ERROR `instruction_set_t32` could not be inlined into `default` but is required to be inlined
66+
instruction_set_default();
67+
inline_always_and_using_inline_asm();
68+
}

tests/ui/force-inlining/asm.stderr

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: `instruction_set_a32` could not be inlined into `t32` but is required to be inlined
2+
--> $DIR/asm.rs:53:5
3+
|
4+
LL | instruction_set_a32();
5+
| ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here
6+
|
7+
= note: could not be inlined due to: incompatible instruction set
8+
9+
error: `inline_always_and_using_inline_asm` could not be inlined into `t32` but is required to be inlined
10+
--> $DIR/asm.rs:57:5
11+
|
12+
LL | inline_always_and_using_inline_asm();
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...`inline_always_and_using_inline_asm` called here
14+
|
15+
= note: could not be inlined due to: cannot move inline-asm across instruction sets
16+
17+
error: `instruction_set_a32` could not be inlined into `default` but is required to be inlined
18+
--> $DIR/asm.rs:62:5
19+
|
20+
LL | instruction_set_a32();
21+
| ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here
22+
|
23+
= note: could not be inlined due to: incompatible instruction set
24+
25+
error: `instruction_set_t32` could not be inlined into `default` but is required to be inlined
26+
--> $DIR/asm.rs:64:5
27+
|
28+
LL | instruction_set_t32();
29+
| ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_t32` called here
30+
|
31+
= note: could not be inlined due to: incompatible instruction set
32+
33+
error: aborting due to 4 previous errors
34+

0 commit comments

Comments
 (0)