Skip to content

Commit cad760b

Browse files
committed
librustc: Make addresses of immutable statics insignificant unless
`#[inline(never)]` is used. Closes #8958. This can break some code that relied on the addresses of statics being distinct; add `#[inline(never)]` to the affected statics. [breaking-change]
1 parent db29814 commit cad760b

File tree

9 files changed

+55
-38
lines changed

9 files changed

+55
-38
lines changed

src/doc/rust.md

+11-4
Original file line numberDiff line numberDiff line change
@@ -1829,8 +1829,6 @@ type int8_t = i8;
18291829

18301830
### Static-only attributes
18311831

1832-
- `address_insignificant` - references to this static may alias with
1833-
references to other statics, potentially of unrelated type.
18341832
- `thread_local` - on a `static mut`, this signals that the value of this
18351833
static may change depending on the current thread. The exact consequences of
18361834
this are implementation-defined.
@@ -2141,13 +2139,22 @@ These types help drive the compiler's analysis
21412139
### Inline attributes
21422140

21432141
The inline attribute is used to suggest to the compiler to perform an inline
2144-
expansion and place a copy of the function in the caller rather than generating
2145-
code to call the function where it is defined.
2142+
expansion and place a copy of the function or static in the caller rather than
2143+
generating code to call the function or access the static where it is defined.
21462144

21472145
The compiler automatically inlines functions based on internal heuristics.
21482146
Incorrectly inlining functions can actually making the program slower, so it
21492147
should be used with care.
21502148

2149+
Immutable statics are always considered inlineable
2150+
unless marked with `#[inline(never)]`.
2151+
It is undefined
2152+
whether two different inlineable statics
2153+
have the same memory address.
2154+
In other words,
2155+
the compiler is free
2156+
to collapse duplicate inlineable statics together.
2157+
21512158
`#[inline]` and `#[inline(always)]` always causes the function to be serialized
21522159
into crate metadata to allow cross-crate inlining.
21532160

src/librustc/middle/lint.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,6 @@ fn check_unused_attribute(cx: &Context, attr: &ast::Attribute) {
10871087

10881088
// FIXME: #14406 these are processed in trans, which happens after the
10891089
// lint pass
1090-
"address_insignificant",
10911090
"cold",
10921091
"inline",
10931092
"link",

src/librustc/middle/reachable.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,20 @@ use std::collections::HashSet;
2626
use syntax::abi;
2727
use syntax::ast;
2828
use syntax::ast_map;
29-
use syntax::ast_util::{is_local};
29+
use syntax::ast_util::is_local;
30+
use syntax::ast_util;
31+
use syntax::attr::{InlineAlways, InlineHint, InlineNever, InlineNone};
3032
use syntax::attr;
3133
use syntax::visit::Visitor;
3234
use syntax::visit;
3335

3436
// Returns true if the given set of attributes contains the `#[inline]`
3537
// attribute.
3638
fn attributes_specify_inlining(attrs: &[ast::Attribute]) -> bool {
37-
attr::contains_name(attrs, "inline")
39+
match attr::find_inline_attr(attrs) {
40+
InlineNone | InlineNever => false,
41+
InlineAlways | InlineHint => true,
42+
}
3843
}
3944

4045
// Returns true if the given set of generics implies that the item it's
@@ -118,8 +123,8 @@ impl<'a> Visitor<()> for ReachableContext<'a> {
118123
match def {
119124
// If this path leads to a static, then we may have
120125
// to do some work to figure out whether the static
121-
// is indeed reachable (address_insignificant
122-
// statics are *never* reachable).
126+
// is indeed reachable. (Inlineable statics are
127+
// never reachable.)
123128
def::DefStatic(..) => {
124129
self.worklist.push(def_id.node);
125130
}
@@ -281,9 +286,10 @@ impl<'a> ReachableContext<'a> {
281286

282287
// Statics with insignificant addresses are not reachable
283288
// because they're inlined specially into all other crates.
284-
ast::ItemStatic(_, _, ref init) => {
285-
if attr::contains_name(item.attrs.as_slice(),
286-
"address_insignificant") {
289+
ast::ItemStatic(_, mutbl, ref init) => {
290+
if !ast_util::static_has_significant_address(
291+
mutbl,
292+
item.attrs.as_slice()) {
287293
self.reachable_symbols.remove(&search_item);
288294
}
289295
visit::walk_expr(self, &**init, ());

src/librustc/middle/trans/base.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -1994,7 +1994,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
19941994
let sym = exported_name(ccx, id, ty, i.attrs.as_slice());
19951995

19961996
let v = match i.node {
1997-
ast::ItemStatic(_, _, ref expr) => {
1997+
ast::ItemStatic(_, mutbl, ref expr) => {
19981998
// If this static came from an external crate, then
19991999
// we need to get the symbol from csearch instead of
20002000
// using the current crate's name/version
@@ -2029,28 +2029,24 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
20292029

20302030
// Apply the `unnamed_addr` attribute if
20312031
// requested
2032-
if attr::contains_name(i.attrs.as_slice(),
2033-
"address_insignificant") {
2034-
if ccx.reachable.contains(&id) {
2035-
ccx.sess().span_bug(i.span,
2036-
"insignificant static is reachable");
2037-
}
2032+
if !ast_util::static_has_significant_address(
2033+
mutbl,
2034+
i.attrs.as_slice()) {
20382035
lib::llvm::SetUnnamedAddr(g, true);
20392036

20402037
// This is a curious case where we must make
20412038
// all of these statics inlineable. If a
2042-
// global is tagged as
2043-
// address_insignificant, then LLVM won't
2044-
// coalesce globals unless they have an
2045-
// internal linkage type. This means that
2039+
// global is not tagged as `#[inline(never)]`,
2040+
// then LLVM won't coalesce globals unless they
2041+
// have an internal linkage type. This means that
20462042
// external crates cannot use this global.
20472043
// This is a problem for things like inner
20482044
// statics in generic functions, because the
20492045
// function will be inlined into another
20502046
// crate and then attempt to link to the
20512047
// static in the original crate, only to
20522048
// find that it's not there. On the other
2053-
// side of inlininig, the crates knows to
2049+
// side of inlining, the crates knows to
20542050
// not declare this static as
20552051
// available_externally (because it isn't)
20562052
inlineable = true;

src/librustc/middle/trans/inline.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use middle::ty;
1717

1818
use syntax::ast;
1919
use syntax::ast_util::local_def;
20-
use syntax::attr;
20+
use syntax::ast_util;
2121

2222
pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
2323
-> ast::DefId {
@@ -62,12 +62,13 @@ pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
6262
// however, so we use the available_externally linkage which llvm
6363
// provides
6464
match item.node {
65-
ast::ItemStatic(..) => {
65+
ast::ItemStatic(_, mutbl, _) => {
6666
let g = get_item_val(ccx, item.id);
6767
// see the comment in get_item_val() as to why this check is
6868
// performed here.
69-
if !attr::contains_name(item.attrs.as_slice(),
70-
"address_insignificant") {
69+
if ast_util::static_has_significant_address(
70+
mutbl,
71+
item.attrs.as_slice()) {
7172
SetLinkage(g, AvailableExternallyLinkage);
7273
}
7374
}

src/libsyntax/ast_util.rs

+13
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use ast::*;
1212
use ast;
1313
use ast_util;
14+
use attr::{InlineNever, InlineNone};
15+
use attr;
1416
use codemap;
1517
use codemap::Span;
1618
use owned_slice::OwnedSlice;
@@ -742,6 +744,17 @@ pub fn get_inner_tys(ty: P<Ty>) -> Vec<P<Ty>> {
742744
}
743745
}
744746

747+
/// Returns true if the static with the given mutability and attributes
748+
/// has a significant address and false otherwise.
749+
pub fn static_has_significant_address(mutbl: ast::Mutability,
750+
attrs: &[ast::Attribute])
751+
-> bool {
752+
if mutbl == ast::MutMutable {
753+
return true
754+
}
755+
let inline = attr::find_inline_attr(attrs);
756+
inline == InlineNever || inline == InlineNone
757+
}
745758

746759
#[cfg(test)]
747760
mod test {

src/libsyntax/ext/format.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -312,22 +312,14 @@ impl<'a, 'b> Context<'a, 'b> {
312312
/// These attributes are applied to all statics that this syntax extension
313313
/// will generate.
314314
fn static_attrs(&self) -> Vec<ast::Attribute> {
315-
// Flag statics as `address_insignificant` so LLVM can merge duplicate
316-
// globals as much as possible (which we're generating a whole lot of).
317-
let unnamed = self.ecx
318-
.meta_word(self.fmtsp,
319-
InternedString::new(
320-
"address_insignificant"));
321-
let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
322-
323315
// Do not warn format string as dead code
324316
let dead_code = self.ecx.meta_word(self.fmtsp,
325317
InternedString::new("dead_code"));
326318
let allow_dead_code = self.ecx.meta_list(self.fmtsp,
327319
InternedString::new("allow"),
328320
vec!(dead_code));
329321
let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code);
330-
return vec!(unnamed, allow_dead_code);
322+
return vec!(allow_dead_code);
331323
}
332324

333325
fn rtpath(&self, s: &str) -> Vec<ast::Ident> {

src/test/auxiliary/xcrate_address_insignificant.rs

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// except according to those terms.
1010

1111
pub fn foo<T>() -> int {
12-
#[address_insignificant]
1312
static a: int = 3;
1413
a
1514
}

src/test/auxiliary/xcrate_static_addresses.rs

+4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#[inline(never)]
1112
pub static global: int = 3;
1213

14+
#[inline(never)]
1315
static global0: int = 4;
16+
17+
#[inline(never)]
1418
pub static global2: &'static int = &global0;
1519

1620
pub fn verify_same(a: &'static int) {

0 commit comments

Comments
 (0)