about summary refs log tree commit diff
diff options
context:
space:
mode:
authorManish Goregaokar <manishsmail@gmail.com>2020-06-18 15:20:51 -0700
committerGitHub <noreply@github.com>2020-06-18 15:20:51 -0700
commit0e332e9e3c4a33458cac1801f59c2d0a3ca28484 (patch)
tree47466b9f29e0272a3aa750d65a9820bbbaae2b76
parentbf59152c01d9ffc4ceeb982e26b3df2354ebede6 (diff)
parente8e0a0e4e220533db31bc6a572ed9f1b99b31289 (diff)
downloadrust-0e332e9e3c4a33458cac1801f59c2d0a3ca28484.tar.gz
rust-0e332e9e3c4a33458cac1801f59c2d0a3ca28484.zip
Rollup merge of #73034 - doctorn:nomangle-inline-linkage, r=matthewjasper
Export `#[inline]` fns with extern indicators

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

- #72944
- #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 #72944, resolves #72463 (and maybe some more)
-rw-r--r--src/librustc_codegen_ssa/back/symbol_export.rs10
-rw-r--r--src/librustc_middle/mir/mono.rs8
-rw-r--r--src/test/codegen/cdylib-external-inline-fns.rs43
-rw-r--r--src/test/codegen/export-no-mangle.rs20
-rw-r--r--src/test/codegen/external-no-mangle-fns.rs20
-rw-r--r--src/test/codegen/sanitizer-no-sanitize-inlining.rs2
-rw-r--r--src/test/codegen/staticlib-external-inline-fns.rs43
7 files changed, 132 insertions, 14 deletions
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index 970d13b30c0..98f7da8361c 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -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 {
diff --git a/src/librustc_middle/mir/mono.rs b/src/librustc_middle/mir/mono.rs
index c889dbc0a44..f1c1b962ab9 100644
--- a/src/librustc_middle/mir/mono.rs
+++ b/src/librustc_middle/mir/mono.rs
@@ -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)
                 {
@@ -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;
                 }
diff --git a/src/test/codegen/cdylib-external-inline-fns.rs b/src/test/codegen/cdylib-external-inline-fns.rs
new file mode 100644
index 00000000000..519be6b6a99
--- /dev/null
+++ b/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() {}
diff --git a/src/test/codegen/export-no-mangle.rs b/src/test/codegen/export-no-mangle.rs
index 78d41e4be0a..59e97601c83 100644
--- a/src/test/codegen/export-no-mangle.rs
+++ b/src/test/codegen/export-no-mangle.rs
@@ -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() {}
 }
diff --git a/src/test/codegen/external-no-mangle-fns.rs b/src/test/codegen/external-no-mangle-fns.rs
index 90288214499..41820b057f1 100644
--- a/src/test/codegen/external-no-mangle-fns.rs
+++ b/src/test/codegen/external-no-mangle-fns.rs
@@ -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() {}
diff --git a/src/test/codegen/sanitizer-no-sanitize-inlining.rs b/src/test/codegen/sanitizer-no-sanitize-inlining.rs
index d96e76618d3..48231d6f720 100644
--- a/src/test/codegen/sanitizer-no-sanitize-inlining.rs
+++ b/src/test/codegen/sanitizer-no-sanitize-inlining.rs
@@ -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
diff --git a/src/test/codegen/staticlib-external-inline-fns.rs b/src/test/codegen/staticlib-external-inline-fns.rs
new file mode 100644
index 00000000000..8876ab7376a
--- /dev/null
+++ b/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() {}