rust

Rustc does not emit trivial public functions


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)?


Solution

  • 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.