This code
pub fn foo(v: &[i32], i: usize) -> i32 {
unsafe { *v.get_unchecked(i) }
}
compiles to effectively empty assembly (checked on master and 1.87.0):
$ rustc --crate-type=rlib -O --emit=asm test.rs
$ cat test.s
.file "test.4707fbd51808b46e-cgu.0"
.ident "rustc version 1.89.0-dev"
.section ".note.GNU-stack","",@progbits
and generated binary also does not include foo
:
$ rustc --crate-type=rlib -O test.rs
$ objdump -rd libtest.rlib
In archive libtest.rlib:
lib.rmeta: file format elf64-x86-64
test.test.4707fbd51808b46e-cgu.0.rcgu.o: file format elf64-x86-64
$ readelf -sW libtest.rlib
File: libtest.rlib(lib.rmeta)
Symbol table '.symtab' contains 1 entry:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
File: libtest.rlib(test.test.4707fbd51808b46e-cgu.0.rcgu.o)
Symbol table '.symtab' contains 2 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.4707fbd51808b46e-cgu.0
My understanding is that "trivial" functions like foo
aren't emitted explicitly but compiler still somehow "records" them in .rlib file (in lib.rmeta
?).
Could someone confirm/refute this and maybe add relevant links about this compiler behavior? Also is there some way to force compiler to actually generate assembly for such functions (I want to inspect the generated code)?
Disclaimer: Partial Answer, it works in practice, but there's no guarantees.
I expect, but did not verify, that is linked to whether the function is trivially inlinable, or not.
And indeed, on the playground, annotating the function with #[inline(never)]
results in its code being emitted in LLVM IR, when it isn't without the annotation. Unfortunately, this is somewhat unsatisfying as the inline attribute is always treated as a suggestion, even #[inline(never)]
, and therefore there is no formal guarantee that it wouldn't be inlined anyway.
A related attribute, for static variables, is #[used]
, however it doesn't apply to functions.