Skip to content

Commit

Permalink
Rollup merge of rust-lang#73034 - doctorn:nomangle-inline-linkage, r=…
Browse files Browse the repository at this point in the history
…matthewjasper

Export `#[inline]` fns with extern indicators

In ancient history (rust-lang#36280) we stopped `#[inline]` fns being codegened if they weren't used. However,

- rust-lang#72944
- rust-lang#72463

observe that when writing something like

```rust
#![crate_type = "cdylib"]

#[no_mangle]
#[inline]
pub extern "C" fn foo() {
    // ...
}
```

we really _do_ want `foo` to be codegened. This change makes this the case.

Resolves rust-lang#72944, resolves rust-lang#72463 (and maybe some more)
  • Loading branch information
Manishearth committed Jun 18, 2020
2 parents bf59152 + e8e0a0e commit 0e332e9
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 14 deletions.
10 changes: 6 additions & 4 deletions src/librustc_codegen_ssa/back/symbol_export.rs
Expand Up @@ -89,10 +89,12 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
| 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);
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)
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())
{
Some(def_id)
} else {
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_middle/mir/mono.rs
Expand Up @@ -91,9 +91,9 @@ impl<'tcx> MonoItem<'tcx> {
match *self {
MonoItem::Fn(ref instance) => {
let entry_def_id = tcx.entry_fn(LOCAL_CRATE).map(|(id, _)| id);
// 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()
// 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()
|| !instance.def.generates_cgu_internal_copy(tcx)
|| Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
{
Expand All @@ -102,7 +102,7 @@ impl<'tcx> MonoItem<'tcx> {

// 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
// be creating a local copy per CGU
// be creating a local copy per CGU.
if generate_cgu_internal_copies {
return InstantiationMode::LocalCopy;
}
Expand Down
43 changes: 43 additions & 0 deletions src/test/codegen/cdylib-external-inline-fns.rs
@@ -0,0 +1,43 @@
// 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() {}
20 changes: 15 additions & 5 deletions src/test/codegen/export-no-mangle.rs
Expand Up @@ -11,11 +11,21 @@ mod private {
#[export_name = "BAR"]
static BAR: u32 = 3;

// CHECK: void @foo()
// CHECK: void @a()
#[no_mangle]
pub extern fn foo() {}
pub extern fn a() {}

// CHECK: void @bar()
#[export_name = "bar"]
extern fn bar() {}
// 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() {}
}
20 changes: 20 additions & 0 deletions src/test/codegen/external-no-mangle-fns.rs
Expand Up @@ -53,3 +53,23 @@ fn x() {
core::ptr::read_volatile(&42);
}
}

// 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() {}
2 changes: 1 addition & 1 deletion src/test/codegen/sanitizer-no-sanitize-inlining.rs
Expand Up @@ -13,7 +13,7 @@
#![feature(no_sanitize)]

// ASAN-LABEL: define void @test
// ASAN: tail call fastcc void @random_inline
// ASAN: call {{.*}} @random_inline
// ASAN: }
//
// LSAN-LABEL: define void @test
Expand Down
43 changes: 43 additions & 0 deletions src/test/codegen/staticlib-external-inline-fns.rs
@@ -0,0 +1,43 @@
// 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() {}

0 comments on commit 0e332e9

Please sign in to comment.