about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-10-16 16:02:43 +0000
committerbors <bors@rust-lang.org>2017-10-16 16:02:43 +0000
commitba4e8d7db311b8a43a446cc20c30e4680b94c5d3 (patch)
treedc28540b4527d8c761a70f091274a73399c246ae /src
parenta96ff3b591d3bcc0ae906cd28053046e2efd7bde (diff)
parent5d415e8d080792615b424f3f0a931058519879b5 (diff)
downloadrust-ba4e8d7db311b8a43a446cc20c30e4680b94c5d3.tar.gz
rust-ba4e8d7db311b8a43a446cc20c30e4680b94c5d3.zip
Auto merge of #45202 - alexcrichton:fix-inline-always, r=michaelwoerister
rustc: Handle #[inline(always)] at -O0

This commit updates the handling of `#[inline(always)]` functions at -O0 to
ensure that it's always inlined regardless of the number of codegen units used.

Closes #45201
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/trans_item.rs32
-rw-r--r--src/test/codegen-units/partitioning/local-inlining-but-not-all.rs2
-rw-r--r--src/test/run-make/inline-always-many-cgu/Makefile8
-rw-r--r--src/test/run-make/inline-always-many-cgu/foo.rs25
4 files changed, 58 insertions, 9 deletions
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index e40b1617d0a..060f02ee23e 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -31,7 +31,7 @@ use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::subst::{Subst, Substs};
 use syntax::ast;
-use syntax::attr;
+use syntax::attr::{self, InlineAttr};
 use syntax_pos::Span;
 use syntax_pos::symbol::Symbol;
 use type_of;
@@ -175,16 +175,32 @@ pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
 
         match *self.as_trans_item() {
             TransItem::Fn(ref instance) => {
-                if self.explicit_linkage(tcx).is_none() &&
-                    common::requests_inline(tcx, instance)
+                // 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() ||
+                    !common::requests_inline(tcx, instance)
                 {
-                    if inline_in_all_cgus {
-                        InstantiationMode::LocalCopy
-                    } else {
+                    return InstantiationMode::GloballyShared  { may_conflict: false }
+                }
+
+                // 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
+                if inline_in_all_cgus {
+                    return InstantiationMode::LocalCopy
+                }
+
+                // Finally, if this is `#[inline(always)]` we're sure to respect
+                // that with an inline copy per CGU, but otherwise we'll be
+                // creating one copy of this `#[inline]` function which may
+                // conflict with upstream crates as it could be an exported
+                // symbol.
+                let attrs = instance.def.attrs(tcx);
+                match attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs) {
+                    InlineAttr::Always => InstantiationMode::LocalCopy,
+                    _ => {
                         InstantiationMode::GloballyShared  { may_conflict: true }
                     }
-                } else {
-                    InstantiationMode::GloballyShared  { may_conflict: false }
                 }
             }
             TransItem::Static(..) => {
diff --git a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs
index ccc8f03a40f..84464a627be 100644
--- a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs
+++ b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs
@@ -20,7 +20,7 @@
 mod inline {
 
     //~ TRANS_ITEM fn local_inlining_but_not_all::inline[0]::inlined_function[0] @@ local_inlining_but_not_all-inline[External]
-    #[inline(always)]
+    #[inline]
     pub fn inlined_function()
     {
 
diff --git a/src/test/run-make/inline-always-many-cgu/Makefile b/src/test/run-make/inline-always-many-cgu/Makefile
new file mode 100644
index 00000000000..edf88a6327c
--- /dev/null
+++ b/src/test/run-make/inline-always-many-cgu/Makefile
@@ -0,0 +1,8 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) foo.rs --emit llvm-ir -C codegen-units=2
+	if grep -w call $(TMPDIR)/*.ll; then \
+		echo "found call instruction when one wasn't expected"; \
+		exit 1; \
+	fi
diff --git a/src/test/run-make/inline-always-many-cgu/foo.rs b/src/test/run-make/inline-always-many-cgu/foo.rs
new file mode 100644
index 00000000000..539dcdfa9b3
--- /dev/null
+++ b/src/test/run-make/inline-always-many-cgu/foo.rs
@@ -0,0 +1,25 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
+
+pub mod a {
+    #[inline(always)]
+    pub fn foo() {
+    }
+
+    pub fn bar() {
+    }
+}
+
+#[no_mangle]
+pub fn bar() {
+    a::foo();
+}