提交 90d03d79 编写于 作者: A Alex Crichton

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
上级 a89ad587
......@@ -978,7 +978,8 @@ fn get_lints(&self) -> LintArray {
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
match it.node {
// only check static constants
ast::ItemStatic(_, ast::MutImmutable, _) => {
ast::ItemStatic(_, ast::MutImmutable, _) |
ast::ItemConst(..) => {
let s = token::get_ident(it.ident);
// check for lowercase letters rather than non-uppercase
// ones (some scripts don't have a concept of
......@@ -998,7 +999,7 @@ fn check_item(&mut self, cx: &Context, it: &ast::Item) {
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
// Lint for constants that look like binding identifiers (#7526)
match (&p.node, cx.tcx.def_map.borrow().find(&p.id)) {
(&ast::PatIdent(_, ref path1, _), Some(&def::DefStatic(_, false))) => {
(&ast::PatIdent(_, ref path1, _), Some(&def::DefConst(..))) => {
let s = token::get_ident(path1.node);
if s.get().chars().any(|c| c.is_lowercase()) {
cx.span_lint(NON_UPPERCASE_STATICS, path1.span,
......
......@@ -126,12 +126,14 @@ enum Family {
Trait, // I
Struct, // S
PublicField, // g
InheritedField // N
InheritedField, // N
Constant, // C
}
fn item_family(item: rbml::Doc) -> Family {
let fam = reader::get_doc(item, tag_items_data_item_family);
match reader::doc_as_u8(fam) as char {
'C' => Constant,
'c' => ImmStatic,
'b' => MutStatic,
'f' => Fn,
......@@ -303,6 +305,7 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
-> DefLike {
let fam = item_family(item);
match fam {
Constant => DlDef(def::DefConst(did)),
ImmStatic => DlDef(def::DefStatic(did, false)),
MutStatic => DlDef(def::DefStatic(did, true)),
Struct => DlDef(def::DefStruct(did)),
......
......@@ -69,7 +69,6 @@ pub struct EncodeParams<'a, 'tcx: 'a> {
pub tcx: &'a ty::ctxt<'tcx>,
pub reexports2: &'a middle::resolve::ExportMap2,
pub item_symbols: &'a RefCell<NodeMap<String>>,
pub non_inlineable_statics: &'a RefCell<NodeSet>,
pub link_meta: &'a LinkMeta,
pub cstore: &'a cstore::CStore,
pub encode_inlined_item: EncodeInlinedItem<'a>,
......@@ -81,7 +80,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
pub tcx: &'a ty::ctxt<'tcx>,
pub reexports2: &'a middle::resolve::ExportMap2,
pub item_symbols: &'a RefCell<NodeMap<String>>,
pub non_inlineable_statics: &'a RefCell<NodeSet>,
pub link_meta: &'a LinkMeta,
pub cstore: &'a cstore::CStore,
pub encode_inlined_item: RefCell<EncodeInlinedItem<'a>>,
......@@ -1069,12 +1067,20 @@ fn add_to_index(item: &Item, rbml_w: &Encoder,
encode_symbol(ecx, rbml_w, item.id);
encode_name(rbml_w, item.ident.name);
encode_path(rbml_w, path);
let inlineable = !ecx.non_inlineable_statics.borrow().contains(&item.id);
if inlineable {
encode_inlined_item(ecx, rbml_w, IIItemRef(item));
}
encode_visibility(rbml_w, vis);
encode_stability(rbml_w, stab);
encode_attributes(rbml_w, item.attrs.as_slice());
rbml_w.end_tag();
}
ItemConst(_, _) => {
add_to_index(item, rbml_w, index);
rbml_w.start_tag(tag_items_data_item);
encode_def_id(rbml_w, def_id);
encode_family(rbml_w, 'C');
encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(rbml_w, item.ident.name);
encode_path(rbml_w, path);
encode_inlined_item(ecx, rbml_w, IIItemRef(item));
encode_visibility(rbml_w, vis);
encode_stability(rbml_w, stab);
rbml_w.end_tag();
......@@ -2076,7 +2082,6 @@ struct Stats {
cstore,
encode_inlined_item,
link_meta,
non_inlineable_statics,
reachable,
..
} = parms;
......@@ -2085,7 +2090,6 @@ struct Stats {
tcx: tcx,
reexports2: reexports2,
item_symbols: item_symbols,
non_inlineable_statics: non_inlineable_statics,
link_meta: link_meta,
cstore: cstore,
encode_inlined_item: RefCell::new(encode_inlined_item),
......
......@@ -460,6 +460,7 @@ fn tr(&self, dcx: &DecodeContext) -> def::Def {
def::DefMod(did) => { def::DefMod(did.tr(dcx)) }
def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
def::DefVariant(e_did, v_did, is_s) => {
def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
......
......@@ -169,15 +169,11 @@ fn check_aliasability(bccx: &BorrowckCtxt,
// Borrow of an immutable static item:
match safety {
mc::InteriorUnsafe => {
// If the static item contains an Unsafe<T>, it has interior mutability.
// In such cases, we cannot permit it to be borrowed, because the
// static item resides in immutable memory and mutating it would
// cause segfaults.
bccx.tcx.sess.span_err(borrow_span,
"borrow of immutable static items \
with unsafe interior is not \
allowed");
Err(())
// If the static item contains an Unsafe<T>, it has interior
// mutability. In such cases, another phase of the compiler
// will ensure that the type is `Sync` and then trans will
// not put it in rodata, so this is ok to allow.
Ok(())
}
mc::InteriorSafe => {
// Immutable static can be borrowed, no problem.
......
......@@ -106,7 +106,8 @@ fn borrowck_item(this: &mut BorrowckCtxt, item: &ast::Item) {
// loan step is intended for things that have a data
// flow dependent conditions.
match item.node {
ast::ItemStatic(_, _, ref ex) => {
ast::ItemStatic(_, _, ref ex) |
ast::ItemConst(_, ref ex) => {
gather_loans::gather_loans_in_static_initializer(this, &**ex);
}
_ => {
......
......@@ -48,7 +48,7 @@ fn visit_pat(&mut self, p: &Pat) {
}
fn visit_expr(&mut self, ex: &Expr) {
if check_expr(self, ex) {
visit::walk_expr(v, e);
visit::walk_expr(self, ex);
}
}
}
......@@ -61,7 +61,8 @@ pub fn check_crate(tcx: &ty::ctxt) {
fn check_item(v: &mut CheckCrateVisitor, it: &Item) {
match it.node {
ItemStatic(_, _, ref ex) => {
ItemStatic(_, _, ref ex) |
ItemConst(_, ref ex) => {
v.inside_const(|v| v.visit_expr(&**ex));
}
ItemEnum(ref enum_definition, _) => {
......@@ -138,6 +139,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) -> bool {
}
match v.tcx.def_map.borrow().find(&e.id) {
Some(&DefStatic(..)) |
Some(&DefConst(..)) |
Some(&DefFn(..)) |
Some(&DefVariant(_, _, _)) |
Some(&DefStruct(_)) => { }
......@@ -190,7 +192,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) -> bool {
}
}
match block.expr {
Some(ref expr) => check_expr(v, &**expr),
Some(ref expr) => { check_expr(v, &**expr); }
None => {}
}
}
......
......@@ -32,7 +32,7 @@
use syntax::visit::{mod, Visitor, FnKind};
use util::ppaux::ty_to_string;
static DUMMY_WILD_PAT: Pat = Pat {
pub const DUMMY_WILD_PAT: Pat = Pat {
id: DUMMY_NODE_ID,
node: PatWild(PatWildSingle),
span: DUMMY_SP
......@@ -299,9 +299,10 @@ fn raw_pat<'a>(p: &'a Pat) -> &'a Pat {
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix) {
match is_useful(cx, matrix, &[&DUMMY_WILD_PAT], ConstructWitness) {
UsefulWithWitness(pats) => {
let dummy = DUMMY_WILD_PAT.clone();
let witness = match pats.as_slice() {
[ref witness] => &**witness,
[] => &DUMMY_WILD_PAT,
[] => &dummy,
_ => unreachable!()
};
span_err!(cx.tcx.sess, sp, E0004,
......@@ -349,7 +350,7 @@ fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
PatIdent(..) | PatEnum(..) => {
let def = self.tcx.def_map.borrow().find_copy(&pat.id);
match def {
Some(DefStatic(did, _)) => match lookup_const_by_id(self.tcx, did) {
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
Some(const_expr) => {
const_expr_to_pat(self.tcx, const_expr).map(|mut new_pat| {
new_pat.span = pat.span;
......@@ -359,7 +360,7 @@ fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
None => {
self.failed = true;
span_err!(self.tcx.sess, pat.span, E0158,
"extern statics cannot be referenced in patterns");
"statics cannot be referenced in patterns");
pat
}
},
......@@ -555,8 +556,9 @@ fn is_useful(cx: &MatchCheckCtxt,
let arity = constructor_arity(cx, &c, left_ty);
let mut result = {
let pat_slice = pats.as_slice();
let dummy = DUMMY_WILD_PAT.clone();
let subpats = Vec::from_fn(arity, |i| {
pat_slice.get(i).map_or(&DUMMY_WILD_PAT, |p| &**p)
pat_slice.get(i).map_or(&dummy, |p| &**p)
});
vec![construct_witness(cx, &c, subpats, left_ty)]
};
......@@ -578,8 +580,9 @@ fn is_useful(cx: &MatchCheckCtxt,
}).collect();
match is_useful(cx, &matrix, v.tail(), witness) {
UsefulWithWitness(pats) => {
let dummy = DUMMY_WILD_PAT.clone();
let arity = constructor_arity(cx, &constructor, left_ty);
let wild_pats = Vec::from_elem(arity, &DUMMY_WILD_PAT);
let wild_pats = Vec::from_elem(arity, &dummy);
let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
let mut new_pats = vec![enum_pat];
new_pats.extend(pats.into_iter());
......@@ -600,10 +603,11 @@ fn is_useful_specialized(cx: &MatchCheckCtxt, &Matrix(ref m): &Matrix,
v: &[&Pat], ctor: Constructor, lty: ty::t,
witness: WitnessPreference) -> Usefulness {
let arity = constructor_arity(cx, &ctor, lty);
let dummy = DUMMY_WILD_PAT.clone();
let matrix = Matrix(m.iter().filter_map(|r| {
specialize(cx, r.as_slice(), &ctor, 0u, arity)
specialize(cx, r.as_slice(), &dummy, &ctor, 0u, arity)
}).collect());
match specialize(cx, v, &ctor, 0u, arity) {
match specialize(cx, v, &dummy, &ctor, 0u, arity) {
Some(v) => is_useful(cx, &matrix, v.as_slice(), witness),
None => NotUseful
}
......@@ -624,23 +628,26 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
match pat.node {
PatIdent(..) =>
match cx.tcx.def_map.borrow().find(&pat.id) {
Some(&DefStatic(..)) =>
cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
Some(&DefConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
been rewritten"),
Some(&DefStruct(_)) => vec!(Single),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!()
},
PatEnum(..) =>
match cx.tcx.def_map.borrow().find(&pat.id) {
Some(&DefStatic(..)) =>
cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
Some(&DefConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "static pattern should've \
been rewritten"),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
PatStruct(..) =>
match cx.tcx.def_map.borrow().find(&pat.id) {
Some(&DefStatic(..)) =>
cx.tcx.sess.span_bug(pat.span, "static pattern should've been rewritten"),
Some(&DefConst(..)) =>
cx.tcx.sess.span_bug(pat.span, "static pattern should've \
been rewritten"),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!(Single)
},
......@@ -722,7 +729,7 @@ fn range_covered_by_constructor(ctor: &Constructor,
/// different patterns.
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
/// fields filled with wild patterns.
pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], dummy: &'a Pat,
constructor: &Constructor, col: uint, arity: uint) -> Option<Vec<&'a Pat>> {
let &Pat {
id: pat_id, node: ref node, span: pat_span
......@@ -730,32 +737,34 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
let head: Option<Vec<&Pat>> = match node {
&PatWild(_) =>
Some(Vec::from_elem(arity, &DUMMY_WILD_PAT)),
Some(Vec::from_elem(arity, dummy)),
&PatIdent(_, _, _) => {
let opt_def = cx.tcx.def_map.borrow().find_copy(&pat_id);
match opt_def {
Some(DefStatic(..)) =>
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
Some(DefConst(..)) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
Some(vec!())
} else {
None
},
_ => Some(Vec::from_elem(arity, &DUMMY_WILD_PAT))
_ => Some(Vec::from_elem(arity, dummy))
}
}
&PatEnum(_, ref args) => {
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
match def {
DefStatic(..) =>
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
DefConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
DefVariant(_, id, _) if *constructor != Variant(id) => None,
DefVariant(..) | DefStruct(..) => {
Some(match args {
&Some(ref args) => args.iter().map(|p| &**p).collect(),
&None => Vec::from_elem(arity, &DUMMY_WILD_PAT)
&None => Vec::from_elem(arity, dummy)
})
}
_ => None
......@@ -766,8 +775,9 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
// Is this a struct or an enum variant?
let def = cx.tcx.def_map.borrow().get_copy(&pat_id);
let class_id = match def {
DefStatic(..) =>
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
DefConst(..) =>
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
been rewritten"),
DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
Some(variant_id)
} else {
......@@ -790,7 +800,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
let args = struct_fields.iter().map(|sf| {
match pattern_fields.iter().find(|f| f.ident.name == sf.name) {
Some(ref f) => &*f.pat,
_ => &DUMMY_WILD_PAT
_ => dummy
}
}).collect();
args
......@@ -833,13 +843,13 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
// Fixed-length vectors.
Single => {
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
pats.grow_fn(arity - before.len() - after.len(), |_| &DUMMY_WILD_PAT);
pats.grow_fn(arity - before.len() - after.len(), |_| dummy);
pats.extend(after.iter().map(|p| &**p));
Some(pats)
},
Slice(length) if before.len() + after.len() <= length && slice.is_some() => {
let mut pats: Vec<&Pat> = before.iter().map(|p| &**p).collect();
pats.grow_fn(arity - before.len() - after.len(), |_| &DUMMY_WILD_PAT);
pats.grow_fn(arity - before.len() - after.len(), |_| dummy);
pats.extend(after.iter().map(|p| &**p));
Some(pats)
},
......
......@@ -25,48 +25,103 @@
// by borrowck::gather_loans
use middle::ty;
use middle::def;
use middle::typeck;
use middle::traits;
use middle::mem_categorization as mc;
use middle::expr_use_visitor as euv;
use util::nodemap::NodeSet;
use syntax::ast;
use syntax::print::pprust;
use syntax::visit::Visitor;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::visit;
use syntax::print::pprust;
fn safe_type_for_static_mut(cx: &ty::ctxt, e: &ast::Expr) -> Option<String> {
let node_ty = ty::node_id_to_type(cx, e.id);
let tcontents = ty::type_contents(cx, node_ty);
debug!("safe_type_for_static_mut(dtor={}, managed={}, owned={})",
tcontents.has_dtor(), tcontents.owns_managed(), tcontents.owns_owned())
let suffix = if tcontents.has_dtor() {
"destructors"
} else if tcontents.owns_managed() {
"managed pointers"
} else if tcontents.owns_owned() {
"owned pointers"
} else {
return None;
};
Some(format!("mutable static items are not allowed to have {}", suffix))
#[deriving(Eq, PartialEq)]
enum Mode {
InConstant,
InStatic,
InStaticMut,
InNothing,
}
struct CheckStaticVisitor<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
in_const: bool
mode: Mode,
checker: &'a mut GlobalChecker,
}
struct GlobalVisitor<'a, 'b, 't: 'b>(euv::ExprUseVisitor<'a, 'b, ty::ctxt<'t>>);
struct GlobalChecker {
static_consumptions: NodeSet,
const_borrows: NodeSet,
static_interior_borrows: NodeSet,
}
pub fn check_crate(tcx: &ty::ctxt) {
visit::walk_crate(&mut CheckStaticVisitor { tcx: tcx, in_const: false },
tcx.map.krate())
let mut checker = GlobalChecker {
static_consumptions: NodeSet::new(),
const_borrows: NodeSet::new(),
static_interior_borrows: NodeSet::new(),
};
{
let visitor = euv::ExprUseVisitor::new(&mut checker, tcx);
visit::walk_crate(&mut GlobalVisitor(visitor), tcx.map.krate());
}
visit::walk_crate(&mut CheckStaticVisitor {
tcx: tcx,
mode: InNothing,
checker: &mut checker,
}, tcx.map.krate());
}
impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> {
fn with_const(&mut self, in_const: bool, f: |&mut CheckStaticVisitor<'a, 'tcx>|) {
let was_const = self.in_const;
self.in_const = in_const;
fn with_mode(&mut self, mode: Mode, f: |&mut CheckStaticVisitor<'a, 'tcx>|) {
let old = self.mode;
self.mode = mode;
f(self);
self.in_const = was_const;
self.mode = old;
}
fn msg(&self) -> &'static str {
match self.mode {
InConstant => "constants",
InStaticMut | InStatic => "statics",
InNothing => unreachable!(),
}
}
fn check_static_mut_type(&self, e: &ast::Expr) {
let node_ty = ty::node_id_to_type(self.tcx, e.id);
let tcontents = ty::type_contents(self.tcx, node_ty);
let suffix = if tcontents.has_dtor() {
"destructors"
} else if tcontents.owns_owned() {
"owned pointers"
} else {
return
};
self.tcx.sess.span_err(e.span, format!("mutable statics are not allowed \
to have {}", suffix).as_slice());
}
fn check_static_type(&self, e: &ast::Expr) {
let ty = ty::node_id_to_type(self.tcx, e.id);
let infcx = typeck::infer::new_infer_ctxt(self.tcx);
let mut fulfill_cx = traits::FulfillmentContext::new();
let cause = traits::ObligationCause::misc(DUMMY_SP);
let obligation = traits::obligation_for_builtin_bound(self.tcx, cause, ty,
ty::BoundSync);
fulfill_cx.register_obligation(self.tcx, obligation.unwrap());
let env = ty::empty_parameter_environment();
let result = fulfill_cx.select_all_or_error(&infcx, &env, self.tcx).is_ok();
if !result {
self.tcx.sess.span_err(e.span, "shared static items must have a \
type which implements Sync");
}
}
}
......@@ -74,22 +129,20 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckStaticVisitor<'a, 'tcx> {
fn visit_item(&mut self, i: &ast::Item) {
debug!("visit_item(item={})", pprust::item_to_string(i));
match i.node {
ast::ItemStatic(_, mutability, ref expr) => {
match mutability {
ast::MutImmutable => {
self.with_const(true, |v| v.visit_expr(&**expr));
}
ast::MutMutable => {
match safe_type_for_static_mut(self.tcx, &**expr) {
Some(msg) => {
self.tcx.sess.span_err(expr.span, msg.as_slice());
}
None => {}
}
}
}
ast::ItemStatic(_, ast::MutImmutable, ref expr) => {
self.check_static_type(&**expr);
self.with_mode(InStatic, |v| v.visit_expr(&**expr));
}
ast::ItemStatic(_, ast::MutMutable, ref expr) => {
self.check_static_mut_type(&**expr);
self.with_mode(InStaticMut, |v| v.visit_expr(&**expr));
}
ast::ItemConst(_, ref expr) => {
self.with_mode(InConstant, |v| v.visit_expr(&**expr));
}
_ => {
self.with_mode(InNothing, |v| visit::walk_item(v, i));
}
_ => self.with_const(false, |v| visit::walk_item(v, i))
}
}
......@@ -100,42 +153,170 @@ fn visit_item(&mut self, i: &ast::Item) {
/// of a static item, this method does nothing but walking
/// down through it.
fn visit_expr(&mut self, e: &ast::Expr) {
debug!("visit_expr(expr={})", pprust::expr_to_string(e));
if !self.in_const {
if self.mode == InNothing {
return visit::walk_expr(self, e);
}
match e.node {
ast::ExprField(..) | ast::ExprTupField(..) | ast::ExprVec(..) |
ast::ExprBlock(..) | ast::ExprTup(..) => {
visit::walk_expr(self, e);
let node_ty = ty::node_id_to_type(self.tcx, e.id);
match ty::get(node_ty).sty {
ty::ty_struct(did, _) |
ty::ty_enum(did, _) if ty::has_dtor(self.tcx, did) => {
self.tcx.sess.span_err(e.span,
format!("{} are not allowed to have \
destructors", self.msg()).as_slice())
}
_ => {}
}
// statics cannot be consumed by value at any time, that would imply
// that they're an initializer (what a const is for) or kept in sync
// over time (not feasible), so deny it outright.
if self.checker.static_consumptions.remove(&e.id) {
self.tcx.sess.span_err(e.span, "cannot refer to other statics by \
value, use the address-of operator \
or a constant instead");
}
// Borrowed statics can specifically *only* have their address taken,
// not any number of other borrows such as borrowing fields, reading
// elements of an array, etc.
if self.checker.static_interior_borrows.remove(&e.id) {
self.tcx.sess.span_err(e.span, "cannot refer to the interior of \
another static, use a constant \
instead");
}
// constants cannot be borrowed if they contain interior mutability as
// it means that our "silent insertion of statics" could change
// initializer values (very bad).
if self.checker.const_borrows.remove(&e.id) {
let node_ty = ty::node_id_to_type(self.tcx, e.id);
let tcontents = ty::type_contents(self.tcx, node_ty);
if tcontents.interior_unsafe() {
self.tcx.sess.span_err(e.span, "cannot borrow a constant which \
contains interior mutability, \
create a static instead");
}
}
match e.node {
ast::ExprAddrOf(ast::MutMutable, _) => {
span_err!(self.tcx.sess, e.span, E0020,
"static items are not allowed to have mutable slices");
if self.mode != InStaticMut {
span_err!(self.tcx.sess, e.span, E0020,
"{} are not allowed to have mutable references",
self.msg());
}
},
ast::ExprBox(..) |
ast::ExprUnary(ast::UnUniq, _) => {
span_err!(self.tcx.sess, e.span, E0022,
"static items are not allowed to have custom pointers");
"{} are not allowed to have custom pointers",
self.msg());
}
_ => {
let node_ty = ty::node_id_to_type(self.tcx, e.id);
match ty::get(node_ty).sty {
ty::ty_struct(did, _) |
ty::ty_enum(did, _) => {
if ty::has_dtor(self.tcx, did) {
self.tcx.sess.span_err(e.span,
"static items are not allowed to have destructors");
return;
}
ast::ExprPath(..) => {
match ty::resolve_expr(self.tcx, e) {
def::DefStatic(..) if self.mode == InConstant => {
let msg = "constants cannot refer to other statics, \
insert an intermediate constant \
instead";
self.tcx.sess.span_err(e.span, msg.as_slice());
}
_ => {}
}
visit::walk_expr(self, e);
}
_ => {}
}
visit::walk_expr(self, e);
}
}
impl<'a, 'b, 't, 'v> Visitor<'v> for GlobalVisitor<'a, 'b, 't> {
fn visit_item(&mut self, item: &ast::Item) {
match item.node {
ast::ItemConst(_, ref e) |
ast::ItemStatic(_, _, ref e) => {
let GlobalVisitor(ref mut v) = *self;
v.consume_expr(&**e);
}
_ => {}
}
visit::walk_item(self, item);
}
}
impl euv::Delegate for GlobalChecker {
fn consume(&mut self,
consume_id: ast::NodeId,
_consume_span: Span,
cmt: mc::cmt,
_mode: euv::ConsumeMode) {
let mut cur = &cmt;
loop {
match cur.cat {
mc::cat_static_item => {
self.static_consumptions.insert(consume_id);
break
}
mc::cat_deref(ref cmt, _, _) |
mc::cat_discr(ref cmt, _) |
mc::cat_downcast(ref cmt) |
mc::cat_interior(ref cmt, _) => cur = cmt,
mc::cat_rvalue(..) |
mc::cat_copied_upvar(..) |
mc::cat_upvar(..) |
mc::cat_local(..) => break,
}
}
}
fn borrow(&mut self,
borrow_id: ast::NodeId,
_borrow_span: Span,
cmt: mc::cmt,
_loan_region: ty::Region,
_bk: ty::BorrowKind,
_loan_cause: euv::LoanCause) {
let mut cur = &cmt;
let mut is_interior = false;
loop {
match cur.cat {
mc::cat_rvalue(..) => {
self.const_borrows.insert(borrow_id);
break
}
mc::cat_static_item => {
if is_interior {
self.static_interior_borrows.insert(borrow_id);
}
break
}
mc::cat_deref(ref cmt, _, _) |
mc::cat_interior(ref cmt, _) => {
is_interior = true;
cur = cmt;
}
mc::cat_downcast(..) |
mc::cat_discr(..) |
mc::cat_copied_upvar(..) |
mc::cat_upvar(..) |
mc::cat_local(..) => unreachable!(),
}
}
}
fn decl_without_init(&mut self,
_id: ast::NodeId,
_span: Span) {}
fn mutate(&mut self,
_assignment_id: ast::NodeId,
_assignment_span: Span,
_assignee_cmt: mc::cmt,
_mode: euv::MutateMode) {}
fn consume_pat(&mut self,
_consume_pat: &ast::Pat,
_cmt: mc::cmt,
_mode: euv::ConsumeMode) {}
}
......@@ -13,9 +13,9 @@
use driver::session::Session;
use middle::resolve;
use middle::def::DefStatic;
use middle::def::{DefStatic, DefConst};
use syntax::ast::{Crate, Expr, ExprPath, Item, ItemStatic, NodeId};
use syntax::ast;
use syntax::{ast_util, ast_map};
use syntax::visit::Visitor;
use syntax::visit;
......@@ -27,13 +27,13 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
}
impl<'v, 'a, 'ast> Visitor<'v> for CheckCrateVisitor<'a, 'ast> {
fn visit_item(&mut self, i: &Item) {
fn visit_item(&mut self, i: &ast::Item) {
check_item(self, i);
}
}
pub fn check_crate<'ast>(sess: &Session,
krate: &Crate,
krate: &ast::Crate,
def_map: &resolve::DefMap,
ast_map: &ast_map::Map<'ast>) {
let mut visitor = CheckCrateVisitor {
......@@ -45,9 +45,10 @@ pub fn check_crate<'ast>(sess: &Session,
sess.abort_if_errors();
}
fn check_item(v: &mut CheckCrateVisitor, it: &Item) {
fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) {
match it.node {
ItemStatic(_, _, ref ex) => {
ast::ItemStatic(_, _, ref ex) |
ast::ItemConst(_, ref ex) => {
check_item_recursion(v.sess, v.ast_map, v.def_map, it);
visit::walk_expr(v, &**ex)
},
......@@ -56,11 +57,11 @@ fn check_item(v: &mut CheckCrateVisitor, it: &Item) {
}
struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
root_it: &'a Item,
root_it: &'a ast::Item,
sess: &'a Session,
ast_map: &'a ast_map::Map<'ast>,
def_map: &'a resolve::DefMap,
idstack: Vec<NodeId>
idstack: Vec<ast::NodeId>
}
// Make sure a const item doesn't recursively refer to itself
......@@ -68,7 +69,7 @@ struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
pub fn check_item_recursion<'a>(sess: &'a Session,
ast_map: &'a ast_map::Map,
def_map: &'a resolve::DefMap,
it: &'a Item) {
it: &'a ast::Item) {
let mut visitor = CheckItemRecursionVisitor {
root_it: it,
......@@ -81,7 +82,7 @@ pub fn check_item_recursion<'a>(sess: &'a Session,
}
impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
fn visit_item(&mut self, it: &Item) {
fn visit_item(&mut self, it: &ast::Item) {
if self.idstack.iter().any(|x| x == &(it.id)) {
self.sess.span_err(self.root_it.span, "recursive constant");
return;
......@@ -91,11 +92,12 @@ fn visit_item(&mut self, it: &Item) {
self.idstack.pop();
}
fn visit_expr(&mut self, e: &Expr) {
fn visit_expr(&mut self, e: &ast::Expr) {
match e.node {
ExprPath(..) => {
ast::ExprPath(..) => {
match self.def_map.borrow().find(&e.id) {
Some(&DefStatic(def_id, _)) if
Some(&DefStatic(def_id, _)) |
Some(&DefConst(def_id)) if
ast_util::is_local(def_id) => {
self.visit_item(&*self.ast_map.expect_item(def_id.node));
}
......
......@@ -87,7 +87,7 @@ pub fn join_all<It: Iterator<constness>>(mut cs: It) -> constness {
fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
let opt_def = tcx.def_map.borrow().find_copy(&e.id);
match opt_def {
Some(def::DefStatic(def_id, false)) => {
Some(def::DefConst(def_id)) => {
lookup_const_by_id(tcx, def_id)
}
Some(def::DefVariant(enum_def, variant_def, _)) => {
......@@ -155,7 +155,7 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
match tcx.map.find(def_id.node) {
None => None,
Some(ast_map::NodeItem(it)) => match it.node {
ItemStatic(_, ast::MutImmutable, ref const_expr) => {
ItemConst(_, ref const_expr) => {
Some(&**const_expr)
}
_ => None
......@@ -173,7 +173,7 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
let expr_id = match csearch::maybe_get_item_ast(tcx, def_id,
|a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
csearch::found(&ast::IIItem(ref item)) => match item.node {
ItemStatic(_, ast::MutImmutable, ref const_expr) => Some(const_expr.id),
ItemConst(_, ref const_expr) => Some(const_expr.id),
_ => None
},
_ => None
......
......@@ -215,7 +215,8 @@ fn visit_node(&mut self, node: &ast_map::Node) {
ast::ItemFn(..)
| ast::ItemEnum(..)
| ast::ItemTy(..)
| ast::ItemStatic(..) => {
| ast::ItemStatic(..)
| ast::ItemConst(..) => {
visit::walk_item(self, &*item);
}
_ => ()
......
......@@ -20,6 +20,7 @@ pub enum Def {
DefMod(ast::DefId),
DefForeignMod(ast::DefId),
DefStatic(ast::DefId, bool /* is_mutbl */),
DefConst(ast::DefId),
DefLocal(ast::NodeId),
DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
DefTy(ast::DefId, bool /* is_enum */),
......@@ -61,7 +62,7 @@ pub fn def_id(&self) -> ast::DefId {
DefForeignMod(id) | DefStatic(id, _) |
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(id) |
DefTyParam(_, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
DefMethod(id, _) => {
DefMethod(id, _) | DefConst(id) => {
id
}
DefLocal(id) |
......
......@@ -267,7 +267,7 @@ fn consume_exprs(&mut self, exprs: &Vec<P<ast::Expr>>) {
}
}
fn consume_expr(&mut self, expr: &ast::Expr) {
pub fn consume_expr(&mut self, expr: &ast::Expr) {
debug!("consume_expr(expr={})", expr.repr(self.tcx()));
let cmt = return_if_err!(self.mc.cat_expr(expr));
......
......@@ -544,7 +544,7 @@ pub fn cat_def(&self,
match def {
def::DefStruct(..) | def::DefVariant(..) | def::DefFn(..) |
def::DefStaticMethod(..) => {
def::DefStaticMethod(..) | def::DefConst(..) => {
Ok(self.cat_rvalue_node(id, span, expr_ty))
}
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
......@@ -1104,7 +1104,7 @@ pub fn cat_pattern(&self,
|x,y,z| op(x,y,z)));
}
}
Some(&def::DefStatic(..)) => {
Some(&def::DefConst(..)) => {
for subpat in subpats.iter() {
if_ok!(self.cat_pattern(cmt.clone(), &**subpat, |x,y,z| op(x,y,z)));
}
......
......@@ -46,7 +46,7 @@ pub fn pat_is_const(dm: &resolve::DefMap, pat: &Pat) -> bool {
match pat.node {
PatIdent(_, _, None) | PatEnum(..) => {
match dm.borrow().find(&pat.id) {
Some(&DefStatic(_, false)) => true,
Some(&DefConst(..)) => true,
_ => false
}
}
......
......@@ -805,6 +805,7 @@ fn check_path(&mut self, span: Span, path_id: ast::NodeId, path: &ast::Path) {
def::DefStaticMethod(..) => ck("static method"),
def::DefFn(..) => ck("function"),
def::DefStatic(..) => ck("static"),
def::DefConst(..) => ck("const"),
def::DefVariant(..) => ck("variant"),
def::DefTy(_, false) => ck("type"),
def::DefTy(_, true) => ck("enum"),
......@@ -1181,7 +1182,7 @@ fn check_sane_privacy(&self, item: &ast::Item) {
}
}
ast::ItemStatic(..) | ast::ItemStruct(..) |
ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemStruct(..) |
ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) |
ast::ItemMac(..) => {}
}
......@@ -1245,7 +1246,7 @@ fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: ast::Visibility) {
}
}
ast::ItemStatic(..) |
ast::ItemStatic(..) | ast::ItemConst(..) |
ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) |
ast::ItemMac(..) => {}
}
......
......@@ -27,7 +27,6 @@
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{is_local, PostExpansionMethod};
use syntax::ast_util;
use syntax::attr::{InlineAlways, InlineHint, InlineNever, InlineNone};
use syntax::attr;
use syntax::visit::Visitor;
......@@ -121,15 +120,14 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
self.worklist.push(def_id.node)
} else {
match def {
// If this path leads to a static, then we may have
// to do some work to figure out whether the static
// is indeed reachable. (Inlineable statics are
// never reachable.)
def::DefStatic(..) => {
// If this path leads to a constant, then we need to
// recurse into the constant to continue finding
// items that are reachable.
def::DefConst(..) => {
self.worklist.push(def_id.node);
}
// If this wasn't a static, then this destination is
// If this wasn't a static, then the destination is
// surely reachable.
_ => {
self.reachable_symbols.insert(def_id.node);
......@@ -238,15 +236,14 @@ fn def_id_represents_local_inlined_item(&self, def_id: ast::DefId) -> bool {
fn propagate(&mut self) {
let mut scanned = HashSet::new();
loop {
if self.worklist.len() == 0 {
break
}
let search_item = self.worklist.pop().unwrap();
if scanned.contains(&search_item) {
let search_item = match self.worklist.pop() {
Some(item) => item,
None => break,
};
if !scanned.insert(search_item) {
continue
}
scanned.insert(search_item);
match self.tcx.map.find(search_item) {
Some(ref item) => self.propagate_node(item, search_item),
None if search_item == ast::CRATE_NODE_ID => {}
......@@ -297,21 +294,17 @@ fn propagate_node(&mut self, node: &ast_map::Node,
}
}
// Statics with insignificant addresses are not reachable
// because they're inlined specially into all other crates.
ast::ItemStatic(_, mutbl, ref init) => {
if !ast_util::static_has_significant_address(
mutbl,
item.attrs.as_slice()) {
self.reachable_symbols.remove(&search_item);
}
visit::walk_expr(self, &**init);
// Reachable constants will be inlined into other crates
// unconditionally, so we need to make sure that their
// contents are also reachable.
ast::ItemConst(_, ref init) => {
self.visit_expr(&**init);
}
// These are normal, nothing reachable about these
// inherently and their children are already in the
// worklist, as determined by the privacy pass
ast::ItemTy(..) |
ast::ItemTy(..) | ast::ItemStatic(_, _, _) |
ast::ItemMod(..) | ast::ItemForeignMod(..) |
ast::ItemImpl(..) | ast::ItemTrait(..) |
ast::ItemStruct(..) | ast::ItemEnum(..) => {}
......
......@@ -29,7 +29,7 @@
use syntax::ast::{ForeignItem, ForeignItemFn, ForeignItemStatic, Generics};
use syntax::ast::{Ident, ImplItem, Item, ItemEnum, ItemFn, ItemForeignMod};
use syntax::ast::{ItemImpl, ItemMac, ItemMod, ItemStatic, ItemStruct};
use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local};
use syntax::ast::{ItemTrait, ItemTy, LOCAL_CRATE, Local, ItemConst};
use syntax::ast::{MethodImplItem, Mod, Name, NamedField, NodeId};
use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
use syntax::ast::{PatRange, PatStruct, Path, PathListIdent, PathListMod};
......@@ -1243,6 +1243,12 @@ fn build_reduced_graph_for_item(&mut self,
(DefStatic(local_def(item.id), mutbl), sp, is_public);
parent
}
ItemConst(_, _) => {
self.add_child(ident, parent.clone(), ForbidDuplicateValues, sp)
.define_value(DefConst(local_def(item.id)),
sp, is_public);
parent
}
ItemFn(_, fn_style, _, _, _) => {
let name_bindings =
self.add_child(ident, parent.clone(), ForbidDuplicateValues, sp);
......@@ -1829,7 +1835,7 @@ fn handle_external_def(&mut self,
csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id)
.map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, is_public);
}
DefFn(..) | DefStaticMethod(..) | DefStatic(..) => {
DefFn(..) | DefStaticMethod(..) | DefStatic(..) | DefConst(..) => {
debug!("(building reduced graph for external \
crate) building value (fn/static) {}", final_ident);
child_name_bindings.define_value(def, DUMMY_SP, is_public);
......@@ -4216,7 +4222,7 @@ fn resolve_item(&mut self, item: &Item) {
&**block);
}
ItemStatic(..) => {
ItemConst(..) | ItemStatic(..) => {
self.with_constant_rib(|this| {
visit::walk_item(this, item);
});
......@@ -5084,6 +5090,7 @@ struct or enum variant",
Some(def @ (DefFn(..), _)) |
Some(def @ (DefVariant(..), _)) |
Some(def @ (DefStruct(..), _)) |
Some(def @ (DefConst(..), _)) |
Some(def @ (DefStatic(..), _)) => {
self.record_def(pattern.id, def);
}
......@@ -5171,12 +5178,14 @@ fn resolve_bare_identifier_pattern(&mut self, name: Ident, span: Span)
def @ DefVariant(..) | def @ DefStruct(..) => {
return FoundStructOrEnumVariant(def, LastMod(AllPublic));
}
def @ DefStatic(_, false) => {
def @ DefConst(..) => {
return FoundConst(def, LastMod(AllPublic));
}
DefStatic(_, true) => {
DefStatic(..) => {
self.resolve_error(span,
"mutable static variables cannot be referenced in a pattern");
"static variables cannot be \
referenced in a pattern, \
use a `const` instead");
return BareIdentifierPatternUnresolved;
}
_ => {
......
......@@ -92,7 +92,7 @@ fn visit_item(&mut self, item: &ast::Item) {
ast::ItemMod(..) |
ast::ItemMac(..) |
ast::ItemForeignMod(..) |
ast::ItemStatic(..) => {
ast::ItemStatic(..) | ast::ItemConst(..) => {
self.with(|_, f| f(RootScope), |v| visit::walk_item(v, item));
return;
}
......
......@@ -230,6 +230,7 @@ fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
def::DefAssociatedTy(..) |
def::DefTrait(_) => Some(recorder::TypeRef),
def::DefStatic(_, _) |
def::DefConst(_) |
def::DefLocal(_) |
def::DefVariant(_, _, _) |
def::DefUpvar(..) => Some(recorder::VarRef),
......@@ -521,6 +522,29 @@ fn process_static(&mut self,
self.visit_expr(expr);
}
fn process_const(&mut self,
item: &ast::Item,
typ: &ast::Ty,
expr: &ast::Expr)
{
let qualname = self.analysis.ty_cx.map.path_to_string(item.id);
let sub_span = self.span.sub_span_after_keyword(item.span,
keywords::Const);
self.fmt.static_str(item.span,
sub_span,
item.id,
get_ident(item.ident).get(),
qualname.as_slice(),
"",
ty_to_string(&*typ).as_slice(),
self.cur_scope);
// walk type and init value
self.visit_ty(&*typ);
self.visit_expr(expr);
}
fn process_struct(&mut self,
item: &ast::Item,
def: &ast::StructDef,
......@@ -740,6 +764,7 @@ fn process_path(&mut self,
def::DefUpvar(..) |
def::DefLocal(..) |
def::DefStatic(..) |
def::DefConst(..) |
def::DefVariant(..) => self.fmt.ref_str(recorder::VarRef,
ex.span,
sub_span,
......@@ -807,6 +832,7 @@ fn process_path(&mut self,
},
def::DefLocal(_) |
def::DefStatic(_,_) |
def::DefConst(..) |
def::DefStruct(_) |
def::DefFn(..) => self.write_sub_paths_truncated(path),
_ => {},
......@@ -1008,6 +1034,8 @@ fn visit_item(&mut self, item: &ast::Item) {
self.process_fn(item, &**decl, ty_params, &**body),
ast::ItemStatic(ref typ, mt, ref expr) =>
self.process_static(item, &**typ, mt, &**expr),
ast::ItemConst(ref typ, ref expr) =>
self.process_const(item, &**typ, &**expr),
ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
ast::ItemImpl(ref ty_params,
......@@ -1386,6 +1414,7 @@ fn visit_arm(&mut self, arm: &ast::Arm) {
self.cur_scope),
// FIXME(nrc) what is this doing here?
def::DefStatic(_, _) => {}
def::DefConst(..) => {}
_ => error!("unexpected definition kind when processing collected paths: {:?}",
*def)
}
......
......@@ -271,14 +271,14 @@ fn trans<'blk, 'tcx>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, 'tcx>
match *self {
ConstantValue(ConstantExpr(lit_expr)) => {
let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id);
let (llval, _, _) = consts::const_expr(ccx, &*lit_expr, true);
let (llval, _) = consts::const_expr(ccx, &*lit_expr);
let lit_datum = immediate_rvalue(llval, lit_ty);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
SingleResult(Result::new(bcx, lit_datum.val))
}
ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2)) => {
let (l1, _, _) = consts::const_expr(ccx, &**l1, true);
let (l2, _, _) = consts::const_expr(ccx, &**l2, true);
let (l1, _) = consts::const_expr(ccx, &**l1);
let (l2, _) = consts::const_expr(ccx, &**l2);
RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
}
Variant(disr_val, ref repr, _) => {
......@@ -350,7 +350,20 @@ struct ArmData<'p, 'blk, 'tcx: 'blk> {
struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> {
pats: Vec<&'p ast::Pat>,
data: &'a ArmData<'p, 'blk, 'tcx>,
bound_ptrs: Vec<(Ident, ValueRef)>
bound_ptrs: Vec<(Ident, ValueRef)>,
// This is a pointer to an instance of check_match::DUMMY_WILD_PAT. The
// check_match code requires that we pass this in (with the same lifetime as
// the patterns passed in). Unfortunately this is required to be propagated
// into this structure in order to get the lifetimes to work.
//
// Lots of the `check_match` code will deal with &DUMMY_WILD_PAT when
// returning references, which used to have the `'static` lifetime before
// const was added to the language. The DUMMY_WILD_PAT does not implement
// Sync, however, so it must be a const, which longer has a static lifetime,
// hence we're passing it in here. This certainly isn't crucial, and if it
// can be removed, please do!
dummy: &'p ast::Pat,
}
impl<'a, 'p, 'blk, 'tcx> Repr for Match<'a, 'p, 'blk, 'tcx> {
......@@ -403,21 +416,22 @@ fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
*pats.get_mut(col) = pat;
Match {
pats: pats,
dummy: br.dummy,
data: &*br.data,
bound_ptrs: bound_ptrs
}
}).collect()
}
type EnterPatterns<'a> = <'p> |&[&'p ast::Pat]|: 'a -> Option<Vec<&'p ast::Pat>>;
type EnterPatterns<'a, 'p> = |&[&'p ast::Pat]|: 'a -> Option<Vec<&'p ast::Pat>>;
fn enter_match<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
dm: &DefMap,
m: &[Match<'a, 'p, 'blk, 'tcx>],
col: uint,
val: ValueRef,
e: EnterPatterns)
-> Vec<Match<'a, 'p, 'blk, 'tcx>> {
fn enter_match<'a, 'b, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
dm: &DefMap,
m: &[Match<'a, 'p, 'blk, 'tcx>],
col: uint,
val: ValueRef,
e: EnterPatterns<'b, 'p>)
-> Vec<Match<'a, 'p, 'blk, 'tcx>> {
debug!("enter_match(bcx={}, m={}, col={}, val={})",
bcx.to_str(),
m.repr(bcx.tcx()),
......@@ -450,6 +464,7 @@ fn enter_match<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
Match {
pats: pats,
dummy: br.dummy,
data: br.data,
bound_ptrs: bound_ptrs
}
......@@ -544,7 +559,8 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>(
let mcx = check_match::MatchCheckCtxt { tcx: bcx.tcx() };
enter_match(bcx, dm, m, col, val, |pats|
check_match::specialize(&mcx, pats.as_slice(), &ctor, col, variant_size)
check_match::specialize(&mcx, pats.as_slice(), m[0].dummy, &ctor, col,
variant_size)
)
}
......@@ -1025,7 +1041,9 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
match adt_vals {
Some(field_vals) => {
let pats = enter_match(bcx, dm, m, col, val, |pats|
check_match::specialize(&mcx, pats, &check_match::Single, col, field_vals.len())
check_match::specialize(&mcx, pats, m[0].dummy,
&check_match::Single, col,
field_vals.len())
);
let vals = field_vals.append(vals_left.as_slice());
compile_submatch(bcx, pats.as_slice(), vals.as_slice(), chk, has_genuine_default);
......@@ -1347,6 +1365,7 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>,
bindings_map: create_bindings_map(bcx, &**arm.pats.get(0), discr_expr, &*arm.body)
}).collect();
let dummy = check_match::DUMMY_WILD_PAT.clone();
let mut static_inliner = StaticInliner::new(scope_cx.tcx());
let arm_pats: Vec<Vec<P<ast::Pat>>> = arm_datas.iter().map(|arm_data| {
arm_data.arm.pats.iter().map(|p| static_inliner.fold_pat((*p).clone())).collect()
......@@ -1355,6 +1374,7 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>,
for (arm_data, pats) in arm_datas.iter().zip(arm_pats.iter()) {
matches.extend(pats.iter().map(|p| Match {
pats: vec![&**p],
dummy: &dummy,
data: arm_data,
bound_ptrs: Vec::new(),
}));
......
......@@ -32,7 +32,7 @@
use driver::driver::{CrateAnalysis, CrateTranslation, ModuleTranslation};
use driver::session::Session;
use lint;
use llvm::{BasicBlockRef, ModuleRef, ValueRef, Vector, get_param};
use llvm::{BasicBlockRef, ValueRef, Vector, get_param};
use llvm;
use metadata::{csearch, encoder, loader};
use middle::astencode;
......@@ -89,7 +89,7 @@
use std::{i8, i16, i32, i64};
use syntax::abi::{X86, X86_64, Arm, Mips, Mipsel, Rust, RustCall};
use syntax::abi::{RustIntrinsic, Abi, OsWindows};
use syntax::ast_util::{local_def, is_local};
use syntax::ast_util::local_def;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::Span;
......@@ -317,17 +317,31 @@ pub fn decl_internal_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> Va
llfn
}
pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
name: &str, ty: Type) -> ValueRef {
match externs.find_equiv(&name) {
pub fn get_extern_const(ccx: &CrateContext, did: ast::DefId,
t: ty::t) -> ValueRef {
let name = csearch::get_symbol(&ccx.sess().cstore, did);
let ty = type_of(ccx, t);
match ccx.externs().borrow_mut().find(&name) {
Some(n) => return *n,
None => ()
}
unsafe {
let c = name.with_c_str(|buf| {
llvm::LLVMAddGlobal(llmod, ty.to_ref(), buf)
llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf)
});
externs.insert(name.to_string(), c);
// 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.
ty::each_attr(ccx.tcx(), did, |attr| {
if attr.check_name("thread_local") {
llvm::set_thread_local(c, true);
}
true
});
ccx.externs().borrow_mut().insert(name.to_string(), c);
return c;
}
}
......@@ -935,11 +949,7 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
get_extern_rust_fn(ccx, t, name.as_slice(), did)
}
_ => {
let llty = type_of(ccx, t);
get_extern_const(&mut *ccx.externs().borrow_mut(),
ccx.llmod(),
name.as_slice(),
llty)
get_extern_const(ccx, did, t)
}
}
}
......@@ -2228,21 +2238,19 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
ast::ItemEnum(ref enum_definition, _) => {
enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
}
ast::ItemConst(_, ref expr) => {
// Recurse on the expression to catch items in blocks
let mut v = TransItemVisitor{ ccx: ccx };
v.visit_expr(&**expr);
}
ast::ItemStatic(_, m, ref expr) => {
// Recurse on the expression to catch items in blocks
let mut v = TransItemVisitor{ ccx: ccx };
v.visit_expr(&**expr);
let trans_everywhere = attr::requests_inline(item.attrs.as_slice());
for (ref ccx, is_origin) in ccx.maybe_iter(!from_external && trans_everywhere) {
consts::trans_const(ccx, m, item.id);
let g = get_item_val(ccx, item.id);
update_linkage(ccx,
g,
Some(item.id),
if is_origin { OriginalTranslation } else { InlinedCopy });
}
consts::trans_static(ccx, m, item.id);
let g = get_item_val(ccx, item.id);
update_linkage(ccx, g, Some(item.id), OriginalTranslation);
// Do static_assert checking. It can't really be done much earlier
// because we need to get the value of the bool out of LLVM
......@@ -2253,7 +2261,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
static");
}
let v = ccx.const_values().borrow().get_copy(&item.id);
let v = ccx.static_values().borrow().get_copy(&item.id);
unsafe {
if !(llvm::LLVMConstIntGetZExtValue(v) != 0) {
ccx.sess().span_fatal(expr.span, "static assertion failed");
......@@ -2667,23 +2675,21 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
let val = match item {
ast_map::NodeItem(i) => {
let ty = ty::node_id_to_type(ccx.tcx(), i.id);
let sym = exported_name(ccx, id, ty, i.attrs.as_slice());
let sym = || exported_name(ccx, id, ty, i.attrs.as_slice());
let v = match i.node {
ast::ItemStatic(_, mutbl, ref expr) => {
ast::ItemStatic(_, _, ref expr) => {
// If this static came from an external crate, then
// we need to get the symbol from csearch instead of
// using the current crate's name/version
// information in the hash of the symbol
let sym = sym();
debug!("making {}", sym);
let is_local = !ccx.external_srcs().borrow().contains_key(&id);
// We need the translated value here, because for enums the
// LLVM type is not fully determined by the Rust type.
let (v, inlineable, ty) = consts::const_expr(ccx, &**expr, is_local);
ccx.const_values().borrow_mut().insert(id, v);
let mut inlineable = inlineable;
let (v, ty) = consts::const_expr(ccx, &**expr);
ccx.static_values().borrow_mut().insert(id, v);
unsafe {
// boolean SSA values are i1, but they have to be stored in i8 slots,
// otherwise some LLVM optimization passes don't work as expected
......@@ -2694,55 +2700,30 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
};
if contains_null(sym.as_slice()) {
ccx.sess().fatal(
format!("Illegal null byte in export_name value: `{}`",
sym).as_slice());
format!("Illegal null byte in export_name \
value: `{}`", sym).as_slice());
}
let g = sym.as_slice().with_c_str(|buf| {
llvm::LLVMAddGlobal(ccx.llmod(), llty, buf)
});
// Apply the `unnamed_addr` attribute if
// requested
if !ast_util::static_has_significant_address(
mutbl,
i.attrs.as_slice()) {
llvm::SetUnnamedAddr(g, true);
// This is a curious case where we must make
// all of these statics inlineable. If a
// global is not tagged as `#[inline(never)]`,
// then LLVM won't coalesce globals unless they
// have an internal linkage type. This means that
// external crates cannot use this global.
// This is a problem for things like inner
// statics in generic functions, because the
// function will be inlined into another
// crate and then attempt to link to the
// static in the original crate, only to
// find that it's not there. On the other
// side of inlining, the crates knows to
// not declare this static as
// available_externally (because it isn't)
inlineable = true;
}
if attr::contains_name(i.attrs.as_slice(),
"thread_local") {
llvm::set_thread_local(g, true);
}
if !inlineable {
debug!("{} not inlined", sym);
ccx.non_inlineable_statics().borrow_mut()
.insert(id);
}
ccx.item_symbols().borrow_mut().insert(i.id, sym);
g
}
}
ast::ItemConst(_, ref expr) => {
let (v, _) = consts::const_expr(ccx, &**expr);
ccx.const_values().borrow_mut().insert(id, v);
v
}
ast::ItemFn(_, _, abi, _, _) => {
let sym = sym();
let llfn = if abi == Rust {
register_fn(ccx, i.span, sym, i.id, ty)
} else {
......@@ -2911,7 +2892,6 @@ pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'tcx>,
tcx: cx.tcx(),
reexports2: cx.exp_map2(),
item_symbols: cx.item_symbols(),
non_inlineable_statics: cx.non_inlineable_statics(),
link_meta: cx.link_meta(),
cstore: &cx.sess().cstore,
encode_inlined_item: ie,
......
......@@ -196,6 +196,7 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def: def::Def, ref_expr: &ast::
}
}
def::DefStatic(..) |
def::DefConst(..) |
def::DefLocal(..) |
def::DefUpvar(..) => {
datum_callee(bcx, ref_expr)
......
此差异已折叠。
......@@ -66,10 +66,6 @@ pub struct SharedCrateContext<'tcx> {
reachable: NodeSet,
item_symbols: RefCell<NodeMap<String>>,
link_meta: LinkMeta,
/// A set of static items which cannot be inlined into other crates. This
/// will prevent in IIItem() structures from being encoded into the metadata
/// that is generated
non_inlineable_statics: RefCell<NodeSet>,
symbol_hasher: RefCell<Sha256>,
tcx: ty::ctxt<'tcx>,
stats: Stats,
......@@ -121,6 +117,9 @@ pub struct LocalCrateContext {
/// Cache of emitted const values
const_values: RefCell<NodeMap<ValueRef>>,
/// Cache of emitted static values
static_values: RefCell<NodeMap<ValueRef>>,
/// Cache of external const values
extern_const_values: RefCell<DefIdMap<ValueRef>>,
......@@ -259,7 +258,6 @@ pub fn new(crate_name: &str,
reachable: reachable,
item_symbols: RefCell::new(NodeMap::new()),
link_meta: link_meta,
non_inlineable_statics: RefCell::new(NodeSet::new()),
symbol_hasher: RefCell::new(symbol_hasher),
tcx: tcx,
stats: Stats {
......@@ -351,10 +349,6 @@ pub fn link_meta<'a>(&'a self) -> &'a LinkMeta {
&self.link_meta
}
pub fn non_inlineable_statics<'a>(&'a self) -> &'a RefCell<NodeSet> {
&self.non_inlineable_statics
}
pub fn symbol_hasher<'a>(&'a self) -> &'a RefCell<Sha256> {
&self.symbol_hasher
}
......@@ -414,6 +408,7 @@ fn new(shared: &SharedCrateContext,
const_cstr_cache: RefCell::new(HashMap::new()),
const_globals: RefCell::new(HashMap::new()),
const_values: RefCell::new(NodeMap::new()),
static_values: RefCell::new(NodeMap::new()),
extern_const_values: RefCell::new(DefIdMap::new()),
impl_method_cache: RefCell::new(HashMap::new()),
closure_bare_wrapper_cache: RefCell::new(HashMap::new()),
......@@ -610,10 +605,6 @@ pub fn external_srcs<'a>(&'a self) -> &'a RefCell<NodeMap<ast::DefId>> {
&self.local.external_srcs
}
pub fn non_inlineable_statics<'a>(&'a self) -> &'a RefCell<NodeSet> {
&self.shared.non_inlineable_statics
}
pub fn monomorphized<'a>(&'a self) -> &'a RefCell<HashMap<MonoId, ValueRef>> {
&self.local.monomorphized
}
......@@ -638,6 +629,10 @@ pub fn const_values<'a>(&'a self) -> &'a RefCell<NodeMap<ValueRef>> {
&self.local.const_values
}
pub fn static_values<'a>(&'a self) -> &'a RefCell<NodeMap<ValueRef>> {
&self.local.static_values
}
pub fn extern_const_values<'a>(&'a self) -> &'a RefCell<DefIdMap<ValueRef>> {
&self.local.extern_const_values
}
......
......@@ -776,6 +776,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
ast_map::NodeItem(item) => {
match item.node {
ast::ItemStatic(..) => (item.ident, item.span),
ast::ItemConst(..) => (item.ident, item.span),
_ => {
cx.sess()
.span_bug(item.span,
......
......@@ -36,7 +36,6 @@
use back::abi;
use llvm;
use llvm::{ValueRef};
use metadata::csearch;
use middle::def;
use middle::mem_categorization::Typer;
use middle::subst;
......@@ -839,25 +838,20 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
trans_def_fn_unadjusted(bcx, ref_expr, def)
}
def::DefStatic(did, _) => {
// There are three things that may happen here:
// There are two things that may happen here:
// 1) If the static item is defined in this crate, it will be
// translated using `get_item_val`, and we return a pointer to
// the result.
// 2) If the static item is defined in another crate, but is
// marked inlineable, then it will be inlined into this crate
// and then translated with `get_item_val`. Again, we return a
// pointer to the result.
// 3) If the static item is defined in another crate and is not
// marked inlineable, then we add (or reuse) a declaration of
// an external global, and return a pointer to that.
// 2) If the static item is defined in another crate then we add
// (or reuse) a declaration of an external global, and return a
// pointer to that.
let const_ty = expr_ty(bcx, ref_expr);
fn get_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, did: ast::DefId, const_ty: ty::t)
-> ValueRef {
fn get_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, did: ast::DefId,
const_ty: ty::t) -> ValueRef {
// For external constants, we don't inline.
if did.krate == ast::LOCAL_CRATE {
// Case 1 or 2. (The inlining in case 2 produces a new
// DefId in LOCAL_CRATE.)
// Case 1.
// The LLVM global has the type of its initializer,
// which may not be equal to the enum's type for
......@@ -866,36 +860,41 @@ fn get_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, did: ast::DefId, const_ty: ty::t)
let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
PointerCast(bcx, val, pty)
} else {
// Case 3.
match bcx.ccx().extern_const_values().borrow().find(&did) {
None => {} // Continue.
Some(llval) => {
return *llval;
}
}
unsafe {
let llty = type_of::type_of(bcx.ccx(), const_ty);
let symbol = csearch::get_symbol(
&bcx.ccx().sess().cstore,
did);
let llval = symbol.as_slice().with_c_str(|buf| {
llvm::LLVMAddGlobal(bcx.ccx().llmod(),
llty.to_ref(),
buf)
});
bcx.ccx().extern_const_values().borrow_mut()
.insert(did, llval);
llval
}
// Case 2.
base::get_extern_const(bcx.ccx(), did, const_ty)
}
}
// The DefId produced by `maybe_instantiate_inline`
// may be in the LOCAL_CRATE or not.
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
let val = get_val(bcx, did, const_ty);
DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr))
}
def::DefConst(did) => {
// First, inline any external constants into the local crate so we
// can be sure to get the LLVM value corresponding to it.
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
if did.krate != ast::LOCAL_CRATE {
bcx.tcx().sess.span_bug(ref_expr.span,
"cross crate constant could not \
be inlined");
}
let val = base::get_item_val(bcx.ccx(), did.node);
// Next, we need to crate a ByRef rvalue datum to return. We can't
// use the normal .to_ref_datum() function because the type of
// `val` is not actually the same as `const_ty`.
//
// To get around this, we make a custom alloca slot with the
// appropriate type (const_ty), and then we cast it to a pointer of
// typeof(val), store the value, and then hand this slot over to
// the datum infrastructure.
let const_ty = expr_ty(bcx, ref_expr);
let llty = type_of::type_of(bcx.ccx(), const_ty);
let slot = alloca(bcx, llty, "const");
let pty = Type::from_ref(unsafe { llvm::LLVMTypeOf(val) }).ptr_to();
Store(bcx, val, PointerCast(bcx, slot, pty));
let datum = Datum::new(slot, const_ty, Rvalue::new(ByRef));
DatumBlock::new(bcx, datum.to_expr_datum())
}
_ => {
DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
}
......
......@@ -17,7 +17,6 @@
use syntax::ast;
use syntax::ast_util::{local_def, PostExpansionMethod};
use syntax::ast_util;
fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
-> Option<ast::DefId> {
......@@ -76,21 +75,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
}
}
}
ast::ItemStatic(_, mutbl, _) => {
if !ast_util::static_has_significant_address(mutbl, item.attrs.as_slice()) {
// Inlined static items use internal linkage when
// possible, so that LLVM will coalesce globals with
// identical initializers. (It only does this for
// globals with unnamed_addr and either internal or
// private linkage.)
Some(InternalLinkage)
} else {
// The address is significant, so we can't create an
// internal copy of the static. (The copy would have a
// different address from the original.)
Some(AvailableExternallyLinkage)
}
}
ast::ItemConst(..) => None,
_ => unreachable!(),
};
......
......@@ -1374,6 +1374,7 @@ pub fn for_item(cx: &ctxt, id: NodeId) -> ParameterEnvironment {
ast::ItemEnum(..) |
ast::ItemStruct(..) |
ast::ItemImpl(..) |
ast::ItemConst(..) |
ast::ItemStatic(..) => {
let def_id = ast_util::local_def(id);
let pty = ty::lookup_item_type(cx, def_id);
......@@ -3576,6 +3577,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
def::DefUpvar(..) |
def::DefLocal(..) => LvalueExpr,
def::DefConst(..) => RvalueDatumExpr,
def => {
tcx.sess.span_bug(
expr.span,
......
......@@ -677,7 +677,8 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) {
let _indenter = indenter();
match it.node {
ast::ItemStatic(_, _, ref e) => check_const(ccx, it.span, &**e, it.id),
ast::ItemStatic(_, _, ref e) |
ast::ItemConst(_, ref e) => check_const(ccx, it.span, &**e, it.id),
ast::ItemEnum(ref enum_definition, _) => {
check_enum_variants(ccx,
it.span,
......@@ -5083,7 +5084,7 @@ pub fn polytype_for_def(fcx: &FnCtxt,
}
def::DefFn(id, _, _) | def::DefStaticMethod(id, _, _) |
def::DefStatic(id, _) | def::DefVariant(_, id, _) |
def::DefStruct(id) => {
def::DefStruct(id) | def::DefConst(id) => {
return ty::lookup_item_type(fcx.ccx.tcx, id);
}
def::DefTrait(_) |
......@@ -5211,6 +5212,7 @@ pub fn instantiate_path(fcx: &FnCtxt,
// Case 2. Reference to a top-level value.
def::DefFn(..) |
def::DefConst(..) |
def::DefStatic(..) => {
segment_spaces = Vec::from_elem(path.segments.len() - 1, None);
segment_spaces.push(Some(subst::FnSpace));
......
......@@ -69,6 +69,9 @@ fn check_item_well_formed(&mut self, ccx: &CrateCtxt, item: &ast::Item) {
ast::ItemStatic(..) => {
self.check_item_type(item);
}
ast::ItemConst(..) => {
self.check_item_type(item);
}
ast::ItemStruct(ref struct_def, _) => {
self.check_type_defn(item, |fcx| {
vec![struct_variant(fcx, &**struct_def)]
......
......@@ -1550,7 +1550,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
_ => {}
}
match it.node {
ast::ItemStatic(ref t, _, _) => {
ast::ItemStatic(ref t, _, _) | ast::ItemConst(ref t, _) => {
let typ = ccx.to_ty(&ExplicitRscope, &**t);
let pty = no_params(typ);
......
......@@ -197,7 +197,7 @@ fn search(this: &Env,
}
return match it.node {
ast::ItemStatic(..) | ast::ItemFn(..) |
ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemFn(..) |
ast::ItemForeignMod(..) | ast::ItemTy(..) => {
None
}
......
......@@ -384,6 +384,7 @@ fn visit_item(&mut self, item: &ast::Item) {
ast::ItemImpl(..) |
ast::ItemStatic(..) |
ast::ItemConst(..) |
ast::ItemFn(..) |
ast::ItemMod(..) |
ast::ItemForeignMod(..) |
......@@ -528,6 +529,7 @@ fn visit_item(&mut self, item: &ast::Item) {
}
ast::ItemStatic(..) |
ast::ItemConst(..) |
ast::ItemFn(..) |
ast::ItemMod(..) |
ast::ItemForeignMod(..) |
......
......@@ -1309,6 +1309,7 @@ pub struct Item {
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum Item_ {
ItemStatic(P<Ty>, Mutability, P<Expr>),
ItemConst(P<Ty>, P<Expr>),
ItemFn(P<FnDecl>, FnStyle, Abi, Generics, P<Block>),
ItemMod(Mod),
ItemForeignMod(ForeignMod),
......
......@@ -1018,6 +1018,7 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String {
let path_str = map.path_to_str_with_ident(id, item.ident);
let item_str = match item.node {
ItemStatic(..) => "static",
ItemConst(..) => "const",
ItemFn(..) => "fn",
ItemMod(..) => "mod",
ItemForeignMod(..) => "foreign mod",
......
......@@ -12,8 +12,6 @@
use ast::*;
use ast;
use ast_util;
use attr::{InlineNever, InlineNone};
use attr;
use codemap;
use codemap::Span;
use owned_slice::OwnedSlice;
......@@ -706,18 +704,6 @@ pub fn lit_is_str(lit: &Lit) -> bool {
}
}
/// Returns true if the static with the given mutability and attributes
/// has a significant address and false otherwise.
pub fn static_has_significant_address(mutbl: ast::Mutability,
attrs: &[ast::Attribute])
-> bool {
if mutbl == ast::MutMutable {
return true
}
let inline = attr::find_inline_attr(attrs);
inline == InlineNever || inline == InlineNone
}
/// Macro invocations are guaranteed not to occur after expansion is complete.
/// Extracting fields of a method requires a dynamic check to make sure that it's
/// not a macro invocation. This check is guaranteed to succeed, assuming
......
......@@ -250,6 +250,13 @@ fn item_static(&self,
expr: P<ast::Expr>)
-> P<ast::Item>;
fn item_const(&self,
span: Span,
name: Ident,
ty: P<ast::Ty>,
expr: P<ast::Expr>)
-> P<ast::Item>;
fn item_ty_poly(&self,
span: Span,
name: Ident,
......@@ -1033,6 +1040,15 @@ fn item_static(&self,
self.item(span, name, Vec::new(), ast::ItemStatic(ty, mutbl, expr))
}
fn item_const(&self,
span: Span,
name: Ident,
ty: P<ast::Ty>,
expr: P<ast::Expr>)
-> P<ast::Item> {
self.item(span, name, Vec::new(), ast::ItemConst(ty, expr))
}
fn item_ty_poly(&self, span: Span, name: Ident, ty: P<ast::Ty>,
generics: Generics) -> P<ast::Item> {
self.item(span, name, Vec::new(), ast::ItemTy(ty, generics))
......
......@@ -903,6 +903,9 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
ItemStatic(t, m, e) => {
ItemStatic(folder.fold_ty(t), m, folder.fold_expr(e))
}
ItemConst(t, e) => {
ItemConst(folder.fold_ty(t), folder.fold_expr(e))
}
ItemFn(decl, fn_style, abi, generics, body) => {
ItemFn(
folder.fold_fn_decl(decl),
......
......@@ -32,7 +32,7 @@
use ast::{FnOnceUnboxedClosureKind};
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod};
use ast::{Ident, NormalFn, Inherited, ImplItem, Item, Item_, ItemStatic};
use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl};
use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst};
use ast::{ItemMac, ItemMod, ItemStruct, ItemTrait, ItemTy};
use ast::{LifetimeDef, Lit, Lit_};
use ast::{LitBool, LitChar, LitByte, LitBinary};
......@@ -4739,14 +4739,18 @@ fn parse_mod_items(&mut self,
}
}
fn parse_item_const(&mut self, m: Mutability) -> ItemInfo {
fn parse_item_const(&mut self, m: Option<Mutability>) -> ItemInfo {
let id = self.parse_ident();
self.expect(&token::COLON);
let ty = self.parse_ty(true);
self.expect(&token::EQ);
let e = self.parse_expr();
self.commit_expr_expecting(&*e, token::SEMI);
(id, ItemStatic(ty, m, e), None)
let item = match m {
Some(m) => ItemStatic(ty, m, e),
None => ItemConst(ty, e),
};
(id, item, None)
}
/// Parse a `mod <foo> { ... }` or `mod <foo>;` item
......@@ -5296,7 +5300,7 @@ fn parse_item_or_view_item(&mut self,
// STATIC ITEM
self.bump();
let m = if self.eat_keyword(keywords::Mut) {MutMutable} else {MutImmutable};
let (ident, item_, extra_attrs) = self.parse_item_const(m);
let (ident, item_, extra_attrs) = self.parse_item_const(Some(m));
let last_span = self.last_span;
let item = self.mk_item(lo,
last_span.hi,
......@@ -5314,7 +5318,7 @@ fn parse_item_or_view_item(&mut self,
self.span_err(last_span, "const globals cannot be mutable, \
did you mean to declare a static?");
}
let (ident, item_, extra_attrs) = self.parse_item_const(MutImmutable);
let (ident, item_, extra_attrs) = self.parse_item_const(None);
let last_span = self.last_span;
let item = self.mk_item(lo,
last_span.hi,
......
......@@ -757,6 +757,20 @@ pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> {
try!(word(&mut self.s, ";"));
try!(self.end()); // end the outer cbox
}
ast::ItemConst(ref ty, ref expr) => {
try!(self.head(visibility_qualified(item.vis,
"const").as_slice()));
try!(self.print_ident(item.ident));
try!(self.word_space(":"));
try!(self.print_type(&**ty));
try!(space(&mut self.s));
try!(self.end()); // end the head-ibox
try!(self.word_space("="));
try!(self.print_expr(&**expr));
try!(word(&mut self.s, ";"));
try!(self.end()); // end the outer cbox
}
ast::ItemFn(ref decl, fn_style, abi, ref typarams, ref body) => {
try!(self.print_fn(
&**decl,
......
......@@ -493,11 +493,10 @@ fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
Some(static_lt),
ast::MutImmutable);
// static TESTS: $static_type = &[...];
ecx.item_static(sp,
ecx.ident_of("TESTS"),
static_type,
ast::MutImmutable,
test_descs)
ecx.item_const(sp,
ecx.ident_of("TESTS"),
static_type,
test_descs)
}
fn is_test_crate(krate: &ast::Crate) -> bool {
......
......@@ -211,7 +211,8 @@ pub fn walk_trait_ref_helper<'v,V>(visitor: &mut V, trait_ref: &'v TraitRef)
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_ident(item.span, item.ident);
match item.node {
ItemStatic(ref typ, _, ref expr) => {
ItemStatic(ref typ, _, ref expr) |
ItemConst(ref typ, ref expr) => {
visitor.visit_ty(&**typ);
visitor.visit_expr(&**expr);
}
......
// Copyright 2014 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.
struct A;
impl Drop for A {
fn drop(&mut self) {}
}
const FOO: A = A;
//~ ERROR: constants are not allowed to have destructors
fn main() {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册