Change:
I currently use Rust to generate a static library for FFI consumption. In some public interfaces, I call other FFI public interfaces as primarily a wrapper with a few tweaks. I'd like to mark these "inner" functions as inline, however, this seems to cause them to not show up in the final staticlib. Given this drastically simplified example: The function makes it to the static library, but the function does not: If I remove the attribute, we see both functions in the static lib: The don't seem to hint that can prevent / items from surviving all the way to the final library, or that they shouldn't be used together. I would expect any function marked and/or should be present in the final artifact, regardless of attributes. I see this behavior on stable, as well as a recent nightly. I don't know if this is a regression, as this is the first time I've run into this. Thanks! Edit: Simplified profile settings, they are not needed to reproduce. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --This issue has been assigned to via . <!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Tried with = same result
I’ve noticed this for a while but I always assumed it was intended... It would be really nice if this was fixed
This appears to have been done deliberately: Maybe it shouldn't apply to s.
Expanding on note, I would also expect this not to apply to s as well (I used the staticlib for my example, but my use case generates code for both static and dynamic library usage).
I think I'm going to take this on claim

Discussion:
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => { let def_id = tcx.hir().local_def_id(hir_id); let generics = tcx.generics_of(def_id); <del> if !generics.requires_monomorphization(tcx) && // Functions marked with #[inline] are only ever codegened // with "internal" linkage and are never exported. !Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx) </del> <ins> if !generics.requires_monomorphization(tcx) // Functions marked with #[inline] are codegened with "internal" // linkage and are not exported unless marked with an extern // inidicator && (!Instance::mono(tcx, def_id.to_def_id()).def.generates_cgu_internal_copy(tcx) || tcx.codegen_fn_attrs(def_id.to_def_id()).contains_extern_indicator()) </ins> { Some(def_id) } else {

match *self { MonoItem::Fn(ref instance) => { let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id); <del> // If this function isn't inlined or otherwise has explicit // linkage, then we'll be creating a globally shared version. if self.explicit_linkage(tcx).is_some() </del> <ins> // If this function isn't inlined or otherwise has an extern // indicator, then we'll be creating a globally shared version. if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator() </ins> || !instance.def.generates_cgu_internal_copy(tcx) || Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id) {

// At this point we don't have explicit linkage and we're an // inlined function. If we're inlining into all CGUs then we'll <del> // be creating a local copy per CGU </del> <ins> // be creating a local copy per CGU. </ins> if generate_cgu_internal_copies { return InstantiationMode::LocalCopy; }

<ins> // compile-flags: -C no-prepopulate-passes #![crate_type = "cdylib"] // CHECK: define void @a() #[no_mangle] #[inline] pub extern "C" fn a() {} // CHECK: define void @b() #[export_name = "b"] #[inline] pub extern "C" fn b() {} // CHECK: define void @c() #[no_mangle] #[inline] extern "C" fn c() {} // CHECK: define void @d() #[export_name = "d"] #[inline] extern "C" fn d() {} // CHECK: define void @e() #[no_mangle] #[inline(always)] pub extern "C" fn e() {} // CHECK: define void @f() #[export_name = "f"] #[inline(always)] pub extern "C" fn f() {} // CHECK: define void @g() #[no_mangle] #[inline(always)] extern "C" fn g() {} // CHECK: define void @h() #[export_name = "h"] #[inline(always)] extern "C" fn h() {} </ins>

#[export_name = "BAR"] static BAR: u32 = 3; <del> // CHECK: void @foo() </del> <ins> // CHECK: void @a() </ins> #[no_mangle] <del> pub extern fn foo() {} </del> <ins> pub extern fn a() {} </ins> <del> // CHECK: void @bar() #[export_name = "bar"] extern fn bar() {} </del> <ins> // CHECK: void @b() #[export_name = "b"] extern fn b() {} // CHECK: void @c() #[export_name = "c"] #[inline] extern fn c() {} // CHECK: void @d() #[export_name = "d"] #[inline(always)] extern fn d() {} </ins> }

core::ptr::read_volatile(&42); } } <ins> // CHECK: define void @i() #[no_mangle] #[inline] fn i() {} // CHECK: define void @j() #[no_mangle] #[inline] pub fn j() {} // CHECK: define void @k() #[no_mangle] #[inline(always)] fn k() {} // CHECK: define void @l() #[no_mangle] #[inline(always)] pub fn l() {} </ins>

#![feature(no_sanitize)] // ASAN-LABEL: define void @test <del> // ASAN:         tail call fastcc void @random_inline </del> <ins> // ASAN:         call {{.*}} @random_inline </ins> // ASAN:       } // // LSAN-LABEL: define void @test

<ins> // compile-flags: -C no-prepopulate-passes #![crate_type = "staticlib"] // CHECK: define void @a() #[no_mangle] #[inline] pub extern "C" fn a() {} // CHECK: define void @b() #[export_name = "b"] #[inline] pub extern "C" fn b() {} // CHECK: define void @c() #[no_mangle] #[inline] extern "C" fn c() {} // CHECK: define void @d() #[export_name = "d"] #[inline] extern "C" fn d() {} // CHECK: define void @e() #[no_mangle] #[inline(always)] pub extern "C" fn e() {} // CHECK: define void @f() #[export_name = "f"] #[inline(always)] pub extern "C" fn f() {} // CHECK: define void @g() #[no_mangle] #[inline(always)] extern "C" fn g() {} // CHECK: define void @h() #[export_name = "h"] #[inline(always)] extern "C" fn h() {} </ins>