similar to GCC's __attribute((used))__. This attribute prevents LLVM from
optimizing away a non-exported symbol, within a compilation unit (object file),
when there are no references to it.
This is better explained with an example:
```
#[used]
static LIVE: i32 = 0;
static REFERENCED: i32 = 0;
static DEAD: i32 = 0;
fn internal() {}
pub fn exported() -> &'static i32 {
&REFERENCED
}
```
Without optimizations, LLVM pretty much preserves all the static variables and
functions within the compilation unit.
```
$ rustc --crate-type=lib --emit=obj symbols.rs && nm -C symbols.o
0000000000000000 t drop::h1be0f8f27a2ba94a
0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c
0000000000000000 r symbols::DEAD::hc2ea8f9bd06f380b
0000000000000000 r symbols::LIVE::h0970cf9889edb56e
0000000000000000 T symbols::exported::h6f096c2b1fc292b2
0000000000000000 t symbols::internal::h0ac1aadbc1e3a494
```
With optimizations, LLVM will drop dead code. Here `internal` is dropped because
it's not a exported function/symbol (i.e. not `pub`lic). `DEAD` is dropped for
the same reason. `REFERENCED` is preserved, even though it's not exported,
because it's referenced by the `exported` function. Finally, `LIVE` survives
because of the `#[used]` attribute even though it's not exported or referenced.
```
$ rustc --crate-type=lib -C opt-level=3 --emit=obj symbols.rs && nm -C symbols.o
0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c
0000000000000000 r symbols::LIVE::h0970cf9889edb56e
0000000000000000 T symbols::exported::h6f096c2b1fc292b2
```
Note that the linker knows nothing about `#[used]` and will drop `LIVE`
because no other object references to it.
```
$ echo 'fn main() {}' >> symbols.rs
$ rustc symbols.rs && nm -C symbols | grep LIVE
```
At this time, `#[used]` only works on `static` variables.
use callee;
use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
use collector::{self, TransItemCollectionMode};
-use common::{C_struct_in_context, C_u64, C_undef};
+use common::{C_struct_in_context, C_u64, C_undef, C_array};
use common::CrateContext;
use common::{type_is_zero_size, val_ty};
use common;
}
}
+ // Create llvm.used variable
+ if !ccx.used_statics().borrow().is_empty() {
+ debug!("llvm.used");
+
+ let name = CString::new("llvm.used").unwrap();
+ let section = CString::new("llvm.metadata").unwrap();
+ let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
+
+ unsafe {
+ let g = llvm::LLVMAddGlobal(ccx.llmod(),
+ val_ty(array).to_ref(),
+ name.as_ptr());
+ llvm::LLVMSetInitializer(g, array);
+ llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+ llvm::LLVMSetSection(g, section.as_ptr());
+ }
+ }
+
// Finalize debuginfo
if ccx.sess().opts.debuginfo != NoDebugInfo {
debuginfo::finalize(&ccx);
base::set_link_section(ccx, g, attrs);
+ if attr::contains_name(attrs, "used") {
+ ccx.used_statics().borrow_mut().push(g);
+ }
+
Ok(g)
}
}
/// to constants.)
statics_to_rauw: RefCell<Vec<(ValueRef, ValueRef)>>,
+ used_statics: RefCell<Vec<ValueRef>>,
+
lltypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
llsizingtypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
type_hashcodes: RefCell<FxHashMap<Ty<'tcx>, String>>,
impl_method_cache: RefCell::new(FxHashMap()),
closure_bare_wrapper_cache: RefCell::new(FxHashMap()),
statics_to_rauw: RefCell::new(Vec::new()),
+ used_statics: RefCell::new(Vec::new()),
lltypes: RefCell::new(FxHashMap()),
llsizingtypes: RefCell::new(FxHashMap()),
type_hashcodes: RefCell::new(FxHashMap()),
&self.local().statics_to_rauw
}
+ pub fn used_statics<'a>(&'a self) -> &'a RefCell<Vec<ValueRef>> {
+ &self.local().used_statics
+ }
+
pub fn lltypes<'a>(&'a self) -> &'a RefCell<FxHashMap<Ty<'tcx>, Type>> {
&self.local().lltypes
}
// `extern "x86-interrupt" fn()`
(active, abi_x86_interrupt, "1.17.0", Some(40180)),
+
// Allows the `catch {...}` expression
(active, catch_expr, "1.17.0", Some(31436)),
// See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
(active, rvalue_static_promotion, "1.15.1", Some(38865)),
+
+ // Used to preserve symbols
+ (active, used, "1.18.0", None),
);
declare_features! (
"unwind_attributes",
"#[unwind] is experimental",
cfg_fn!(unwind_attributes))),
+ ("used", Whitelisted, Gated(
+ Stability::Unstable, "used",
+ "the `#[used]` attribute is an experimental feature",
+ cfg_fn!(used))),
// used in resolve
("prelude_import", Whitelisted, Gated(Stability::Unstable,