2012-12-04 00:48:01 +00:00
|
|
|
// Copyright 2012 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.
|
|
|
|
|
2013-05-17 22:28:44 +00:00
|
|
|
|
2014-07-08 00:58:01 +00:00
|
|
|
use llvm;
|
2016-08-02 21:25:19 +00:00
|
|
|
use llvm::{SetUnnamedAddr};
|
2016-09-01 18:52:33 +00:00
|
|
|
use llvm::{ValueRef, True};
|
2016-08-16 14:41:38 +00:00
|
|
|
use rustc_const_eval::ConstEvalErr;
|
2016-03-29 09:54:26 +00:00
|
|
|
use rustc::hir::def_id::DefId;
|
2016-03-29 05:50:44 +00:00
|
|
|
use rustc::hir::map as hir_map;
|
2016-08-16 14:41:38 +00:00
|
|
|
use {debuginfo, machine};
|
2016-05-12 16:52:38 +00:00
|
|
|
use base::{self, push_ctxt};
|
2016-05-09 17:37:14 +00:00
|
|
|
use trans_item::TransItem;
|
2016-08-16 14:41:38 +00:00
|
|
|
use common::{CrateContext, val_ty};
|
2016-03-22 17:23:36 +00:00
|
|
|
use declare;
|
2016-08-16 14:41:38 +00:00
|
|
|
use monomorphize::{Instance};
|
2016-03-22 17:23:36 +00:00
|
|
|
use type_::Type;
|
|
|
|
use type_of;
|
2016-08-16 14:41:38 +00:00
|
|
|
use rustc::ty;
|
2012-12-13 21:05:22 +00:00
|
|
|
|
2016-03-29 05:50:44 +00:00
|
|
|
use rustc::hir;
|
2015-07-31 07:04:06 +00:00
|
|
|
|
2015-06-28 17:36:46 +00:00
|
|
|
use std::ffi::{CStr, CString};
|
2016-08-16 14:41:38 +00:00
|
|
|
use syntax::ast;
|
2016-08-23 03:54:53 +00:00
|
|
|
use syntax::attr;
|
2012-08-01 01:34:36 +00:00
|
|
|
|
2015-01-04 16:47:58 +00:00
|
|
|
pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
|
2013-01-11 05:23:07 +00:00
|
|
|
unsafe {
|
2015-01-04 16:47:58 +00:00
|
|
|
llvm::LLVMConstPointerCast(val, ty.to_ref())
|
2013-01-11 05:23:07 +00:00
|
|
|
}
|
2012-08-09 23:05:34 +00:00
|
|
|
}
|
|
|
|
|
2016-04-21 13:15:56 +00:00
|
|
|
pub fn addr_of_mut(ccx: &CrateContext,
|
|
|
|
cv: ValueRef,
|
|
|
|
align: machine::llalign,
|
|
|
|
kind: &str)
|
|
|
|
-> ValueRef {
|
2013-03-07 20:34:39 +00:00
|
|
|
unsafe {
|
2016-10-21 16:41:20 +00:00
|
|
|
let name = ccx.generate_local_symbol_name(kind);
|
2015-03-03 23:08:06 +00:00
|
|
|
let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{
|
2016-03-28 23:46:02 +00:00
|
|
|
bug!("symbol `{}` is already defined", name);
|
2015-03-03 23:08:06 +00:00
|
|
|
});
|
2013-03-07 20:34:39 +00:00
|
|
|
llvm::LLVMSetInitializer(gv, cv);
|
2015-10-08 23:26:21 +00:00
|
|
|
llvm::LLVMSetAlignment(gv, align);
|
2016-09-01 18:52:33 +00:00
|
|
|
llvm::LLVMRustSetLinkage(gv, llvm::Linkage::InternalLinkage);
|
2015-01-29 12:03:34 +00:00
|
|
|
SetUnnamedAddr(gv, true);
|
2013-03-07 20:34:39 +00:00
|
|
|
gv
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-29 12:03:34 +00:00
|
|
|
pub fn addr_of(ccx: &CrateContext,
|
|
|
|
cv: ValueRef,
|
2015-10-08 23:26:21 +00:00
|
|
|
align: machine::llalign,
|
2015-03-03 23:08:06 +00:00
|
|
|
kind: &str)
|
2015-01-29 12:03:34 +00:00
|
|
|
-> ValueRef {
|
2016-07-03 21:38:37 +00:00
|
|
|
if let Some(&gv) = ccx.const_globals().borrow().get(&cv) {
|
|
|
|
unsafe {
|
|
|
|
// Upgrade the alignment in cases where the same constant is used with different
|
|
|
|
// alignment requirements
|
|
|
|
if align > llvm::LLVMGetAlignment(gv) {
|
|
|
|
llvm::LLVMSetAlignment(gv, align);
|
2015-10-08 23:26:21 +00:00
|
|
|
}
|
|
|
|
}
|
2016-07-03 21:38:37 +00:00
|
|
|
return gv;
|
2015-01-29 12:03:34 +00:00
|
|
|
}
|
2015-10-08 23:26:21 +00:00
|
|
|
let gv = addr_of_mut(ccx, cv, align, kind);
|
2015-01-29 12:03:34 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMSetGlobalConstant(gv, True);
|
|
|
|
}
|
|
|
|
ccx.const_globals().borrow_mut().insert(cv, gv);
|
|
|
|
gv
|
|
|
|
}
|
|
|
|
|
2016-08-16 14:41:38 +00:00
|
|
|
pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
|
2016-05-11 21:11:20 +00:00
|
|
|
let instance = Instance::mono(ccx.shared(), def_id);
|
2016-02-23 20:04:27 +00:00
|
|
|
if let Some(&g) = ccx.instances().borrow().get(&instance) {
|
2016-08-16 14:41:38 +00:00
|
|
|
return g;
|
2016-02-23 20:04:27 +00:00
|
|
|
}
|
|
|
|
|
2016-11-10 14:49:53 +00:00
|
|
|
let ty = ccx.tcx().item_type(def_id);
|
2016-02-23 19:39:35 +00:00
|
|
|
let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) {
|
2016-05-26 12:59:58 +00:00
|
|
|
|
2016-03-06 12:17:53 +00:00
|
|
|
let llty = type_of::type_of(ccx, ty);
|
2016-05-07 00:02:09 +00:00
|
|
|
let (g, attrs) = match ccx.tcx().map.get(id) {
|
2016-02-23 19:39:35 +00:00
|
|
|
hir_map::NodeItem(&hir::Item {
|
2016-05-07 00:02:09 +00:00
|
|
|
ref attrs, span, node: hir::ItemStatic(..), ..
|
2016-02-23 19:39:35 +00:00
|
|
|
}) => {
|
2016-05-26 12:59:58 +00:00
|
|
|
let sym = ccx.symbol_map()
|
|
|
|
.get(TransItem::Static(id))
|
|
|
|
.expect("Local statics should always be in the SymbolMap");
|
2016-05-07 00:02:09 +00:00
|
|
|
// Make sure that this is never executed for something inlined.
|
2016-07-29 20:49:26 +00:00
|
|
|
assert!(!ccx.tcx().map.is_inlined_node_id(id));
|
2016-05-07 00:02:09 +00:00
|
|
|
|
|
|
|
let defined_in_current_codegen_unit = ccx.codegen_unit()
|
2016-07-21 16:49:59 +00:00
|
|
|
.items()
|
2016-05-07 00:02:09 +00:00
|
|
|
.contains_key(&TransItem::Static(id));
|
2016-08-17 19:50:55 +00:00
|
|
|
assert!(!defined_in_current_codegen_unit);
|
|
|
|
|
|
|
|
if declare::get_declared_value(ccx, sym).is_some() {
|
|
|
|
span_bug!(span, "trans: Conflicting symbol names for static?");
|
2016-05-07 00:02:09 +00:00
|
|
|
}
|
|
|
|
|
2016-05-26 12:59:58 +00:00
|
|
|
let g = declare::define_global(ccx, sym, llty).unwrap();
|
2016-05-07 00:02:09 +00:00
|
|
|
|
|
|
|
(g, attrs)
|
2016-02-23 19:39:35 +00:00
|
|
|
}
|
|
|
|
|
2016-03-06 12:17:53 +00:00
|
|
|
hir_map::NodeForeignItem(&hir::ForeignItem {
|
2016-05-12 16:52:38 +00:00
|
|
|
ref attrs, span, node: hir::ForeignItemStatic(..), ..
|
2016-03-06 12:17:53 +00:00
|
|
|
}) => {
|
2016-05-26 12:59:58 +00:00
|
|
|
let sym = instance.symbol_name(ccx.shared());
|
2016-03-06 12:17:53 +00:00
|
|
|
let g = if let Some(name) =
|
|
|
|
attr::first_attr_value_str_by_name(&attrs, "linkage") {
|
|
|
|
// If this is a static with a linkage specified, then we need to handle
|
|
|
|
// it a little specially. The typesystem prevents things like &T and
|
|
|
|
// extern "C" fn() from being non-null, so we can't just declare a
|
|
|
|
// static and call it a day. Some linkages (like weak) will make it such
|
|
|
|
// that the static actually has a null value.
|
2016-11-16 10:52:37 +00:00
|
|
|
let linkage = match base::llvm_linkage_by_name(&name.as_str()) {
|
2016-03-06 12:17:53 +00:00
|
|
|
Some(linkage) => linkage,
|
|
|
|
None => {
|
|
|
|
ccx.sess().span_fatal(span, "invalid linkage specified");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let llty2 = match ty.sty {
|
|
|
|
ty::TyRawPtr(ref mt) => type_of::type_of(ccx, mt.ty),
|
|
|
|
_ => {
|
|
|
|
ccx.sess().span_fatal(span, "must have type `*const T` or `*mut T`");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
unsafe {
|
|
|
|
// Declare a symbol `foo` with the desired linkage.
|
2016-05-12 16:52:38 +00:00
|
|
|
let g1 = declare::declare_global(ccx, &sym, llty2);
|
2016-09-01 18:52:33 +00:00
|
|
|
llvm::LLVMRustSetLinkage(g1, linkage);
|
2016-03-06 12:17:53 +00:00
|
|
|
|
|
|
|
// Declare an internal global `extern_with_linkage_foo` which
|
|
|
|
// is initialized with the address of `foo`. If `foo` is
|
|
|
|
// discarded during linking (for example, if `foo` has weak
|
|
|
|
// linkage and there are no definitions), then
|
|
|
|
// `extern_with_linkage_foo` will instead be initialized to
|
|
|
|
// zero.
|
|
|
|
let mut real_name = "_rust_extern_with_linkage_".to_string();
|
2016-05-12 16:52:38 +00:00
|
|
|
real_name.push_str(&sym);
|
2016-03-06 12:17:53 +00:00
|
|
|
let g2 = declare::define_global(ccx, &real_name, llty).unwrap_or_else(||{
|
|
|
|
ccx.sess().span_fatal(span,
|
2016-05-26 12:59:58 +00:00
|
|
|
&format!("symbol `{}` is already defined", &sym))
|
2016-03-06 12:17:53 +00:00
|
|
|
});
|
2016-09-01 18:52:33 +00:00
|
|
|
llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
|
2016-03-06 12:17:53 +00:00
|
|
|
llvm::LLVMSetInitializer(g2, g1);
|
|
|
|
g2
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Generate an external declaration.
|
2016-05-12 16:52:38 +00:00
|
|
|
declare::declare_global(ccx, &sym, llty)
|
2016-03-06 12:17:53 +00:00
|
|
|
};
|
|
|
|
|
2016-05-07 00:02:09 +00:00
|
|
|
(g, attrs)
|
2016-03-06 12:17:53 +00:00
|
|
|
}
|
2016-02-23 19:39:35 +00:00
|
|
|
|
2016-03-28 23:46:02 +00:00
|
|
|
item => bug!("get_static: expected static, found {:?}", item)
|
2016-05-07 00:02:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
for attr in attrs {
|
|
|
|
if attr.check_name("thread_local") {
|
|
|
|
llvm::set_thread_local(g, true);
|
|
|
|
}
|
2016-02-23 19:39:35 +00:00
|
|
|
}
|
2016-05-07 00:02:09 +00:00
|
|
|
|
|
|
|
g
|
2016-02-23 19:39:35 +00:00
|
|
|
} else {
|
2016-05-26 12:59:58 +00:00
|
|
|
let sym = instance.symbol_name(ccx.shared());
|
|
|
|
|
2016-02-23 19:39:35 +00:00
|
|
|
// FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
|
|
|
|
// FIXME(nagisa): investigate whether it can be changed into define_global
|
2016-05-12 16:52:38 +00:00
|
|
|
let g = declare::declare_global(ccx, &sym, type_of::type_of(ccx, ty));
|
2016-02-23 19:39:35 +00:00
|
|
|
// Thread-local statics in some other crate need to *always* be linked
|
|
|
|
// against in a thread-local fashion, so we need to be sure to apply the
|
|
|
|
// thread-local attribute locally if it was present remotely. If we
|
|
|
|
// don't do this then linker errors can be generated where the linker
|
|
|
|
// complains that one object files has a thread local version of the
|
|
|
|
// symbol and another one doesn't.
|
|
|
|
for attr in ccx.tcx().get_attrs(def_id).iter() {
|
|
|
|
if attr.check_name("thread_local") {
|
|
|
|
llvm::set_thread_local(g, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ccx.use_dll_storage_attrs() {
|
2016-08-02 21:25:19 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport);
|
|
|
|
}
|
2016-02-23 19:39:35 +00:00
|
|
|
}
|
|
|
|
g
|
|
|
|
};
|
|
|
|
|
2016-02-23 20:04:27 +00:00
|
|
|
ccx.instances().borrow_mut().insert(instance, g);
|
2016-04-21 13:15:56 +00:00
|
|
|
ccx.statics().borrow_mut().insert(g, def_id);
|
2016-08-16 14:41:38 +00:00
|
|
|
g
|
2016-02-23 19:39:35 +00:00
|
|
|
}
|
|
|
|
|
2015-06-28 17:36:46 +00:00
|
|
|
pub fn trans_static(ccx: &CrateContext,
|
2015-07-31 07:04:06 +00:00
|
|
|
m: hir::Mutability,
|
2015-06-28 17:36:46 +00:00
|
|
|
id: ast::NodeId,
|
2015-12-17 17:41:28 +00:00
|
|
|
attrs: &[ast::Attribute])
|
2015-10-02 08:36:45 +00:00
|
|
|
-> Result<ValueRef, ConstEvalErr> {
|
2013-01-11 05:23:07 +00:00
|
|
|
unsafe {
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 15:17:01 +00:00
|
|
|
let _icx = push_ctxt("trans_static");
|
2016-02-23 19:39:35 +00:00
|
|
|
let def_id = ccx.tcx().map.local_def_id(id);
|
2016-08-16 14:41:38 +00:00
|
|
|
let g = get_static(ccx, def_id);
|
2015-06-28 17:36:46 +00:00
|
|
|
|
2016-08-16 14:41:38 +00:00
|
|
|
let v = ::mir::trans_static_initializer(ccx, def_id)?;
|
2015-06-28 17:36:46 +00:00
|
|
|
|
2014-10-08 21:20:18 +00:00
|
|
|
// boolean SSA values are i1, but they have to be stored in i8 slots,
|
|
|
|
// otherwise some LLVM optimization passes don't work as expected
|
2016-02-23 19:39:35 +00:00
|
|
|
let mut val_llty = val_ty(v);
|
|
|
|
let v = if val_llty == Type::i1(ccx) {
|
|
|
|
val_llty = Type::i8(ccx);
|
|
|
|
llvm::LLVMConstZExt(v, val_llty.to_ref())
|
2014-10-08 21:20:18 +00:00
|
|
|
} else {
|
|
|
|
v
|
|
|
|
};
|
2015-06-28 17:36:46 +00:00
|
|
|
|
2016-11-10 14:49:53 +00:00
|
|
|
let ty = ccx.tcx().item_type(def_id);
|
2016-08-16 14:41:38 +00:00
|
|
|
let llty = type_of::type_of(ccx, ty);
|
2016-02-23 19:39:35 +00:00
|
|
|
let g = if val_llty == llty {
|
2016-08-16 14:41:38 +00:00
|
|
|
g
|
2015-06-28 17:36:46 +00:00
|
|
|
} else {
|
|
|
|
// If we created the global with the wrong type,
|
|
|
|
// correct the type.
|
|
|
|
let empty_string = CString::new("").unwrap();
|
2016-08-16 14:41:38 +00:00
|
|
|
let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g));
|
2015-06-28 17:36:46 +00:00
|
|
|
let name_string = CString::new(name_str_ref.to_bytes()).unwrap();
|
2016-08-16 14:41:38 +00:00
|
|
|
llvm::LLVMSetValueName(g, empty_string.as_ptr());
|
2016-08-01 23:35:09 +00:00
|
|
|
let new_g = llvm::LLVMRustGetOrInsertGlobal(
|
2016-02-23 19:39:35 +00:00
|
|
|
ccx.llmod(), name_string.as_ptr(), val_llty.to_ref());
|
2015-06-28 17:36:46 +00:00
|
|
|
// To avoid breaking any invariants, we leave around the old
|
|
|
|
// global for the moment; we'll replace all references to it
|
|
|
|
// with the new global later. (See base::trans_crate.)
|
2016-08-16 14:41:38 +00:00
|
|
|
ccx.statics_to_rauw().borrow_mut().push((g, new_g));
|
2015-06-28 17:36:46 +00:00
|
|
|
new_g
|
|
|
|
};
|
2016-08-16 14:41:38 +00:00
|
|
|
llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty));
|
2013-01-11 05:23:07 +00:00
|
|
|
llvm::LLVMSetInitializer(g, v);
|
2014-07-21 23:42:34 +00:00
|
|
|
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 15:17:01 +00:00
|
|
|
// As an optimization, all shared statics which do not have interior
|
|
|
|
// mutability are placed into read-only memory.
|
2015-07-31 07:04:06 +00:00
|
|
|
if m != hir::MutMutable {
|
2016-08-16 14:41:38 +00:00
|
|
|
let tcontents = ty.type_contents(ccx.tcx());
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 15:17:01 +00:00
|
|
|
if !tcontents.interior_unsafe() {
|
2015-06-28 17:36:46 +00:00
|
|
|
llvm::LLVMSetGlobalConstant(g, llvm::True);
|
rustc: Add `const` globals to the language
This change is an implementation of [RFC 69][rfc] which adds a third kind of
global to the language, `const`. This global is most similar to what the old
`static` was, and if you're unsure about what to use then you should use a
`const`.
The semantics of these three kinds of globals are:
* A `const` does not represent a memory location, but only a value. Constants
are translated as rvalues, which means that their values are directly inlined
at usage location (similar to a #define in C/C++). Constant values are, well,
constant, and can not be modified. Any "modification" is actually a
modification to a local value on the stack rather than the actual constant
itself.
Almost all values are allowed inside constants, whether they have interior
mutability or not. There are a few minor restrictions listed in the RFC, but
they should in general not come up too often.
* A `static` now always represents a memory location (unconditionally). Any
references to the same `static` are actually a reference to the same memory
location. Only values whose types ascribe to `Sync` are allowed in a `static`.
This restriction is in place because many threads may access a `static`
concurrently. Lifting this restriction (and allowing unsafe access) is a
future extension not implemented at this time.
* A `static mut` continues to always represent a memory location. All references
to a `static mut` continue to be `unsafe`.
This is a large breaking change, and many programs will need to be updated
accordingly. A summary of the breaking changes is:
* Statics may no longer be used in patterns. Statics now always represent a
memory location, which can sometimes be modified. To fix code, repurpose the
matched-on-`static` to a `const`.
static FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
change this code to:
const FOO: uint = 4;
match n {
FOO => { /* ... */ }
_ => { /* ... */ }
}
* Statics may no longer refer to other statics by value. Due to statics being
able to change at runtime, allowing them to reference one another could
possibly lead to confusing semantics. If you are in this situation, use a
constant initializer instead. Note, however, that statics may reference other
statics by address, however.
* Statics may no longer be used in constant expressions, such as array lengths.
This is due to the same restrictions as listed above. Use a `const` instead.
[breaking-change]
[rfc]: https://github.com/rust-lang/rfcs/pull/246
2014-10-06 15:17:01 +00:00
|
|
|
}
|
2013-06-22 01:46:34 +00:00
|
|
|
}
|
2015-06-28 17:36:46 +00:00
|
|
|
|
2014-02-21 01:44:29 +00:00
|
|
|
debuginfo::create_global_var_metadata(ccx, id, g);
|
2015-06-28 17:36:46 +00:00
|
|
|
|
|
|
|
if attr::contains_name(attrs,
|
|
|
|
"thread_local") {
|
|
|
|
llvm::set_thread_local(g, true);
|
|
|
|
}
|
2016-05-07 00:02:09 +00:00
|
|
|
|
|
|
|
base::set_link_section(ccx, g, attrs);
|
|
|
|
|
2015-10-02 08:36:45 +00:00
|
|
|
Ok(g)
|
2013-01-11 05:23:07 +00:00
|
|
|
}
|
2012-08-01 01:34:36 +00:00
|
|
|
}
|