Skip to content

Commit 90d03d7

Browse files
committed
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]: rust-lang/rfcs#246
1 parent a89ad58 commit 90d03d7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+721
-445
lines changed

src/librustc/lint/builtin.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,8 @@ impl LintPass for NonUppercaseStatics {
978978
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
979979
match it.node {
980980
// only check static constants
981-
ast::ItemStatic(_, ast::MutImmutable, _) => {
981+
ast::ItemStatic(_, ast::MutImmutable, _) |
982+
ast::ItemConst(..) => {
982983
let s = token::get_ident(it.ident);
983984
// check for lowercase letters rather than non-uppercase
984985
// ones (some scripts don't have a concept of
@@ -998,7 +999,7 @@ impl LintPass for NonUppercaseStatics {
998999
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
9991000
// Lint for constants that look like binding identifiers (#7526)
10001001
match (&p.node, cx.tcx.def_map.borrow().find(&p.id)) {
1001-
(&ast::PatIdent(_, ref path1, _), Some(&def::DefStatic(_, false))) => {
1002+
(&ast::PatIdent(_, ref path1, _), Some(&def::DefConst(..))) => {
10021003
let s = token::get_ident(path1.node);
10031004
if s.get().chars().any(|c| c.is_lowercase()) {
10041005
cx.span_lint(NON_UPPERCASE_STATICS, path1.span,

src/librustc/metadata/decoder.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,14 @@ enum Family {
126126
Trait, // I
127127
Struct, // S
128128
PublicField, // g
129-
InheritedField // N
129+
InheritedField, // N
130+
Constant, // C
130131
}
131132

132133
fn item_family(item: rbml::Doc) -> Family {
133134
let fam = reader::get_doc(item, tag_items_data_item_family);
134135
match reader::doc_as_u8(fam) as char {
136+
'C' => Constant,
135137
'c' => ImmStatic,
136138
'b' => MutStatic,
137139
'f' => Fn,
@@ -303,6 +305,7 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
303305
-> DefLike {
304306
let fam = item_family(item);
305307
match fam {
308+
Constant => DlDef(def::DefConst(did)),
306309
ImmStatic => DlDef(def::DefStatic(did, false)),
307310
MutStatic => DlDef(def::DefStatic(did, true)),
308311
Struct => DlDef(def::DefStruct(did)),

src/librustc/metadata/encoder.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ pub struct EncodeParams<'a, 'tcx: 'a> {
6969
pub tcx: &'a ty::ctxt<'tcx>,
7070
pub reexports2: &'a middle::resolve::ExportMap2,
7171
pub item_symbols: &'a RefCell<NodeMap<String>>,
72-
pub non_inlineable_statics: &'a RefCell<NodeSet>,
7372
pub link_meta: &'a LinkMeta,
7473
pub cstore: &'a cstore::CStore,
7574
pub encode_inlined_item: EncodeInlinedItem<'a>,
@@ -81,7 +80,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
8180
pub tcx: &'a ty::ctxt<'tcx>,
8281
pub reexports2: &'a middle::resolve::ExportMap2,
8382
pub item_symbols: &'a RefCell<NodeMap<String>>,
84-
pub non_inlineable_statics: &'a RefCell<NodeSet>,
8583
pub link_meta: &'a LinkMeta,
8684
pub cstore: &'a cstore::CStore,
8785
pub encode_inlined_item: RefCell<EncodeInlinedItem<'a>>,
@@ -1069,12 +1067,20 @@ fn encode_info_for_item(ecx: &EncodeContext,
10691067
encode_symbol(ecx, rbml_w, item.id);
10701068
encode_name(rbml_w, item.ident.name);
10711069
encode_path(rbml_w, path);
1072-
1073-
let inlineable = !ecx.non_inlineable_statics.borrow().contains(&item.id);
1074-
1075-
if inlineable {
1076-
encode_inlined_item(ecx, rbml_w, IIItemRef(item));
1077-
}
1070+
encode_visibility(rbml_w, vis);
1071+
encode_stability(rbml_w, stab);
1072+
encode_attributes(rbml_w, item.attrs.as_slice());
1073+
rbml_w.end_tag();
1074+
}
1075+
ItemConst(_, _) => {
1076+
add_to_index(item, rbml_w, index);
1077+
rbml_w.start_tag(tag_items_data_item);
1078+
encode_def_id(rbml_w, def_id);
1079+
encode_family(rbml_w, 'C');
1080+
encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
1081+
encode_name(rbml_w, item.ident.name);
1082+
encode_path(rbml_w, path);
1083+
encode_inlined_item(ecx, rbml_w, IIItemRef(item));
10781084
encode_visibility(rbml_w, vis);
10791085
encode_stability(rbml_w, stab);
10801086
rbml_w.end_tag();
@@ -2076,7 +2082,6 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter, parms: EncodeParams, krate:
20762082
cstore,
20772083
encode_inlined_item,
20782084
link_meta,
2079-
non_inlineable_statics,
20802085
reachable,
20812086
..
20822087
} = parms;
@@ -2085,7 +2090,6 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter, parms: EncodeParams, krate:
20852090
tcx: tcx,
20862091
reexports2: reexports2,
20872092
item_symbols: item_symbols,
2088-
non_inlineable_statics: non_inlineable_statics,
20892093
link_meta: link_meta,
20902094
cstore: cstore,
20912095
encode_inlined_item: RefCell::new(encode_inlined_item),

src/librustc/middle/astencode.rs

+1
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ impl tr for def::Def {
460460
def::DefMod(did) => { def::DefMod(did.tr(dcx)) }
461461
def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
462462
def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
463+
def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
463464
def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
464465
def::DefVariant(e_did, v_did, is_s) => {
465466
def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)

src/librustc/middle/borrowck/gather_loans/mod.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,11 @@ fn check_aliasability(bccx: &BorrowckCtxt,
169169
// Borrow of an immutable static item:
170170
match safety {
171171
mc::InteriorUnsafe => {
172-
// If the static item contains an Unsafe<T>, it has interior mutability.
173-
// In such cases, we cannot permit it to be borrowed, because the
174-
// static item resides in immutable memory and mutating it would
175-
// cause segfaults.
176-
bccx.tcx.sess.span_err(borrow_span,
177-
"borrow of immutable static items \
178-
with unsafe interior is not \
179-
allowed");
180-
Err(())
172+
// If the static item contains an Unsafe<T>, it has interior
173+
// mutability. In such cases, another phase of the compiler
174+
// will ensure that the type is `Sync` and then trans will
175+
// not put it in rodata, so this is ok to allow.
176+
Ok(())
181177
}
182178
mc::InteriorSafe => {
183179
// Immutable static can be borrowed, no problem.

src/librustc/middle/borrowck/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ fn borrowck_item(this: &mut BorrowckCtxt, item: &ast::Item) {
106106
// loan step is intended for things that have a data
107107
// flow dependent conditions.
108108
match item.node {
109-
ast::ItemStatic(_, _, ref ex) => {
109+
ast::ItemStatic(_, _, ref ex) |
110+
ast::ItemConst(_, ref ex) => {
110111
gather_loans::gather_loans_in_static_initializer(this, &**ex);
111112
}
112113
_ => {

src/librustc/middle/check_const.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
4848
}
4949
fn visit_expr(&mut self, ex: &Expr) {
5050
if check_expr(self, ex) {
51-
visit::walk_expr(v, e);
51+
visit::walk_expr(self, ex);
5252
}
5353
}
5454
}
@@ -61,7 +61,8 @@ pub fn check_crate(tcx: &ty::ctxt) {
6161

6262
fn check_item(v: &mut CheckCrateVisitor, it: &Item) {
6363
match it.node {
64-
ItemStatic(_, _, ref ex) => {
64+
ItemStatic(_, _, ref ex) |
65+
ItemConst(_, ref ex) => {
6566
v.inside_const(|v| v.visit_expr(&**ex));
6667
}
6768
ItemEnum(ref enum_definition, _) => {
@@ -138,6 +139,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) -> bool {
138139
}
139140
match v.tcx.def_map.borrow().find(&e.id) {
140141
Some(&DefStatic(..)) |
142+
Some(&DefConst(..)) |
141143
Some(&DefFn(..)) |
142144
Some(&DefVariant(_, _, _)) |
143145
Some(&DefStruct(_)) => { }
@@ -190,7 +192,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) -> bool {
190192
}
191193
}
192194
match block.expr {
193-
Some(ref expr) => check_expr(v, &**expr),
195+
Some(ref expr) => { check_expr(v, &**expr); }
194196
None => {}
195197
}
196198
}

src/librustc/middle/check_match.rs

+37-27
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use syntax::ptr::P;
3232
use syntax::visit::{mod, Visitor, FnKind};
3333
use util::ppaux::ty_to_string;
3434

35-
static DUMMY_WILD_PAT: Pat = Pat {
35+
pub const DUMMY_WILD_PAT: Pat = Pat {
3636
id: DUMMY_NODE_ID,
3737
node: PatWild(PatWildSingle),
3838
span: DUMMY_SP
@@ -299,9 +299,10 @@ fn raw_pat<'a>(p: &'a Pat) -> &'a Pat {
299299
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix) {
300300
match is_useful(cx, matrix, &[&DUMMY_WILD_PAT], ConstructWitness) {
301301
UsefulWithWitness(pats) => {
302+
let dummy = DUMMY_WILD_PAT.clone();
302303
let witness = match pats.as_slice() {
303304
[ref witness] => &**witness,
304-
[] => &DUMMY_WILD_PAT,
305+
[] => &dummy,
305306
_ => unreachable!()
306307
};
307308
span_err!(cx.tcx.sess, sp, E0004,
@@ -349,7 +350,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
349350
PatIdent(..) | PatEnum(..) => {
350351
let def = self.tcx.def_map.borrow().find_copy(&pat.id);
351352
match def {
352-
Some(DefStatic(did, _)) => match lookup_const_by_id(self.tcx, did) {
353+
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
353354
Some(const_expr) => {
354355
const_expr_to_pat(self.tcx, const_expr).map(|mut new_pat| {
355356
new_pat.span = pat.span;
@@ -359,7 +360,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
359360
None => {
360361
self.failed = true;
361362
span_err!(self.tcx.sess, pat.span, E0158,
362-
"extern statics cannot be referenced in patterns");
363+
"statics cannot be referenced in patterns");
363364
pat
364365
}
365366
},
@@ -555,8 +556,9 @@ fn is_useful(cx: &MatchCheckCtxt,
555556
let arity = constructor_arity(cx, &c, left_ty);
556557
let mut result = {
557558
let pat_slice = pats.as_slice();
559+
let dummy = DUMMY_WILD_PAT.clone();
558560
let subpats = Vec::from_fn(arity, |i| {
559-
pat_slice.get(i).map_or(&DUMMY_WILD_PAT, |p| &**p)
561+
pat_slice.get(i).map_or(&dummy, |p| &**p)
560562
});
561563
vec![construct_witness(cx, &c, subpats, left_ty)]
562564
};
@@ -578,8 +580,9 @@ fn is_useful(cx: &MatchCheckCtxt,
578580
}).collect();
579581
match is_useful(cx, &matrix, v.tail(), witness) {
580582
UsefulWithWitness(pats) => {
583+
let dummy = DUMMY_WILD_PAT.clone();
581584
let arity = constructor_arity(cx, &constructor, left_ty);
582-
let wild_pats = Vec::from_elem(arity, &DUMMY_WILD_PAT);
585+
let wild_pats = Vec::from_elem(arity, &dummy);
583586
let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
584587
let mut new_pats = vec![enum_pat];
585588
new_pats.extend(pats.into_iter());
@@ -600,10 +603,11 @@ fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix,
600603
v: &[&Pat], ctor: Constructor, lty: ty::t,
601604
witness: WitnessPreference) -> Usefulness {
602605
let arity = constructor_arity(cx, &ctor, lty);
606+
let dummy = DUMMY_WILD_PAT.clone();
603607
let matrix = Matrix(m.iter().filter_map(|r| {
604-
specialize(cx, r.as_slice(), &ctor, 0u, arity)
608+
specialize(cx, r.as_slice(), &dummy, &ctor, 0u, arity)
605609
}).collect());
606-
match specialize(cx, v, &ctor, 0u, arity) {
610+
match specialize(cx, v, &dummy, &ctor, 0u, arity) {
607611
Some(v) => is_useful(cx, &matrix, v.as_slice(), witness),
608612
None => NotUseful
609613
}
@@ -624,23 +628,26 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
624628
match pat.node {
625629
PatIdent(..) =>
626630
match cx.tcx.def_map.borrow().find(&pat.id) {
627-
Some(&DefStatic(..)) =>
628-
cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
631+
Some(&DefConst(..)) =>
632+
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
633+
been rewritten"),
629634
Some(&DefStruct(_)) => vec!(Single),
630635
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
631636
_ => vec!()
632637
},
633638
PatEnum(..) =>
634639
match cx.tcx.def_map.borrow().find(&pat.id) {
635-
Some(&DefStatic(..)) =>
636-
cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
640+
Some(&DefConst(..)) =>
641+
cx.tcx.sess.span_bug(pat.span, "static pattern should've \
642+
been rewritten"),
637643
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
638644
_ => vec!(Single)
639645
},
640646
PatStruct(..) =>
641647
match cx.tcx.def_map.borrow().find(&pat.id) {
642-
Some(&DefStatic(..)) =>
643-
cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
648+
Some(&DefConst(..)) =>
649+
cx.tcx.sess.span_bug(pat.span, "static pattern should've \
650+
been rewritten"),
644651
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
645652
_ => vec!(Single)
646653
},
@@ -722,40 +729,42 @@ fn range_covered_by_constructor(ctor: &Constructor,
722729
/// different patterns.
723730
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
724731
/// fields filled with wild patterns.
725-
pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
732+
pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], dummy: &'a Pat,
726733
constructor: &Constructor, col: uint, arity: uint) -> Option<Vec<&'a Pat>> {
727734
let &Pat {
728735
id: pat_id, node: ref node, span: pat_span
729736
} = raw_pat(r[col]);
730737
let head: Option<Vec<&Pat>> = match node {
731738

732739
&PatWild(_) =>
733-
Some(Vec::from_elem(arity, &DUMMY_WILD_PAT)),
740+
Some(Vec::from_elem(arity, dummy)),
734741

735742
&PatIdent(_, _, _) => {
736743
let opt_def = cx.tcx.def_map.borrow().find_copy(&pat_id);
737744
match opt_def {
738-
Some(DefStatic(..)) =>
739-
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
745+
Some(DefConst(..)) =>
746+
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
747+
been rewritten"),
740748
Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
741749
Some(vec!())
742750
} else {
743751
None
744752
},
745-
_ => Some(Vec::from_elem(arity, &DUMMY_WILD_PAT))
753+
_ => Some(Vec::from_elem(arity, dummy))
746754
}
747755
}
748756

749757
&PatEnum(_, ref args) => {
750758
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
751759
match def {
752-
DefStatic(..) =>
753-
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
760+
DefConst(..) =>
761+
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
762+
been rewritten"),
754763
DefVariant(_, id, _) if *constructor != Variant(id) => None,
755764
DefVariant(..) | DefStruct(..) => {
756765
Some(match args {
757766
&Some(ref args) => args.iter().map(|p| &**p).collect(),
758-
&None => Vec::from_elem(arity, &DUMMY_WILD_PAT)
767+
&None => Vec::from_elem(arity, dummy)
759768
})
760769
}
761770
_ => None
@@ -766,8 +775,9 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
766775
// Is this a struct or an enum variant?
767776
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
768777
let class_id = match def {
769-
DefStatic(..) =>
770-
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
778+
DefConst(..) =>
779+
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
780+
been rewritten"),
771781
DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
772782
Some(variant_id)
773783
} else {
@@ -790,7 +800,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
790800
let args = struct_fields.iter().map(|sf| {
791801
match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
792802
Some(ref f) => &*f.pat,
793-
_ => &DUMMY_WILD_PAT
803+
_ => dummy
794804
}
795805
}).collect();
796806
args
@@ -833,13 +843,13 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
833843
// Fixed-length vectors.
834844
Single => {
835845
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
836-
pats.grow_fn(arity - before.len() - after.len(), |_| &DUMMY_WILD_PAT);
846+
pats.grow_fn(arity - before.len() - after.len(), |_| dummy);
837847
pats.extend(after.iter().map(|p| &**p));
838848
Some(pats)
839849
},
840850
Slice(length) if before.len() + after.len() <= length && slice.is_some() => {
841851
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
842-
pats.grow_fn(arity - before.len() - after.len(), |_| &DUMMY_WILD_PAT);
852+
pats.grow_fn(arity - before.len() - after.len(), |_| dummy);
843853
pats.extend(after.iter().map(|p| &**p));
844854
Some(pats)
845855
},

0 commit comments

Comments
 (0)