diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 4c147517a7f03..451d39fbc3def 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -978,7 +978,8 @@ impl LintPass for NonUppercaseStatics { 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 @@ impl LintPass for NonUppercaseStatics { 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, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 58d0f132e06a2..dcf394aa3f406 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -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)), diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 642f66e259a62..94d86956f7005 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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>, - pub non_inlineable_statics: &'a RefCell, 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>, - pub non_inlineable_statics: &'a RefCell, pub link_meta: &'a LinkMeta, pub cstore: &'a cstore::CStore, pub encode_inlined_item: RefCell>, @@ -1069,12 +1067,20 @@ fn encode_info_for_item(ecx: &EncodeContext, 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 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter, parms: EncodeParams, krate: cstore, encode_inlined_item, link_meta, - non_inlineable_statics, reachable, .. } = parms; @@ -2085,7 +2090,6 @@ fn encode_metadata_inner(wr: &mut SeekableMemWriter, parms: EncodeParams, krate: 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), diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 2bd145706aaad..955228c99deed 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -460,6 +460,7 @@ impl tr for 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) diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index cd003432ef22c..f2ff104ba1d10 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -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, 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, 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. diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index a86ae42006595..7d0d99443b0d8 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -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); } _ => { diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index bb62a96f0adc6..f0455db6e3bb6 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -48,7 +48,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { } 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 => {} } } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 92f04b108c19b..297640707687c 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -32,7 +32,7 @@ use syntax::ptr::P; 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 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { 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> { 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> = 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) }, diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 64e4d7ff28425..9cc1f92dc9304 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -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 { - 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 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckStaticVisitor<'a, 'tcx> { /// 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) {} +} + diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index b571a18c1ece7..1f76d9dba2635 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -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 + idstack: Vec } // 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 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> { 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)); } diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 98d2cefac0fcf..abcdc45bdcfde 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -87,7 +87,7 @@ pub fn join_all>(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 diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 1b2f62a9385a2..ff3720381009c 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -215,7 +215,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { ast::ItemFn(..) | ast::ItemEnum(..) | ast::ItemTy(..) - | ast::ItemStatic(..) => { + | ast::ItemStatic(..) + | ast::ItemConst(..) => { visit::walk_item(self, &*item); } _ => () diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index bd42586435f26..3b7af9788ac57 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -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 @@ impl Def { 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) | diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 51cdbfcf2514c..6cfdac93efc8a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -267,7 +267,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,TYPER> { } } - 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)); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 9a0885ca30135..fa494b357c19d 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -544,7 +544,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { 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 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { |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))); } diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index e3806f02ed4c8..4d61baca70874 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -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 } } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 7e415d1f5c1a7..e434d859993c0 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -805,6 +805,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { } } - ast::ItemStatic(..) | ast::ItemStruct(..) | + ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemStruct(..) | ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) | ast::ItemMac(..) => {} } @@ -1245,7 +1246,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { } } - ast::ItemStatic(..) | + ast::ItemStatic(..) | ast::ItemConst(..) | ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemTy(..) | ast::ItemMac(..) => {} } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 555a033a568d1..5d6f7048b82e1 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -27,7 +27,6 @@ use syntax::abi; 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 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { 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 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { 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 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } } - // 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(..) => {} diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 595739585a398..318bc05d05f88 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -29,7 +29,7 @@ use syntax::ast::{ExprPath, ExprProc, ExprStruct, ExprUnboxedFn, FnDecl}; 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 @@ impl<'a> Resolver<'a> { (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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { &**block); } - ItemStatic(..) => { + ItemConst(..) | ItemStatic(..) => { self.with_constant_rib(|this| { visit::walk_item(this, item); }); @@ -5084,6 +5090,7 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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; } _ => { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 42ae877122490..6d84b8cb49dd2 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -92,7 +92,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { ast::ItemMod(..) | ast::ItemMac(..) | ast::ItemForeignMod(..) | - ast::ItemStatic(..) => { + ast::ItemStatic(..) | ast::ItemConst(..) => { self.with(|_, f| f(RootScope), |v| visit::walk_item(v, item)); return; } diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs index debcfe3933c03..4aba29d7bae16 100644 --- a/src/librustc/middle/save/mod.rs +++ b/src/librustc/middle/save/mod.rs @@ -230,6 +230,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefAssociatedTy(..) | def::DefTrait(_) => Some(recorder::TypeRef), def::DefStatic(_, _) | + def::DefConst(_) | def::DefLocal(_) | def::DefVariant(_, _, _) | def::DefUpvar(..) => Some(recorder::VarRef), @@ -521,6 +522,29 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { 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 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefUpvar(..) | def::DefLocal(..) | def::DefStatic(..) | + def::DefConst(..) | def::DefVariant(..) => self.fmt.ref_str(recorder::VarRef, ex.span, sub_span, @@ -807,6 +832,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { }, def::DefLocal(_) | def::DefStatic(_,_) | + def::DefConst(..) | def::DefStruct(_) | def::DefFn(..) => self.write_sub_paths_truncated(path), _ => {}, @@ -1008,6 +1034,8 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { 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 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { self.cur_scope), // FIXME(nrc) what is this doing here? def::DefStatic(_, _) => {} + def::DefConst(..) => {} _ => error!("unexpected definition kind when processing collected paths: {:?}", *def) } diff --git a/src/librustc/middle/traexpr b/src/librustc/middle/traexpr new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 38f09d1957252..9eb02717f04a1 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -271,14 +271,14 @@ impl<'a> Opt<'a> { 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>; +type EnterPatterns<'a, 'p> = |&[&'p ast::Pat]|: 'a -> Option>; -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> { +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> { 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>> = 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(), })); diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d175919fb8108..8df5b375a8167 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -32,7 +32,7 @@ use driver::config::{NoDebugInfo, FullDebugInfo}; 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::rc::Rc; 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, diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 7942a0211e4e6..bc562b39c98f7 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -196,6 +196,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) } } def::DefStatic(..) | + def::DefConst(..) | def::DefLocal(..) | def::DefUpvar(..) => { datum_callee(bcx, ref_expr) diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 5e4692bd0f617..ec357f7bfd7c6 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -33,7 +33,6 @@ use middle::ty; use util::ppaux::{Repr, ty_to_string}; use std::c_str::ToCStr; -use std::vec; use libc::c_uint; use syntax::{ast, ast_util}; use syntax::ptr::P; @@ -96,24 +95,20 @@ pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef { } } -// Helper function because we don't have tuple-swizzling. -fn first_two((a, b, _): (R, S, T)) -> (R, S) { - (a, b) -} - fn const_vec(cx: &CrateContext, e: &ast::Expr, - es: &[P], is_local: bool) -> (ValueRef, Type, bool) { + es: &[P]) -> (ValueRef, Type) { let vec_ty = ty::expr_ty(cx.tcx(), e); let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty); let llunitty = type_of::type_of(cx, unit_ty); - let (vs, inlineable) = vec::unzip(es.iter().map(|e| first_two(const_expr(cx, &**e, is_local)))); + let vs = es.iter().map(|e| const_expr(cx, &**e).val0()) + .collect::>(); // If the vector contains enums, an LLVM array won't work. let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) { C_struct(cx, vs.as_slice(), false) } else { C_array(llunitty, vs.as_slice()) }; - (v, llunitty, inlineable.iter().fold(true, |a, &b| a && b)) + (v, llunitty) } pub fn const_addr_of(cx: &CrateContext, cv: ValueRef, mutbl: ast::Mutability) -> ValueRef { @@ -177,7 +172,7 @@ fn const_deref(cx: &CrateContext, v: ValueRef, t: ty::t, explicit: bool) } pub fn get_const_val(cx: &CrateContext, - mut def_id: ast::DefId) -> (ValueRef, bool) { + mut def_id: ast::DefId) -> ValueRef { let contains_key = cx.const_values().borrow().contains_key(&def_id.node); if !ast_util::is_local(def_id) || !contains_key { if !ast_util::is_local(def_id) { @@ -185,21 +180,17 @@ pub fn get_const_val(cx: &CrateContext, } match cx.tcx().map.expect_item(def_id.node).node { - ast::ItemStatic(_, ast::MutImmutable, _) => { - trans_const(cx, ast::MutImmutable, def_id.node); - } + ast::ItemConst(..) => { base::get_item_val(cx, def_id.node); } _ => {} } } - (cx.const_values().borrow().get_copy(&def_id.node), - !cx.non_inlineable_statics().borrow().contains(&def_id.node)) + cx.const_values().borrow().get_copy(&def_id.node) } -pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool, ty::t) { - let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local); +pub fn const_expr(cx: &CrateContext, e: &ast::Expr) -> (ValueRef, ty::t) { + let llconst = const_expr_unadjusted(cx, e); let mut llconst = llconst; - let mut inlineable = inlineable; let ety = ty::expr_ty(cx.tcx(), e); let mut ety_adjusted = ty::expr_ty_adjusted(cx.tcx(), e); let opt_adj = cx.tcx().adjustments.borrow().find_copy(&e.id); @@ -213,7 +204,7 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef ety_adjusted, def, llconst, - is_local); + true); llconst = C_struct(cx, [wrapper, C_null(Type::i8p(cx))], false) } ty::AdjustAddEnv(store) => { @@ -250,7 +241,6 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef // Don't copy data to do a deref+ref // (i.e., skip the last auto-deref). if adj.autoderefs == 0 { - inlineable = false; llconst = const_addr_of(cx, llconst, ast::MutImmutable); } } @@ -271,7 +261,6 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef match ty::get(ty).sty { ty::ty_vec(unit_ty, Some(len)) => { - inlineable = false; let llunitty = type_of::type_of(cx, unit_ty); let llptr = const_ptrcast(cx, llconst, llunitty); assert_eq!(abi::slice_elt_base, 0); @@ -314,29 +303,25 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef e.repr(cx.tcx()), ty_to_string(cx.tcx(), ety), csize, tsize).as_slice()); } - (llconst, inlineable, ety_adjusted) + (llconst, ety_adjusted) } // the bool returned is whether this expression can be inlined into other crates // if it's assigned to a static. -fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, - is_local: bool) -> (ValueRef, bool) { +fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef { let map_list = |exprs: &[P]| { - exprs.iter().map(|e| first_two(const_expr(cx, &**e, is_local))) - .fold((Vec::new(), true), - |(l, all_inlineable), (val, inlineable)| { - (l.append_one(val), all_inlineable && inlineable) - }) + exprs.iter().map(|e| const_expr(cx, &**e).val0()) + .fold(Vec::new(), |l, val| l.append_one(val)) }; unsafe { let _icx = push_ctxt("const_expr"); return match e.node { ast::ExprLit(ref lit) => { - (consts::const_lit(cx, e, &**lit), true) + consts::const_lit(cx, e, &**lit) } ast::ExprBinary(b, ref e1, ref e2) => { - let (te1, _, _) = const_expr(cx, &**e1, is_local); - let (te2, _, _) = const_expr(cx, &**e2, is_local); + let (te1, _) = const_expr(cx, &**e1); + let (te2, _) = const_expr(cx, &**e2); let te2 = base::cast_shift_const_rhs(b, te1, te2); @@ -345,7 +330,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, let ty = ty::expr_ty(cx.tcx(), &**e1); let is_float = ty::type_is_fp(ty); let signed = ty::type_is_signed(ty); - return (match b { + return match b { ast::BiAdd => { if is_float { llvm::LLVMConstFAdd(te1, te2) } else { llvm::LLVMConstAdd(te1, te2) } @@ -414,13 +399,13 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, else { ConstICmp(IntUGT, te1, te2) } } }, - }, true) + } }, ast::ExprUnary(u, ref e) => { - let (te, _, _) = const_expr(cx, &**e, is_local); + let (te, _) = const_expr(cx, &**e); let ty = ty::expr_ty(cx.tcx(), &**e); let is_float = ty::type_is_fp(ty); - return (match u { + return match u { ast::UnUniq | ast::UnDeref => { let (dv, _dt) = const_deref(cx, te, ty, true); dv @@ -430,26 +415,26 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, if is_float { llvm::LLVMConstFNeg(te) } else { llvm::LLVMConstNeg(te) } } - }, true) + } } ast::ExprField(ref base, field, _) => { - let (bv, inlineable, bt) = const_expr(cx, &**base, is_local); + let (bv, bt) = const_expr(cx, &**base); let brepr = adt::represent_type(cx, bt); expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| { let ix = ty::field_idx_strict(cx.tcx(), field.node.name, field_tys); - (adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable) + adt::const_get_field(cx, &*brepr, bv, discr, ix) }) } ast::ExprTupField(ref base, idx, _) => { - let (bv, inlineable, bt) = const_expr(cx, &**base, is_local); + let (bv, bt) = const_expr(cx, &**base); let brepr = adt::represent_type(cx, bt); expr::with_field_tys(cx.tcx(), bt, None, |discr, _| { - (adt::const_get_field(cx, &*brepr, bv, discr, idx.node), inlineable) + adt::const_get_field(cx, &*brepr, bv, discr, idx.node) }) } ast::ExprIndex(ref base, ref index) => { - let (bv, inlineable, bt) = const_expr(cx, &**base, is_local); + let (bv, bt) = const_expr(cx, &**base); let iv = match const_eval::eval_const_expr(cx.tcx(), &**index) { const_eval::const_int(i) => i as u64, const_eval::const_uint(u) => u, @@ -500,13 +485,13 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, cx.sess().span_err(e.span, "const index-expr is out of bounds"); } - (const_get_elt(cx, arr, [iv as c_uint]), inlineable) + const_get_elt(cx, arr, [iv as c_uint]) } ast::ExprCast(ref base, _) => { let ety = ty::expr_ty(cx.tcx(), e); let llty = type_of::type_of(cx, ety); - let (v, inlineable, basety) = const_expr(cx, &**base, is_local); - return (match (expr::cast_type_kind(cx.tcx(), basety), + let (v, basety) = const_expr(cx, &**base); + return match (expr::cast_type_kind(cx.tcx(), basety), expr::cast_type_kind(cx.tcx(), ety)) { (expr::cast_integral, expr::cast_integral) => { @@ -554,17 +539,38 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, cx.sess().impossible_case(e.span, "bad combination of types for cast") } - }, inlineable) + } } ast::ExprAddrOf(mutbl, ref sub) => { - let (e, _, _) = const_expr(cx, &**sub, is_local); - (const_addr_of(cx, e, mutbl), false) + // If this is the address of some static, then we need to return + // the actual address of the static itself (short circuit the rest + // of const eval). + let mut cur = sub; + loop { + match cur.node { + ast::ExprParen(ref sub) => cur = sub, + _ => break, + } + } + let opt_def = cx.tcx().def_map.borrow().find_copy(&cur.id); + match opt_def { + Some(def::DefStatic(def_id, _)) => { + let ty = ty::expr_ty(cx.tcx(), e); + return get_static_val(cx, def_id, ty); + } + _ => {} + } + + // If this isn't the address of a static, then keep going through + // normal constant evaluation. + let (e, _) = const_expr(cx, &**sub); + const_addr_of(cx, e, mutbl) } ast::ExprTup(ref es) => { let ety = ty::expr_ty(cx.tcx(), e); let repr = adt::represent_type(cx, ety); - let (vals, inlineable) = map_list(es.as_slice()); - (adt::trans_const(cx, &*repr, 0, vals.as_slice()), inlineable) + let vals = map_list(es.as_slice()); + adt::trans_const(cx, &*repr, 0, vals.as_slice()) } ast::ExprStruct(_, ref fs, ref base_opt) => { let ety = ty::expr_ty(cx.tcx(), e); @@ -572,36 +578,34 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, let tcx = cx.tcx(); let base_val = match *base_opt { - Some(ref base) => Some(const_expr(cx, &**base, is_local)), + Some(ref base) => Some(const_expr(cx, &**base)), None => None }; expr::with_field_tys(tcx, ety, Some(e.id), |discr, field_tys| { - let (cs, inlineable) = vec::unzip(field_tys.iter().enumerate() - .map(|(ix, &field_ty)| { + let cs = field_tys.iter().enumerate() + .map(|(ix, &field_ty)| { match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) { - Some(ref f) => first_two(const_expr(cx, &*f.expr, is_local)), + Some(ref f) => const_expr(cx, &*f.expr).val0(), None => { match base_val { - Some((bv, inlineable, _)) => { - (adt::const_get_field(cx, &*repr, bv, discr, ix), - inlineable) - } - None => cx.sess().span_bug(e.span, "missing struct field") + Some((bv, _)) => { + adt::const_get_field(cx, &*repr, bv, + discr, ix) + } + None => { + cx.sess().span_bug(e.span, + "missing struct field") + } } } } - })); - (adt::trans_const(cx, &*repr, discr, cs.as_slice()), - inlineable.iter().fold(true, |a, &b| a && b)) + }).collect::>(); + adt::trans_const(cx, &*repr, discr, cs.as_slice()) }) } ast::ExprVec(ref es) => { - let (v, _, inlineable) = const_vec(cx, - e, - es.as_slice(), - is_local); - (v, inlineable) + const_vec(cx, e, es.as_slice()).val0() } ast::ExprRepeat(ref elem, ref count) => { let vec_ty = ty::expr_ty(cx.tcx(), e); @@ -612,13 +616,12 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, const_eval::const_uint(i) => i as uint, _ => cx.sess().span_bug(count.span, "count must be integral const expression.") }; - let vs = Vec::from_elem(n, const_expr(cx, &**elem, is_local).val0()); - let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) { + let vs = Vec::from_elem(n, const_expr(cx, &**elem).val0()); + if vs.iter().any(|vi| val_ty(*vi) != llunitty) { C_struct(cx, vs.as_slice(), false) } else { C_array(llunitty, vs.as_slice()) - }; - (v, true) + } } ast::ExprPath(ref pth) => { // Assert that there are no type parameters in this path. @@ -629,13 +632,13 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, Some(def::DefFn(def_id, _fn_style, _)) => { if !ast_util::is_local(def_id) { let ty = csearch::get_type(cx.tcx(), def_id).ty; - (base::trans_external_path(cx, def_id, ty), true) + base::trans_external_path(cx, def_id, ty) } else { assert!(ast_util::is_local(def_id)); - (base::get_item_val(cx, def_id.node), true) + base::get_item_val(cx, def_id.node) } } - Some(def::DefStatic(def_id, false)) => { + Some(def::DefConst(def_id)) => { get_const_val(cx, def_id) } Some(def::DefVariant(enum_did, variant_did, _)) => { @@ -644,15 +647,16 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, let vinfo = ty::enum_variant_with_id(cx.tcx(), enum_did, variant_did); - (adt::trans_const(cx, &*repr, vinfo.disr_val, []), true) + adt::trans_const(cx, &*repr, vinfo.disr_val, []) } Some(def::DefStruct(_)) => { let ety = ty::expr_ty(cx.tcx(), e); let llty = type_of::type_of(cx, ety); - (C_null(llty), true) + C_null(llty) } _ => { - cx.sess().span_bug(e.span, "expected a const, fn, struct, or variant def") + cx.sess().span_bug(e.span, "expected a const, fn, struct, \ + or variant def") } } } @@ -662,9 +666,8 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, Some(def::DefStruct(_)) => { let ety = ty::expr_ty(cx.tcx(), e); let repr = adt::represent_type(cx, ety); - let (arg_vals, inlineable) = map_list(args.as_slice()); - (adt::trans_const(cx, &*repr, 0, arg_vals.as_slice()), - inlineable) + let arg_vals = map_list(args.as_slice()); + adt::trans_const(cx, &*repr, 0, arg_vals.as_slice()) } Some(def::DefVariant(enum_did, variant_did, _)) => { let ety = ty::expr_ty(cx.tcx(), e); @@ -672,20 +675,20 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, let vinfo = ty::enum_variant_with_id(cx.tcx(), enum_did, variant_did); - let (arg_vals, inlineable) = map_list(args.as_slice()); - (adt::trans_const(cx, - &*repr, - vinfo.disr_val, - arg_vals.as_slice()), inlineable) + let arg_vals = map_list(args.as_slice()); + adt::trans_const(cx, + &*repr, + vinfo.disr_val, + arg_vals.as_slice()) } _ => cx.sess().span_bug(e.span, "expected a struct or variant def") } } - ast::ExprParen(ref e) => first_two(const_expr(cx, &**e, is_local)), + ast::ExprParen(ref e) => const_expr(cx, &**e).val0(), ast::ExprBlock(ref block) => { match block.expr { - Some(ref expr) => first_two(const_expr(cx, &**expr, is_local)), - None => (C_nil(cx), true) + Some(ref expr) => const_expr(cx, &**expr).val0(), + None => C_nil(cx) } } _ => cx.sess().span_bug(e.span, @@ -694,13 +697,13 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr, } } -pub fn trans_const(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { +pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { unsafe { - let _icx = push_ctxt("trans_const"); + let _icx = push_ctxt("trans_static"); let g = base::get_item_val(ccx, id); // At this point, get_item_val has already translated the // constant's initializer to determine its LLVM type. - let v = ccx.const_values().borrow().get_copy(&id); + let v = ccx.static_values().borrow().get_copy(&id); // boolean SSA values are i1, but they have to be stored in i8 slots, // otherwise some LLVM optimization passes don't work as expected let v = if llvm::LLVMTypeOf(v) == Type::i1(ccx).to_ref() { @@ -710,17 +713,20 @@ pub fn trans_const(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { }; llvm::LLVMSetInitializer(g, v); - // `get_item_val` left `g` with external linkage, but we just set an - // initializer for it. But we don't know yet if `g` should really be - // defined in this compilation unit, so we set its linkage to - // `AvailableExternallyLinkage`. (It's still a definition, but acts - // like a declaration for most purposes.) If `g` really should be - // declared here, then `trans_item` will fix up the linkage later on. - llvm::SetLinkage(g, llvm::AvailableExternallyLinkage); - + // As an optimization, all shared statics which do not have interior + // mutability are placed into read-only memory. if m != ast::MutMutable { - llvm::LLVMSetGlobalConstant(g, True); + let node_ty = ty::node_id_to_type(ccx.tcx(), id); + let tcontents = ty::type_contents(ccx.tcx(), node_ty); + if !tcontents.interior_unsafe() { + llvm::LLVMSetGlobalConstant(g, True); + } } debuginfo::create_global_var_metadata(ccx, id, g); } } + +fn get_static_val(ccx: &CrateContext, did: ast::DefId, ty: ty::t) -> ValueRef { + if ast_util::is_local(did) { return base::get_item_val(ccx, did.node) } + base::trans_external_path(ccx, did, ty) +} diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index 5c8c6a24b4fa5..ee5ba61a295cf 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -66,10 +66,6 @@ pub struct SharedCrateContext<'tcx> { reachable: NodeSet, item_symbols: RefCell>, 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, symbol_hasher: RefCell, tcx: ty::ctxt<'tcx>, stats: Stats, @@ -121,6 +117,9 @@ pub struct LocalCrateContext { /// Cache of emitted const values const_values: RefCell>, + /// Cache of emitted static values + static_values: RefCell>, + /// Cache of external const values extern_const_values: RefCell>, @@ -259,7 +258,6 @@ impl<'tcx> SharedCrateContext<'tcx> { 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 @@ impl<'tcx> SharedCrateContext<'tcx> { &self.link_meta } - pub fn non_inlineable_statics<'a>(&'a self) -> &'a RefCell { - &self.non_inlineable_statics - } - pub fn symbol_hasher<'a>(&'a self) -> &'a RefCell { &self.symbol_hasher } @@ -414,6 +408,7 @@ impl LocalCrateContext { 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 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.external_srcs } - pub fn non_inlineable_statics<'a>(&'a self) -> &'a RefCell { - &self.shared.non_inlineable_statics - } - pub fn monomorphized<'a>(&'a self) -> &'a RefCell> { &self.local.monomorphized } @@ -638,6 +629,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.const_values } + pub fn static_values<'a>(&'a self) -> &'a RefCell> { + &self.local.static_values + } + pub fn extern_const_values<'a>(&'a self) -> &'a RefCell> { &self.local.extern_const_values } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index a2b7cb159d9dc..ec92f935c49be 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -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, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index cd4ad85d0942c..19c9c5e0119d2 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -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 trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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()) } diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index e5c8d4d0ab343..048402782a6d9 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -17,7 +17,6 @@ use middle::ty; use syntax::ast; use syntax::ast_util::{local_def, PostExpansionMethod}; -use syntax::ast_util; fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) -> Option { @@ -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!(), }; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 10bc1da3acb54..e1491c1f49be2 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1374,6 +1374,7 @@ impl 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, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 4af71bfda8b35..68bb3fcf94544 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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)); diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs index 587aa072fa863..4c3cec1aff42f 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc/middle/typeck/check/wf.rs @@ -69,6 +69,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { 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)] diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 40c52fd36b9c1..0b5c86fea7123 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -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); diff --git a/src/librustc/middle/typeck/infer/test.rs b/src/librustc/middle/typeck/infer/test.rs index 29cd2e77e8b1f..6ef2143b624f8 100644 --- a/src/librustc/middle/typeck/infer/test.rs +++ b/src/librustc/middle/typeck/infer/test.rs @@ -197,7 +197,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } return match it.node { - ast::ItemStatic(..) | ast::ItemFn(..) | + ast::ItemConst(..) | ast::ItemStatic(..) | ast::ItemFn(..) | ast::ItemForeignMod(..) | ast::ItemTy(..) => { None } diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 9317ba2c7fa93..60a7aa7790442 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -384,6 +384,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { ast::ItemImpl(..) | ast::ItemStatic(..) | + ast::ItemConst(..) | ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemForeignMod(..) | @@ -528,6 +529,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { } ast::ItemStatic(..) | + ast::ItemConst(..) | ast::ItemFn(..) | ast::ItemMod(..) | ast::ItemForeignMod(..) | diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 0a87c0a344e52..c47d6b0fc9dc8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1309,6 +1309,7 @@ pub struct Item { #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub enum Item_ { ItemStatic(P, Mutability, P), + ItemConst(P, P), ItemFn(P, FnStyle, Abi, Generics, P), ItemMod(Mod), ItemForeignMod(ForeignMod), diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 257bfc632d882..2d0cea2fefc9d 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -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", diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index f746e1f14822a..f51c2985f0bf4 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -12,8 +12,6 @@ use abi::Abi; 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 diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 1fdb6dd505f45..87983e1aea3a9 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -250,6 +250,13 @@ pub trait AstBuilder { expr: P) -> P; + fn item_const(&self, + span: Span, + name: Ident, + ty: P, + expr: P) + -> P; + fn item_ty_poly(&self, span: Span, name: Ident, @@ -1033,6 +1040,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.item(span, name, Vec::new(), ast::ItemStatic(ty, mutbl, expr)) } + fn item_const(&self, + span: Span, + name: Ident, + ty: P, + expr: P) + -> P { + self.item(span, name, Vec::new(), ast::ItemConst(ty, expr)) + } + fn item_ty_poly(&self, span: Span, name: Ident, ty: P, generics: Generics) -> P { self.item(span, name, Vec::new(), ast::ItemTy(ty, generics)) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 84de6c3b91339..32e226361e9d4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -903,6 +903,9 @@ pub fn noop_fold_item_underscore(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), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9bfb593786ef1..e73ffd7e58123 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -32,7 +32,7 @@ use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind}; 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 @@ impl<'a> Parser<'a> { } } - fn parse_item_const(&mut self, m: Mutability) -> ItemInfo { + fn parse_item_const(&mut self, m: Option) -> 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 { ... }` or `mod ;` item @@ -5296,7 +5300,7 @@ impl<'a> Parser<'a> { // 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 @@ impl<'a> Parser<'a> { 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, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c3a3848019a5d..321b00db47eaf 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -757,6 +757,20 @@ impl<'a> State<'a> { 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, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 3f5b524a9b5b2..9fb5742bb9b15 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -493,11 +493,10 @@ fn mk_tests(cx: &TestCtxt) -> P { 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 { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 249f87d3102dd..5c7b144f4ab6e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -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); } diff --git a/src/test/compile-fail/issue-17718-const-destructors.rs b/src/test/compile-fail/issue-17718-const-destructors.rs new file mode 100644 index 0000000000000..dffbfe155646a --- /dev/null +++ b/src/test/compile-fail/issue-17718-const-destructors.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , 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() {}