diff --git a/src/etc/local_stage0.sh b/src/etc/local_stage0.sh index aee69a5c8bc58..fb455441910b8 100755 --- a/src/etc/local_stage0.sh +++ b/src/etc/local_stage0.sh @@ -55,6 +55,14 @@ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}extra*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_D cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}rust*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}std*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}syntax*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}flate*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}fmt_macros*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}getopts*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}graphviz*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}log*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}rbml*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}serialize*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ +cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}term*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/ # do not fail if one of the above fails, as all we need is a working rustc! exit 0 diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 7bdf9eaccc323..10e4ea1c3f055 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -525,14 +525,16 @@ impl ExactSizeIterator for Box {} /// } /// ``` #[rustc_paren_sugar] -#[unstable(feature = "fnbox", reason = "Newly introduced", issue = "28796")] +#[unstable(feature = "fnbox", + reason = "will be deprecated if and when Box becomes usable", issue = "28796")] pub trait FnBox { type Output; fn call_box(self: Box, args: A) -> Self::Output; } -#[unstable(feature = "fnbox", reason = "Newly introduced", issue = "28796")] +#[unstable(feature = "fnbox", + reason = "will be deprecated if and when Box becomes usable", issue = "28796")] impl FnBox for F where F: FnOnce { type Output = F::Output; @@ -542,7 +544,8 @@ impl FnBox for F where F: FnOnce } } -#[unstable(feature = "fnbox", reason = "Newly introduced", issue = "28796")] +#[unstable(feature = "fnbox", + reason = "will be deprecated if and when Box becomes usable", issue = "28796")] impl<'a, A, R> FnOnce for Box + 'a> { type Output = R; @@ -551,7 +554,8 @@ impl<'a, A, R> FnOnce for Box + 'a> { } } -#[unstable(feature = "fnbox", reason = "Newly introduced", issue = "28796")] +#[unstable(feature = "fnbox", + reason = "will be deprecated if and when Box becomes usable", issue = "28796")] impl<'a, A, R> FnOnce for Box + Send + 'a> { type Output = R; diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 306fad2328b62..eedf4c2c11f34 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -184,7 +184,7 @@ use boxed::Box; /// let len = story.len(); /// let capacity = story.capacity(); /// -/// // story has thirteen bytes +/// // story has nineteen bytes /// assert_eq!(19, len); /// /// // Now that we have our parts, we throw the story away. diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index cf3e45cf3de79..e141a92c3ee3d 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -142,13 +142,13 @@ pub enum Ordering { #[stable(feature = "rust1", since = "1.0.0")] Relaxed, /// When coupled with a store, all previous writes become visible - /// to another thread that performs a load with `Acquire` ordering + /// to the other threads that perform a load with `Acquire` ordering /// on the same value. #[stable(feature = "rust1", since = "1.0.0")] Release, /// When coupled with a load, all subsequent loads will see data /// written before a store with `Release` ordering on the same value - /// in another thread. + /// in other threads. #[stable(feature = "rust1", since = "1.0.0")] Acquire, /// When coupled with a load, uses `Acquire` ordering, and with a store diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 0026412013c8e..5ca99a7db67f5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -50,7 +50,6 @@ use std::collections::BTreeMap; use std::iter; use syntax::ast::*; use syntax::attr::{ThinAttributes, ThinAttributesExt}; -use syntax::errors::Handler; use syntax::ext::mtwt; use syntax::ptr::P; use syntax::codemap::{respan, Spanned, Span}; @@ -58,8 +57,6 @@ use syntax::parse::token; use syntax::std_inject; use syntax::visit::{self, Visitor}; -use std::cell::{Cell, RefCell}; - pub struct LoweringContext<'a> { crate_root: Option<&'static str>, // Use to assign ids to hir nodes that do not directly correspond to an ast node @@ -67,8 +64,8 @@ pub struct LoweringContext<'a> { // As we walk the AST we must keep track of the current 'parent' def id (in // the form of a DefIndex) so that if we create a new node which introduces // a definition, then we can properly create the def id. - parent_def: Cell>, - resolver: RefCell<&'a mut Resolver>, + parent_def: Option, + resolver: &'a mut Resolver, } pub trait Resolver { @@ -94,26 +91,58 @@ impl Resolver for DummyResolver { } } -impl<'a, 'hir> LoweringContext<'a> { - pub fn new(id_assigner: &'a NodeIdAssigner, - c: Option<&Crate>, - resolver: &'a mut Resolver) - -> LoweringContext<'a> { - let crate_root = c.and_then(|c| { - if std_inject::no_core(c) { - None - } else if std_inject::no_std(c) { - Some("core") - } else { - Some("std") - } - }); +pub fn lower_crate(krate: &Crate, id_assigner: &NodeIdAssigner, resolver: &mut Resolver) + -> hir::Crate { + LoweringContext { + crate_root: if std_inject::no_core(krate) { + None + } else if std_inject::no_std(krate) { + Some("core") + } else { + Some("std") + }, + id_assigner: id_assigner, + parent_def: None, + resolver: resolver, + }.lower_crate(krate) +} +impl<'a> LoweringContext<'a> { + pub fn testing_context(id_assigner: &'a NodeIdAssigner, resolver: &'a mut Resolver) -> Self { LoweringContext { - crate_root: crate_root, + crate_root: None, id_assigner: id_assigner, - parent_def: Cell::new(None), - resolver: RefCell::new(resolver), + parent_def: None, + resolver: resolver, + } + } + + fn lower_crate(&mut self, c: &Crate) -> hir::Crate { + struct ItemLowerer<'lcx, 'interner: 'lcx> { + items: BTreeMap, + lctx: &'lcx mut LoweringContext<'interner>, + } + + impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { + fn visit_item(&mut self, item: &'lcx Item) { + self.items.insert(item.id, self.lctx.lower_item(item)); + visit::walk_item(self, item); + } + } + + let items = { + let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: self }; + visit::walk_crate(&mut item_lowerer, c); + item_lowerer.items + }; + + hir::Crate { + module: self.lower_mod(&c.module), + attrs: self.lower_attrs(&c.attrs), + config: c.config.clone().into(), + span: c.span, + exported_macros: c.exported_macros.iter().map(|m| self.lower_macro_def(m)).collect(), + items: items, } } @@ -125,1893 +154,1811 @@ impl<'a, 'hir> LoweringContext<'a> { hir::Ident::from_name(token::gensym(s)) } - // Panics if this LoweringContext's NodeIdAssigner is not able to emit diagnostics. - fn diagnostic(&self) -> &Handler { - self.id_assigner.diagnostic() - } - - fn with_parent_def T>(&self, parent_id: NodeId, f: F) -> T { - let old_def = self.parent_def.get(); - self.parent_def.set(match self.resolver.borrow_mut().definitions() { + fn with_parent_def(&mut self, parent_id: NodeId, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let old_def = self.parent_def; + self.parent_def = match self.resolver.definitions() { Some(defs) => Some(defs.opt_def_index(parent_id).unwrap()), None => old_def, - }); + }; - let result = f(); + let result = f(self); - self.parent_def.set(old_def); + self.parent_def = old_def; result } -} -pub fn lower_ident(_lctx: &LoweringContext, ident: Ident) -> hir::Ident { - hir::Ident { - name: mtwt::resolve(ident), - unhygienic_name: ident.name, + fn lower_ident(&mut self, ident: Ident) -> hir::Ident { + hir::Ident { + name: mtwt::resolve(ident), + unhygienic_name: ident.name, + } } -} - -pub fn lower_attrs(_lctx: &LoweringContext, attrs: &Vec) -> hir::HirVec { - attrs.clone().into() -} -pub fn lower_view_path(lctx: &LoweringContext, view_path: &ViewPath) -> P { - P(Spanned { - node: match view_path.node { - ViewPathSimple(ident, ref path) => { - hir::ViewPathSimple(ident.name, lower_path(lctx, path)) - } - ViewPathGlob(ref path) => { - hir::ViewPathGlob(lower_path(lctx, path)) - } - ViewPathList(ref path, ref path_list_idents) => { - hir::ViewPathList(lower_path(lctx, path), - path_list_idents.iter() - .map(lower_path_list_item) - .collect()) - } - }, - span: view_path.span, - }) -} + fn lower_attrs(&mut self, attrs: &Vec) -> hir::HirVec { + attrs.clone().into() + } -fn lower_path_list_item(path_list_ident: &PathListItem) -> hir::PathListItem { - Spanned { - node: match path_list_ident.node { - PathListItemKind::Ident { id, name, rename } => hir::PathListIdent { - id: id, - name: name.name, - rename: rename.map(|x| x.name), + fn lower_view_path(&mut self, view_path: &ViewPath) -> P { + P(Spanned { + node: match view_path.node { + ViewPathSimple(ident, ref path) => { + hir::ViewPathSimple(ident.name, self.lower_path(path)) + } + ViewPathGlob(ref path) => { + hir::ViewPathGlob(self.lower_path(path)) + } + ViewPathList(ref path, ref path_list_idents) => { + hir::ViewPathList(self.lower_path(path), + path_list_idents.iter() + .map(|item| self.lower_path_list_item(item)) + .collect()) + } }, - PathListItemKind::Mod { id, rename } => hir::PathListMod { - id: id, - rename: rename.map(|x| x.name), + span: view_path.span, + }) + } + + fn lower_path_list_item(&mut self, path_list_ident: &PathListItem) -> hir::PathListItem { + Spanned { + node: match path_list_ident.node { + PathListItemKind::Ident { id, name, rename } => hir::PathListIdent { + id: id, + name: name.name, + rename: rename.map(|x| x.name), + }, + PathListItemKind::Mod { id, rename } => hir::PathListMod { + id: id, + rename: rename.map(|x| x.name), + }, }, - }, - span: path_list_ident.span, + span: path_list_ident.span, + } } -} -pub fn lower_arm(lctx: &LoweringContext, arm: &Arm) -> hir::Arm { - hir::Arm { - attrs: lower_attrs(lctx, &arm.attrs), - pats: arm.pats.iter().map(|x| lower_pat(lctx, x)).collect(), - guard: arm.guard.as_ref().map(|ref x| lower_expr(lctx, x)), - body: lower_expr(lctx, &arm.body), + fn lower_arm(&mut self, arm: &Arm) -> hir::Arm { + hir::Arm { + attrs: self.lower_attrs(&arm.attrs), + pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(), + guard: arm.guard.as_ref().map(|ref x| self.lower_expr(x)), + body: self.lower_expr(&arm.body), + } } -} -pub fn lower_decl(lctx: &LoweringContext, d: &Decl) -> P { - match d.node { - DeclKind::Local(ref l) => P(Spanned { - node: hir::DeclLocal(lower_local(lctx, l)), - span: d.span, - }), - DeclKind::Item(ref it) => P(Spanned { - node: hir::DeclItem(lower_item_id(lctx, it)), - span: d.span, - }), + fn lower_decl(&mut self, d: &Decl) -> P { + match d.node { + DeclKind::Local(ref l) => P(Spanned { + node: hir::DeclLocal(self.lower_local(l)), + span: d.span, + }), + DeclKind::Item(ref it) => P(Spanned { + node: hir::DeclItem(self.lower_item_id(it)), + span: d.span, + }), + } } -} -pub fn lower_ty_binding(lctx: &LoweringContext, b: &TypeBinding) -> hir::TypeBinding { - hir::TypeBinding { - id: b.id, - name: b.ident.name, - ty: lower_ty(lctx, &b.ty), - span: b.span, + fn lower_ty_binding(&mut self, b: &TypeBinding) -> hir::TypeBinding { + hir::TypeBinding { + id: b.id, + name: b.ident.name, + ty: self.lower_ty(&b.ty), + span: b.span, + } } -} -pub fn lower_ty(lctx: &LoweringContext, t: &Ty) -> P { - use syntax::ast::TyKind::*; - P(hir::Ty { - id: t.id, - node: match t.node { - Infer => hir::TyInfer, - Vec(ref ty) => hir::TyVec(lower_ty(lctx, ty)), - Ptr(ref mt) => hir::TyPtr(lower_mt(lctx, mt)), - Rptr(ref region, ref mt) => { - hir::TyRptr(lower_opt_lifetime(lctx, region), lower_mt(lctx, mt)) - } - BareFn(ref f) => { - hir::TyBareFn(P(hir::BareFnTy { - lifetimes: lower_lifetime_defs(lctx, &f.lifetimes), - unsafety: lower_unsafety(lctx, f.unsafety), - abi: f.abi, - decl: lower_fn_decl(lctx, &f.decl), - })) - } - Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(lctx, ty)).collect()), - Paren(ref ty) => { - return lower_ty(lctx, ty); - } - Path(ref qself, ref path) => { - let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { - hir::QSelf { - ty: lower_ty(lctx, ty), - position: position, - } - }); - hir::TyPath(qself, lower_path(lctx, path)) - } - ObjectSum(ref ty, ref bounds) => { - hir::TyObjectSum(lower_ty(lctx, ty), lower_bounds(lctx, bounds)) - } - FixedLengthVec(ref ty, ref e) => { - hir::TyFixedLengthVec(lower_ty(lctx, ty), lower_expr(lctx, e)) - } - Typeof(ref expr) => { - hir::TyTypeof(lower_expr(lctx, expr)) - } - PolyTraitRef(ref bounds) => { - hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(lctx, b)).collect()) - } - Mac(_) => panic!("TyMac should have been expanded by now."), - }, - span: t.span, - }) -} + fn lower_ty(&mut self, t: &Ty) -> P { + use syntax::ast::TyKind::*; + P(hir::Ty { + id: t.id, + node: match t.node { + Infer => hir::TyInfer, + Vec(ref ty) => hir::TyVec(self.lower_ty(ty)), + Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), + Rptr(ref region, ref mt) => { + hir::TyRptr(self.lower_opt_lifetime(region), self.lower_mt(mt)) + } + BareFn(ref f) => { + hir::TyBareFn(P(hir::BareFnTy { + lifetimes: self.lower_lifetime_defs(&f.lifetimes), + unsafety: self.lower_unsafety(f.unsafety), + abi: f.abi, + decl: self.lower_fn_decl(&f.decl), + })) + } + Tup(ref tys) => hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect()), + Paren(ref ty) => { + return self.lower_ty(ty); + } + Path(ref qself, ref path) => { + let qself = qself.as_ref().map(|&QSelf { ref ty, position }| { + hir::QSelf { + ty: self.lower_ty(ty), + position: position, + } + }); + hir::TyPath(qself, self.lower_path(path)) + } + ObjectSum(ref ty, ref bounds) => { + hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds)) + } + FixedLengthVec(ref ty, ref e) => { + hir::TyFixedLengthVec(self.lower_ty(ty), self.lower_expr(e)) + } + Typeof(ref expr) => { + hir::TyTypeof(self.lower_expr(expr)) + } + PolyTraitRef(ref bounds) => { + let bounds = bounds.iter().map(|b| self.lower_ty_param_bound(b)).collect(); + hir::TyPolyTraitRef(bounds) + } + Mac(_) => panic!("TyMac should have been expanded by now."), + }, + span: t.span, + }) + } -pub fn lower_foreign_mod(lctx: &LoweringContext, fm: &ForeignMod) -> hir::ForeignMod { - hir::ForeignMod { - abi: fm.abi, - items: fm.items.iter().map(|x| lower_foreign_item(lctx, x)).collect(), + fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod { + hir::ForeignMod { + abi: fm.abi, + items: fm.items.iter().map(|x| self.lower_foreign_item(x)).collect(), + } } -} -pub fn lower_variant(lctx: &LoweringContext, v: &Variant) -> hir::Variant { - Spanned { - node: hir::Variant_ { - name: v.node.name.name, - attrs: lower_attrs(lctx, &v.node.attrs), - data: lower_variant_data(lctx, &v.node.data), - disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(lctx, e)), - }, - span: v.span, + fn lower_variant(&mut self, v: &Variant) -> hir::Variant { + Spanned { + node: hir::Variant_ { + name: v.node.name.name, + attrs: self.lower_attrs(&v.node.attrs), + data: self.lower_variant_data(&v.node.data), + disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_expr(e)), + }, + span: v.span, + } } -} -// Path segments are usually unhygienic, hygienic path segments can occur only in -// identifier-like paths originating from `ExprPath`. -// Make life simpler for rustc_resolve by renaming only such segments. -pub fn lower_path_full(lctx: &LoweringContext, p: &Path, maybe_hygienic: bool) -> hir::Path { - let maybe_hygienic = maybe_hygienic && !p.global && p.segments.len() == 1; - hir::Path { - global: p.global, - segments: p.segments - .iter() - .map(|&PathSegment { identifier, ref parameters }| { - hir::PathSegment { - identifier: if maybe_hygienic { - lower_ident(lctx, identifier) - } else { - hir::Ident::from_name(identifier.name) - }, - parameters: lower_path_parameters(lctx, parameters), - } - }) - .collect(), - span: p.span, + // Path segments are usually unhygienic, hygienic path segments can occur only in + // identifier-like paths originating from `ExprPath`. + // Make life simpler for rustc_resolve by renaming only such segments. + fn lower_path_full(&mut self, p: &Path, maybe_hygienic: bool) -> hir::Path { + let maybe_hygienic = maybe_hygienic && !p.global && p.segments.len() == 1; + hir::Path { + global: p.global, + segments: p.segments + .iter() + .map(|&PathSegment { identifier, ref parameters }| { + hir::PathSegment { + identifier: if maybe_hygienic { + self.lower_ident(identifier) + } else { + hir::Ident::from_name(identifier.name) + }, + parameters: self.lower_path_parameters(parameters), + } + }) + .collect(), + span: p.span, + } } -} -pub fn lower_path(lctx: &LoweringContext, p: &Path) -> hir::Path { - lower_path_full(lctx, p, false) -} + fn lower_path(&mut self, p: &Path) -> hir::Path { + self.lower_path_full(p, false) + } -pub fn lower_path_parameters(lctx: &LoweringContext, - path_parameters: &PathParameters) - -> hir::PathParameters { - match *path_parameters { - PathParameters::AngleBracketed(ref data) => - hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(lctx, data)), - PathParameters::Parenthesized(ref data) => - hir::ParenthesizedParameters(lower_parenthesized_parameter_data(lctx, data)), + fn lower_path_parameters(&mut self, path_parameters: &PathParameters) -> hir::PathParameters { + match *path_parameters { + PathParameters::AngleBracketed(ref data) => + hir::AngleBracketedParameters(self.lower_angle_bracketed_parameter_data(data)), + PathParameters::Parenthesized(ref data) => + hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)), + } } -} -pub fn lower_angle_bracketed_parameter_data(lctx: &LoweringContext, + fn lower_angle_bracketed_parameter_data(&mut self, data: &AngleBracketedParameterData) -> hir::AngleBracketedParameterData { - let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings } = data; - hir::AngleBracketedParameterData { - lifetimes: lower_lifetimes(lctx, lifetimes), - types: types.iter().map(|ty| lower_ty(lctx, ty)).collect(), - bindings: bindings.iter().map(|b| lower_ty_binding(lctx, b)).collect(), + let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings } = data; + hir::AngleBracketedParameterData { + lifetimes: self.lower_lifetimes(lifetimes), + types: types.iter().map(|ty| self.lower_ty(ty)).collect(), + bindings: bindings.iter().map(|b| self.lower_ty_binding(b)).collect(), + } } -} -pub fn lower_parenthesized_parameter_data(lctx: &LoweringContext, + fn lower_parenthesized_parameter_data(&mut self, data: &ParenthesizedParameterData) -> hir::ParenthesizedParameterData { - let &ParenthesizedParameterData { ref inputs, ref output, span } = data; - hir::ParenthesizedParameterData { - inputs: inputs.iter().map(|ty| lower_ty(lctx, ty)).collect(), - output: output.as_ref().map(|ty| lower_ty(lctx, ty)), - span: span, - } -} - -pub fn lower_local(lctx: &LoweringContext, l: &Local) -> P { - P(hir::Local { - id: l.id, - ty: l.ty.as_ref().map(|t| lower_ty(lctx, t)), - pat: lower_pat(lctx, &l.pat), - init: l.init.as_ref().map(|e| lower_expr(lctx, e)), - span: l.span, - attrs: l.attrs.clone(), - }) -} - -pub fn lower_explicit_self_underscore(lctx: &LoweringContext, - es: &SelfKind) - -> hir::ExplicitSelf_ { - match *es { - SelfKind::Static => hir::SelfStatic, - SelfKind::Value(v) => hir::SelfValue(v.name), - SelfKind::Region(ref lifetime, m, ident) => { - hir::SelfRegion(lower_opt_lifetime(lctx, lifetime), - lower_mutability(lctx, m), - ident.name) - } - SelfKind::Explicit(ref typ, ident) => { - hir::SelfExplicit(lower_ty(lctx, typ), ident.name) + let &ParenthesizedParameterData { ref inputs, ref output, span } = data; + hir::ParenthesizedParameterData { + inputs: inputs.iter().map(|ty| self.lower_ty(ty)).collect(), + output: output.as_ref().map(|ty| self.lower_ty(ty)), + span: span, } } -} -pub fn lower_mutability(_lctx: &LoweringContext, m: Mutability) -> hir::Mutability { - match m { - Mutability::Mutable => hir::MutMutable, - Mutability::Immutable => hir::MutImmutable, + fn lower_local(&mut self, l: &Local) -> P { + P(hir::Local { + id: l.id, + ty: l.ty.as_ref().map(|t| self.lower_ty(t)), + pat: self.lower_pat(&l.pat), + init: l.init.as_ref().map(|e| self.lower_expr(e)), + span: l.span, + attrs: l.attrs.clone(), + }) } -} -pub fn lower_explicit_self(lctx: &LoweringContext, s: &ExplicitSelf) -> hir::ExplicitSelf { - Spanned { - node: lower_explicit_self_underscore(lctx, &s.node), - span: s.span, + fn lower_explicit_self_underscore(&mut self, es: &SelfKind) -> hir::ExplicitSelf_ { + match *es { + SelfKind::Static => hir::SelfStatic, + SelfKind::Value(v) => hir::SelfValue(v.name), + SelfKind::Region(ref lifetime, m, ident) => { + hir::SelfRegion(self.lower_opt_lifetime(lifetime), + self.lower_mutability(m), + ident.name) + } + SelfKind::Explicit(ref typ, ident) => { + hir::SelfExplicit(self.lower_ty(typ), ident.name) + } + } } -} -pub fn lower_arg(lctx: &LoweringContext, arg: &Arg) -> hir::Arg { - hir::Arg { - id: arg.id, - pat: lower_pat(lctx, &arg.pat), - ty: lower_ty(lctx, &arg.ty), + fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability { + match m { + Mutability::Mutable => hir::MutMutable, + Mutability::Immutable => hir::MutImmutable, + } } -} - -pub fn lower_fn_decl(lctx: &LoweringContext, decl: &FnDecl) -> P { - P(hir::FnDecl { - inputs: decl.inputs.iter().map(|x| lower_arg(lctx, x)).collect(), - output: match decl.output { - FunctionRetTy::Ty(ref ty) => hir::Return(lower_ty(lctx, ty)), - FunctionRetTy::Default(span) => hir::DefaultReturn(span), - FunctionRetTy::None(span) => hir::NoReturn(span), - }, - variadic: decl.variadic, - }) -} -pub fn lower_ty_param_bound(lctx: &LoweringContext, tpb: &TyParamBound) -> hir::TyParamBound { - match *tpb { - TraitTyParamBound(ref ty, modifier) => { - hir::TraitTyParamBound(lower_poly_trait_ref(lctx, ty), - lower_trait_bound_modifier(lctx, modifier)) - } - RegionTyParamBound(ref lifetime) => { - hir::RegionTyParamBound(lower_lifetime(lctx, lifetime)) + fn lower_explicit_self(&mut self, s: &ExplicitSelf) -> hir::ExplicitSelf { + Spanned { + node: self.lower_explicit_self_underscore(&s.node), + span: s.span, } } -} -pub fn lower_ty_param(lctx: &LoweringContext, tp: &TyParam) -> hir::TyParam { - hir::TyParam { - id: tp.id, - name: tp.ident.name, - bounds: lower_bounds(lctx, &tp.bounds), - default: tp.default.as_ref().map(|x| lower_ty(lctx, x)), - span: tp.span, + fn lower_arg(&mut self, arg: &Arg) -> hir::Arg { + hir::Arg { + id: arg.id, + pat: self.lower_pat(&arg.pat), + ty: self.lower_ty(&arg.ty), + } } -} - -pub fn lower_ty_params(lctx: &LoweringContext, - tps: &P<[TyParam]>) - -> hir::HirVec { - tps.iter().map(|tp| lower_ty_param(lctx, tp)).collect() -} -pub fn lower_lifetime(_lctx: &LoweringContext, l: &Lifetime) -> hir::Lifetime { - hir::Lifetime { - id: l.id, - name: l.name, - span: l.span, + fn lower_fn_decl(&mut self, decl: &FnDecl) -> P { + P(hir::FnDecl { + inputs: decl.inputs.iter().map(|x| self.lower_arg(x)).collect(), + output: match decl.output { + FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)), + FunctionRetTy::Default(span) => hir::DefaultReturn(span), + FunctionRetTy::None(span) => hir::NoReturn(span), + }, + variadic: decl.variadic, + }) } -} -pub fn lower_lifetime_def(lctx: &LoweringContext, l: &LifetimeDef) -> hir::LifetimeDef { - hir::LifetimeDef { - lifetime: lower_lifetime(lctx, &l.lifetime), - bounds: lower_lifetimes(lctx, &l.bounds), + fn lower_ty_param_bound(&mut self, tpb: &TyParamBound) -> hir::TyParamBound { + match *tpb { + TraitTyParamBound(ref ty, modifier) => { + hir::TraitTyParamBound(self.lower_poly_trait_ref(ty), + self.lower_trait_bound_modifier(modifier)) + } + RegionTyParamBound(ref lifetime) => { + hir::RegionTyParamBound(self.lower_lifetime(lifetime)) + } + } } -} - -pub fn lower_lifetimes(lctx: &LoweringContext, lts: &Vec) -> hir::HirVec { - lts.iter().map(|l| lower_lifetime(lctx, l)).collect() -} - -pub fn lower_lifetime_defs(lctx: &LoweringContext, - lts: &Vec) - -> hir::HirVec { - lts.iter().map(|l| lower_lifetime_def(lctx, l)).collect() -} - -pub fn lower_opt_lifetime(lctx: &LoweringContext, - o_lt: &Option) - -> Option { - o_lt.as_ref().map(|lt| lower_lifetime(lctx, lt)) -} -pub fn lower_generics(lctx: &LoweringContext, g: &Generics) -> hir::Generics { - hir::Generics { - ty_params: lower_ty_params(lctx, &g.ty_params), - lifetimes: lower_lifetime_defs(lctx, &g.lifetimes), - where_clause: lower_where_clause(lctx, &g.where_clause), + fn lower_ty_param(&mut self, tp: &TyParam) -> hir::TyParam { + hir::TyParam { + id: tp.id, + name: tp.ident.name, + bounds: self.lower_bounds(&tp.bounds), + default: tp.default.as_ref().map(|x| self.lower_ty(x)), + span: tp.span, + } } -} -pub fn lower_where_clause(lctx: &LoweringContext, wc: &WhereClause) -> hir::WhereClause { - hir::WhereClause { - id: wc.id, - predicates: wc.predicates - .iter() - .map(|predicate| lower_where_predicate(lctx, predicate)) - .collect(), + fn lower_ty_params(&mut self, tps: &P<[TyParam]>) -> hir::HirVec { + tps.iter().map(|tp| self.lower_ty_param(tp)).collect() } -} -pub fn lower_where_predicate(lctx: &LoweringContext, - pred: &WherePredicate) - -> hir::WherePredicate { - match *pred { - WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_lifetimes, - ref bounded_ty, - ref bounds, - span}) => { - hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - bound_lifetimes: lower_lifetime_defs(lctx, bound_lifetimes), - bounded_ty: lower_ty(lctx, bounded_ty), - bounds: bounds.iter().map(|x| lower_ty_param_bound(lctx, x)).collect(), - span: span, - }) - } - WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime, - ref bounds, - span}) => { - hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - span: span, - lifetime: lower_lifetime(lctx, lifetime), - bounds: bounds.iter().map(|bound| lower_lifetime(lctx, bound)).collect(), - }) - } - WherePredicate::EqPredicate(WhereEqPredicate{ id, - ref path, - ref ty, - span}) => { - hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - id: id, - path: lower_path(lctx, path), - ty: lower_ty(lctx, ty), - span: span, - }) + fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { + hir::Lifetime { + id: l.id, + name: l.name, + span: l.span, } } -} -pub fn lower_variant_data(lctx: &LoweringContext, vdata: &VariantData) -> hir::VariantData { - match *vdata { - VariantData::Struct(ref fields, id) => { - hir::VariantData::Struct(fields.iter() - .enumerate() - .map(|f| lower_struct_field(lctx, f)) - .collect(), - id) + fn lower_lifetime_def(&mut self, l: &LifetimeDef) -> hir::LifetimeDef { + hir::LifetimeDef { + lifetime: self.lower_lifetime(&l.lifetime), + bounds: self.lower_lifetimes(&l.bounds), } - VariantData::Tuple(ref fields, id) => { - hir::VariantData::Tuple(fields.iter() - .enumerate() - .map(|f| lower_struct_field(lctx, f)) - .collect(), - id) - } - VariantData::Unit(id) => hir::VariantData::Unit(id), } -} -pub fn lower_trait_ref(lctx: &LoweringContext, p: &TraitRef) -> hir::TraitRef { - hir::TraitRef { - path: lower_path(lctx, &p.path), - ref_id: p.ref_id, + fn lower_lifetimes(&mut self, lts: &Vec) -> hir::HirVec { + lts.iter().map(|l| self.lower_lifetime(l)).collect() } -} -pub fn lower_poly_trait_ref(lctx: &LoweringContext, p: &PolyTraitRef) -> hir::PolyTraitRef { - hir::PolyTraitRef { - bound_lifetimes: lower_lifetime_defs(lctx, &p.bound_lifetimes), - trait_ref: lower_trait_ref(lctx, &p.trait_ref), - span: p.span, + fn lower_lifetime_defs(&mut self, lts: &Vec) -> hir::HirVec { + lts.iter().map(|l| self.lower_lifetime_def(l)).collect() } -} -pub fn lower_struct_field(lctx: &LoweringContext, - (index, f): (usize, &StructField)) - -> hir::StructField { - hir::StructField { - span: f.span, - id: f.id, - name: f.ident.map(|ident| ident.name).unwrap_or(token::intern(&index.to_string())), - vis: lower_visibility(lctx, &f.vis), - ty: lower_ty(lctx, &f.ty), - attrs: lower_attrs(lctx, &f.attrs), + fn lower_opt_lifetime(&mut self, o_lt: &Option) -> Option { + o_lt.as_ref().map(|lt| self.lower_lifetime(lt)) } -} -pub fn lower_field(lctx: &LoweringContext, f: &Field) -> hir::Field { - hir::Field { - name: respan(f.ident.span, f.ident.node.name), - expr: lower_expr(lctx, &f.expr), - span: f.span, + fn lower_generics(&mut self, g: &Generics) -> hir::Generics { + hir::Generics { + ty_params: self.lower_ty_params(&g.ty_params), + lifetimes: self.lower_lifetime_defs(&g.lifetimes), + where_clause: self.lower_where_clause(&g.where_clause), + } } -} -pub fn lower_mt(lctx: &LoweringContext, mt: &MutTy) -> hir::MutTy { - hir::MutTy { - ty: lower_ty(lctx, &mt.ty), - mutbl: lower_mutability(lctx, mt.mutbl), + fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause { + hir::WhereClause { + id: wc.id, + predicates: wc.predicates + .iter() + .map(|predicate| self.lower_where_predicate(predicate)) + .collect(), + } } -} - -pub fn lower_opt_bounds(lctx: &LoweringContext, - b: &Option) - -> Option { - b.as_ref().map(|ref bounds| lower_bounds(lctx, bounds)) -} - -fn lower_bounds(lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParamBounds { - bounds.iter().map(|bound| lower_ty_param_bound(lctx, bound)).collect() -} -pub fn lower_block(lctx: &LoweringContext, b: &Block) -> P { - P(hir::Block { - id: b.id, - stmts: b.stmts.iter().map(|s| lower_stmt(lctx, s)).collect(), - expr: b.expr.as_ref().map(|ref x| lower_expr(lctx, x)), - rules: lower_block_check_mode(lctx, &b.rules), - span: b.span, - }) -} - -pub fn lower_item_kind(lctx: &LoweringContext, i: &ItemKind) -> hir::Item_ { - match *i { - ItemKind::ExternCrate(string) => hir::ItemExternCrate(string), - ItemKind::Use(ref view_path) => { - hir::ItemUse(lower_view_path(lctx, view_path)) - } - ItemKind::Static(ref t, m, ref e) => { - hir::ItemStatic(lower_ty(lctx, t), - lower_mutability(lctx, m), - lower_expr(lctx, e)) - } - ItemKind::Const(ref t, ref e) => { - hir::ItemConst(lower_ty(lctx, t), lower_expr(lctx, e)) - } - ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { - hir::ItemFn(lower_fn_decl(lctx, decl), - lower_unsafety(lctx, unsafety), - lower_constness(lctx, constness), - abi, - lower_generics(lctx, generics), - lower_block(lctx, body)) - } - ItemKind::Mod(ref m) => hir::ItemMod(lower_mod(lctx, m)), - ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(lctx, nm)), - ItemKind::Ty(ref t, ref generics) => { - hir::ItemTy(lower_ty(lctx, t), lower_generics(lctx, generics)) - } - ItemKind::Enum(ref enum_definition, ref generics) => { - hir::ItemEnum(hir::EnumDef { - variants: enum_definition.variants - .iter() - .map(|x| lower_variant(lctx, x)) - .collect(), - }, - lower_generics(lctx, generics)) + fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate { + match *pred { + WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_lifetimes, + ref bounded_ty, + ref bounds, + span}) => { + hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bound_lifetimes: self.lower_lifetime_defs(bound_lifetimes), + bounded_ty: self.lower_ty(bounded_ty), + bounds: bounds.iter().map(|x| self.lower_ty_param_bound(x)).collect(), + span: span, + }) + } + WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime, + ref bounds, + span}) => { + hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + span: span, + lifetime: self.lower_lifetime(lifetime), + bounds: bounds.iter().map(|bound| self.lower_lifetime(bound)).collect(), + }) + } + WherePredicate::EqPredicate(WhereEqPredicate{ id, + ref path, + ref ty, + span}) => { + hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { + id: id, + path: self.lower_path(path), + ty: self.lower_ty(ty), + span: span, + }) + } } - ItemKind::Struct(ref struct_def, ref generics) => { - let struct_def = lower_variant_data(lctx, struct_def); - hir::ItemStruct(struct_def, lower_generics(lctx, generics)) + } + + fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData { + match *vdata { + VariantData::Struct(ref fields, id) => { + hir::VariantData::Struct(fields.iter() + .enumerate() + .map(|f| self.lower_struct_field(f)) + .collect(), + id) + } + VariantData::Tuple(ref fields, id) => { + hir::VariantData::Tuple(fields.iter() + .enumerate() + .map(|f| self.lower_struct_field(f)) + .collect(), + id) + } + VariantData::Unit(id) => hir::VariantData::Unit(id), } - ItemKind::DefaultImpl(unsafety, ref trait_ref) => { - hir::ItemDefaultImpl(lower_unsafety(lctx, unsafety), - lower_trait_ref(lctx, trait_ref)) + } + + fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { + hir::TraitRef { + path: self.lower_path(&p.path), + ref_id: p.ref_id, } - ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { - let new_impl_items = impl_items.iter() - .map(|item| lower_impl_item(lctx, item)) - .collect(); - let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(lctx, trait_ref)); - hir::ItemImpl(lower_unsafety(lctx, unsafety), - lower_impl_polarity(lctx, polarity), - lower_generics(lctx, generics), - ifce, - lower_ty(lctx, ty), - new_impl_items) + } + + fn lower_poly_trait_ref(&mut self, p: &PolyTraitRef) -> hir::PolyTraitRef { + hir::PolyTraitRef { + bound_lifetimes: self.lower_lifetime_defs(&p.bound_lifetimes), + trait_ref: self.lower_trait_ref(&p.trait_ref), + span: p.span, } - ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => { - let bounds = lower_bounds(lctx, bounds); - let items = items.iter().map(|item| lower_trait_item(lctx, item)).collect(); - hir::ItemTrait(lower_unsafety(lctx, unsafety), - lower_generics(lctx, generics), - bounds, - items) + } + + fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField { + hir::StructField { + span: f.span, + id: f.id, + name: f.ident.map(|ident| ident.name).unwrap_or(token::intern(&index.to_string())), + vis: self.lower_visibility(&f.vis), + ty: self.lower_ty(&f.ty), + attrs: self.lower_attrs(&f.attrs), } - ItemKind::Mac(_) => panic!("Shouldn't still be around"), } -} -pub fn lower_trait_item(lctx: &LoweringContext, i: &TraitItem) -> hir::TraitItem { - lctx.with_parent_def(i.id, || { - hir::TraitItem { - id: i.id, - name: i.ident.name, - attrs: lower_attrs(lctx, &i.attrs), - node: match i.node { - TraitItemKind::Const(ref ty, ref default) => { - hir::ConstTraitItem(lower_ty(lctx, ty), - default.as_ref().map(|x| lower_expr(lctx, x))) - } - TraitItemKind::Method(ref sig, ref body) => { - hir::MethodTraitItem(lower_method_sig(lctx, sig), - body.as_ref().map(|x| lower_block(lctx, x))) - } - TraitItemKind::Type(ref bounds, ref default) => { - hir::TypeTraitItem(lower_bounds(lctx, bounds), - default.as_ref().map(|x| lower_ty(lctx, x))) - } - }, - span: i.span, + fn lower_field(&mut self, f: &Field) -> hir::Field { + hir::Field { + name: respan(f.ident.span, f.ident.node.name), + expr: self.lower_expr(&f.expr), + span: f.span, } - }) -} + } -pub fn lower_impl_item(lctx: &LoweringContext, i: &ImplItem) -> hir::ImplItem { - lctx.with_parent_def(i.id, || { - hir::ImplItem { - id: i.id, - name: i.ident.name, - attrs: lower_attrs(lctx, &i.attrs), - vis: lower_visibility(lctx, &i.vis), - defaultness: lower_defaultness(lctx, i.defaultness), - node: match i.node { - ImplItemKind::Const(ref ty, ref expr) => { - hir::ImplItemKind::Const(lower_ty(lctx, ty), lower_expr(lctx, expr)) - } - ImplItemKind::Method(ref sig, ref body) => { - hir::ImplItemKind::Method(lower_method_sig(lctx, sig), lower_block(lctx, body)) - } - ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(lower_ty(lctx, ty)), - ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), - }, - span: i.span, + fn lower_mt(&mut self, mt: &MutTy) -> hir::MutTy { + hir::MutTy { + ty: self.lower_ty(&mt.ty), + mutbl: self.lower_mutability(mt.mutbl), } - }) -} + } -pub fn lower_mod(lctx: &LoweringContext, m: &Mod) -> hir::Mod { - hir::Mod { - inner: m.inner, - item_ids: m.items.iter().map(|x| lower_item_id(lctx, x)).collect(), + fn lower_bounds(&mut self, bounds: &TyParamBounds) -> hir::TyParamBounds { + bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect() } -} -struct ItemLowerer<'lcx, 'interner: 'lcx> { - items: BTreeMap, - lctx: &'lcx LoweringContext<'interner>, -} + fn lower_block(&mut self, b: &Block) -> P { + P(hir::Block { + id: b.id, + stmts: b.stmts.iter().map(|s| self.lower_stmt(s)).collect(), + expr: b.expr.as_ref().map(|ref x| self.lower_expr(x)), + rules: self.lower_block_check_mode(&b.rules), + span: b.span, + }) + } -impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> { - fn visit_item(&mut self, item: &'lcx Item) { - self.items.insert(item.id, lower_item(self.lctx, item)); - visit::walk_item(self, item); + fn lower_item_kind(&mut self, i: &ItemKind) -> hir::Item_ { + match *i { + ItemKind::ExternCrate(string) => hir::ItemExternCrate(string), + ItemKind::Use(ref view_path) => { + hir::ItemUse(self.lower_view_path(view_path)) + } + ItemKind::Static(ref t, m, ref e) => { + hir::ItemStatic(self.lower_ty(t), + self.lower_mutability(m), + self.lower_expr(e)) + } + ItemKind::Const(ref t, ref e) => { + hir::ItemConst(self.lower_ty(t), self.lower_expr(e)) + } + ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { + hir::ItemFn(self.lower_fn_decl(decl), + self.lower_unsafety(unsafety), + self.lower_constness(constness), + abi, + self.lower_generics(generics), + self.lower_block(body)) + } + ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), + ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), + ItemKind::Ty(ref t, ref generics) => { + hir::ItemTy(self.lower_ty(t), self.lower_generics(generics)) + } + ItemKind::Enum(ref enum_definition, ref generics) => { + hir::ItemEnum(hir::EnumDef { + variants: enum_definition.variants + .iter() + .map(|x| self.lower_variant(x)) + .collect(), + }, + self.lower_generics(generics)) + } + ItemKind::Struct(ref struct_def, ref generics) => { + let struct_def = self.lower_variant_data(struct_def); + hir::ItemStruct(struct_def, self.lower_generics(generics)) + } + ItemKind::DefaultImpl(unsafety, ref trait_ref) => { + hir::ItemDefaultImpl(self.lower_unsafety(unsafety), + self.lower_trait_ref(trait_ref)) + } + ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { + let new_impl_items = impl_items.iter() + .map(|item| self.lower_impl_item(item)) + .collect(); + let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref)); + hir::ItemImpl(self.lower_unsafety(unsafety), + self.lower_impl_polarity(polarity), + self.lower_generics(generics), + ifce, + self.lower_ty(ty), + new_impl_items) + } + ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => { + let bounds = self.lower_bounds(bounds); + let items = items.iter().map(|item| self.lower_trait_item(item)).collect(); + hir::ItemTrait(self.lower_unsafety(unsafety), + self.lower_generics(generics), + bounds, + items) + } + ItemKind::Mac(_) => panic!("Shouldn't still be around"), + } } -} -pub fn lower_crate(lctx: &LoweringContext, c: &Crate) -> hir::Crate { - let items = { - let mut item_lowerer = ItemLowerer { items: BTreeMap::new(), lctx: lctx }; - visit::walk_crate(&mut item_lowerer, c); - item_lowerer.items - }; - - hir::Crate { - module: lower_mod(lctx, &c.module), - attrs: lower_attrs(lctx, &c.attrs), - config: c.config.clone().into(), - span: c.span, - exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(lctx, m)).collect(), - items: items, + fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { + self.with_parent_def(i.id, |this| { + hir::TraitItem { + id: i.id, + name: i.ident.name, + attrs: this.lower_attrs(&i.attrs), + node: match i.node { + TraitItemKind::Const(ref ty, ref default) => { + hir::ConstTraitItem(this.lower_ty(ty), + default.as_ref().map(|x| this.lower_expr(x))) + } + TraitItemKind::Method(ref sig, ref body) => { + hir::MethodTraitItem(this.lower_method_sig(sig), + body.as_ref().map(|x| this.lower_block(x))) + } + TraitItemKind::Type(ref bounds, ref default) => { + hir::TypeTraitItem(this.lower_bounds(bounds), + default.as_ref().map(|x| this.lower_ty(x))) + } + }, + span: i.span, + } + }) } -} -pub fn lower_macro_def(lctx: &LoweringContext, m: &MacroDef) -> hir::MacroDef { - hir::MacroDef { - name: m.ident.name, - attrs: lower_attrs(lctx, &m.attrs), - id: m.id, - span: m.span, - imported_from: m.imported_from.map(|x| x.name), - export: m.export, - use_locally: m.use_locally, - allow_internal_unstable: m.allow_internal_unstable, - body: m.body.clone().into(), + fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem { + self.with_parent_def(i.id, |this| { + hir::ImplItem { + id: i.id, + name: i.ident.name, + attrs: this.lower_attrs(&i.attrs), + vis: this.lower_visibility(&i.vis), + defaultness: this.lower_defaultness(i.defaultness), + node: match i.node { + ImplItemKind::Const(ref ty, ref expr) => { + hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr)) + } + ImplItemKind::Method(ref sig, ref body) => { + hir::ImplItemKind::Method(this.lower_method_sig(sig), + this.lower_block(body)) + } + ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)), + ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), + }, + span: i.span, + } + }) } -} -pub fn lower_item_id(_lctx: &LoweringContext, i: &Item) -> hir::ItemId { - hir::ItemId { id: i.id } -} + fn lower_mod(&mut self, m: &Mod) -> hir::Mod { + hir::Mod { + inner: m.inner, + item_ids: m.items.iter().map(|x| self.lower_item_id(x)).collect(), + } + } -pub fn lower_item(lctx: &LoweringContext, i: &Item) -> hir::Item { - let node = lctx.with_parent_def(i.id, || { - lower_item_kind(lctx, &i.node) - }); + fn lower_macro_def(&mut self, m: &MacroDef) -> hir::MacroDef { + hir::MacroDef { + name: m.ident.name, + attrs: self.lower_attrs(&m.attrs), + id: m.id, + span: m.span, + imported_from: m.imported_from.map(|x| x.name), + export: m.export, + use_locally: m.use_locally, + allow_internal_unstable: m.allow_internal_unstable, + body: m.body.clone().into(), + } + } - hir::Item { - id: i.id, - name: i.ident.name, - attrs: lower_attrs(lctx, &i.attrs), - node: node, - vis: lower_visibility(lctx, &i.vis), - span: i.span, + fn lower_item_id(&mut self, i: &Item) -> hir::ItemId { + hir::ItemId { id: i.id } } -} -pub fn lower_foreign_item(lctx: &LoweringContext, i: &ForeignItem) -> hir::ForeignItem { - lctx.with_parent_def(i.id, || { - hir::ForeignItem { + pub fn lower_item(&mut self, i: &Item) -> hir::Item { + let node = self.with_parent_def(i.id, |this| { + this.lower_item_kind(&i.node) + }); + + hir::Item { id: i.id, name: i.ident.name, - attrs: lower_attrs(lctx, &i.attrs), - node: match i.node { - ForeignItemKind::Fn(ref fdec, ref generics) => { - hir::ForeignItemFn(lower_fn_decl(lctx, fdec), lower_generics(lctx, generics)) - } - ForeignItemKind::Static(ref t, m) => { - hir::ForeignItemStatic(lower_ty(lctx, t), m) - } - }, - vis: lower_visibility(lctx, &i.vis), + attrs: self.lower_attrs(&i.attrs), + node: node, + vis: self.lower_visibility(&i.vis), span: i.span, } - }) -} + } -pub fn lower_method_sig(lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig { - hir::MethodSig { - generics: lower_generics(lctx, &sig.generics), - abi: sig.abi, - explicit_self: lower_explicit_self(lctx, &sig.explicit_self), - unsafety: lower_unsafety(lctx, sig.unsafety), - constness: lower_constness(lctx, sig.constness), - decl: lower_fn_decl(lctx, &sig.decl), + fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { + self.with_parent_def(i.id, |this| { + hir::ForeignItem { + id: i.id, + name: i.ident.name, + attrs: this.lower_attrs(&i.attrs), + node: match i.node { + ForeignItemKind::Fn(ref fdec, ref generics) => { + hir::ForeignItemFn(this.lower_fn_decl(fdec), this.lower_generics(generics)) + } + ForeignItemKind::Static(ref t, m) => { + hir::ForeignItemStatic(this.lower_ty(t), m) + } + }, + vis: this.lower_visibility(&i.vis), + span: i.span, + } + }) } -} -pub fn lower_unsafety(_lctx: &LoweringContext, u: Unsafety) -> hir::Unsafety { - match u { - Unsafety::Unsafe => hir::Unsafety::Unsafe, - Unsafety::Normal => hir::Unsafety::Normal, + fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig { + hir::MethodSig { + generics: self.lower_generics(&sig.generics), + abi: sig.abi, + explicit_self: self.lower_explicit_self(&sig.explicit_self), + unsafety: self.lower_unsafety(sig.unsafety), + constness: self.lower_constness(sig.constness), + decl: self.lower_fn_decl(&sig.decl), + } } -} -pub fn lower_constness(_lctx: &LoweringContext, c: Constness) -> hir::Constness { - match c { - Constness::Const => hir::Constness::Const, - Constness::NotConst => hir::Constness::NotConst, + fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety { + match u { + Unsafety::Unsafe => hir::Unsafety::Unsafe, + Unsafety::Normal => hir::Unsafety::Normal, + } } -} -pub fn lower_unop(_lctx: &LoweringContext, u: UnOp) -> hir::UnOp { - match u { - UnOp::Deref => hir::UnDeref, - UnOp::Not => hir::UnNot, - UnOp::Neg => hir::UnNeg, + fn lower_constness(&mut self, c: Constness) -> hir::Constness { + match c { + Constness::Const => hir::Constness::Const, + Constness::NotConst => hir::Constness::NotConst, + } } -} -pub fn lower_binop(_lctx: &LoweringContext, b: BinOp) -> hir::BinOp { - Spanned { - node: match b.node { - BinOpKind::Add => hir::BiAdd, - BinOpKind::Sub => hir::BiSub, - BinOpKind::Mul => hir::BiMul, - BinOpKind::Div => hir::BiDiv, - BinOpKind::Rem => hir::BiRem, - BinOpKind::And => hir::BiAnd, - BinOpKind::Or => hir::BiOr, - BinOpKind::BitXor => hir::BiBitXor, - BinOpKind::BitAnd => hir::BiBitAnd, - BinOpKind::BitOr => hir::BiBitOr, - BinOpKind::Shl => hir::BiShl, - BinOpKind::Shr => hir::BiShr, - BinOpKind::Eq => hir::BiEq, - BinOpKind::Lt => hir::BiLt, - BinOpKind::Le => hir::BiLe, - BinOpKind::Ne => hir::BiNe, - BinOpKind::Ge => hir::BiGe, - BinOpKind::Gt => hir::BiGt, - }, - span: b.span, + fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { + match u { + UnOp::Deref => hir::UnDeref, + UnOp::Not => hir::UnNot, + UnOp::Neg => hir::UnNeg, + } } -} -pub fn lower_pat(lctx: &LoweringContext, p: &Pat) -> P { - P(hir::Pat { - id: p.id, - node: match p.node { - PatKind::Wild => hir::PatKind::Wild, - PatKind::Ident(ref binding_mode, pth1, ref sub) => { - lctx.with_parent_def(p.id, || { - hir::PatKind::Ident(lower_binding_mode(lctx, binding_mode), - respan(pth1.span, lower_ident(lctx, pth1.node)), - sub.as_ref().map(|x| lower_pat(lctx, x))) - }) - } - PatKind::Lit(ref e) => hir::PatKind::Lit(lower_expr(lctx, e)), - PatKind::TupleStruct(ref pth, ref pats) => { - hir::PatKind::TupleStruct(lower_path(lctx, pth), - pats.as_ref() - .map(|pats| pats.iter().map(|x| lower_pat(lctx, x)).collect())) - } - PatKind::Path(ref pth) => { - hir::PatKind::Path(lower_path(lctx, pth)) - } - PatKind::QPath(ref qself, ref pth) => { - let qself = hir::QSelf { - ty: lower_ty(lctx, &qself.ty), - position: qself.position, - }; - hir::PatKind::QPath(qself, lower_path(lctx, pth)) - } - PatKind::Struct(ref pth, ref fields, etc) => { - let pth = lower_path(lctx, pth); - let fs = fields.iter() - .map(|f| { - Spanned { - span: f.span, - node: hir::FieldPat { - name: f.node.ident.name, - pat: lower_pat(lctx, &f.node.pat), - is_shorthand: f.node.is_shorthand, - }, - } - }) - .collect(); - hir::PatKind::Struct(pth, fs, etc) - } - PatKind::Tup(ref elts) => { - hir::PatKind::Tup(elts.iter().map(|x| lower_pat(lctx, x)).collect()) - } - PatKind::Box(ref inner) => hir::PatKind::Box(lower_pat(lctx, inner)), - PatKind::Ref(ref inner, mutbl) => { - hir::PatKind::Ref(lower_pat(lctx, inner), lower_mutability(lctx, mutbl)) - } - PatKind::Range(ref e1, ref e2) => { - hir::PatKind::Range(lower_expr(lctx, e1), lower_expr(lctx, e2)) - } - PatKind::Vec(ref before, ref slice, ref after) => { - hir::PatKind::Vec(before.iter().map(|x| lower_pat(lctx, x)).collect(), - slice.as_ref().map(|x| lower_pat(lctx, x)), - after.iter().map(|x| lower_pat(lctx, x)).collect()) - } - PatKind::Mac(_) => panic!("Shouldn't exist here"), - }, - span: p.span, - }) -} + fn lower_binop(&mut self, b: BinOp) -> hir::BinOp { + Spanned { + node: match b.node { + BinOpKind::Add => hir::BiAdd, + BinOpKind::Sub => hir::BiSub, + BinOpKind::Mul => hir::BiMul, + BinOpKind::Div => hir::BiDiv, + BinOpKind::Rem => hir::BiRem, + BinOpKind::And => hir::BiAnd, + BinOpKind::Or => hir::BiOr, + BinOpKind::BitXor => hir::BiBitXor, + BinOpKind::BitAnd => hir::BiBitAnd, + BinOpKind::BitOr => hir::BiBitOr, + BinOpKind::Shl => hir::BiShl, + BinOpKind::Shr => hir::BiShr, + BinOpKind::Eq => hir::BiEq, + BinOpKind::Lt => hir::BiLt, + BinOpKind::Le => hir::BiLe, + BinOpKind::Ne => hir::BiNe, + BinOpKind::Ge => hir::BiGe, + BinOpKind::Gt => hir::BiGt, + }, + span: b.span, + } + } -pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P { - P(hir::Expr { - id: e.id, - node: match e.node { - // Issue #22181: - // Eventually a desugaring for `box EXPR` - // (similar to the desugaring above for `in PLACE BLOCK`) - // should go here, desugaring - // - // to: - // - // let mut place = BoxPlace::make_place(); - // let raw_place = Place::pointer(&mut place); - // let value = $value; - // unsafe { - // ::std::ptr::write(raw_place, value); - // Boxed::finalize(place) - // } - // - // But for now there are type-inference issues doing that. - ExprKind::Box(ref e) => { - hir::ExprBox(lower_expr(lctx, e)) - } + fn lower_pat(&mut self, p: &Pat) -> P { + P(hir::Pat { + id: p.id, + node: match p.node { + PatKind::Wild => hir::PatKind::Wild, + PatKind::Ident(ref binding_mode, pth1, ref sub) => { + self.with_parent_def(p.id, |this| { + hir::PatKind::Ident(this.lower_binding_mode(binding_mode), + respan(pth1.span, this.lower_ident(pth1.node)), + sub.as_ref().map(|x| this.lower_pat(x))) + }) + } + PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), + PatKind::TupleStruct(ref pth, ref pats) => { + hir::PatKind::TupleStruct(self.lower_path(pth), + pats.as_ref() + .map(|pats| pats.iter().map(|x| self.lower_pat(x)).collect())) + } + PatKind::Path(ref pth) => { + hir::PatKind::Path(self.lower_path(pth)) + } + PatKind::QPath(ref qself, ref pth) => { + let qself = hir::QSelf { + ty: self.lower_ty(&qself.ty), + position: qself.position, + }; + hir::PatKind::QPath(qself, self.lower_path(pth)) + } + PatKind::Struct(ref pth, ref fields, etc) => { + let pth = self.lower_path(pth); + let fs = fields.iter() + .map(|f| { + Spanned { + span: f.span, + node: hir::FieldPat { + name: f.node.ident.name, + pat: self.lower_pat(&f.node.pat), + is_shorthand: f.node.is_shorthand, + }, + } + }) + .collect(); + hir::PatKind::Struct(pth, fs, etc) + } + PatKind::Tup(ref elts) => { + hir::PatKind::Tup(elts.iter().map(|x| self.lower_pat(x)).collect()) + } + PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)), + PatKind::Ref(ref inner, mutbl) => { + hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl)) + } + PatKind::Range(ref e1, ref e2) => { + hir::PatKind::Range(self.lower_expr(e1), self.lower_expr(e2)) + } + PatKind::Vec(ref before, ref slice, ref after) => { + hir::PatKind::Vec(before.iter().map(|x| self.lower_pat(x)).collect(), + slice.as_ref().map(|x| self.lower_pat(x)), + after.iter().map(|x| self.lower_pat(x)).collect()) + } + PatKind::Mac(_) => panic!("Shouldn't exist here"), + }, + span: p.span, + }) + } - // Desugar ExprBox: `in (PLACE) EXPR` - ExprKind::InPlace(ref placer, ref value_expr) => { + fn lower_expr(&mut self, e: &Expr) -> P { + P(hir::Expr { + id: e.id, + node: match e.node { + // Issue #22181: + // Eventually a desugaring for `box EXPR` + // (similar to the desugaring above for `in PLACE BLOCK`) + // should go here, desugaring + // // to: // - // let p = PLACE; - // let mut place = Placer::make_place(p); + // let mut place = BoxPlace::make_place(); // let raw_place = Place::pointer(&mut place); - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let placer_expr = lower_expr(lctx, placer); - let value_expr = lower_expr(lctx, value_expr); - - let placer_ident = lctx.str_to_ident("placer"); - let place_ident = lctx.str_to_ident("place"); - let p_ptr_ident = lctx.str_to_ident("p_ptr"); - - let make_place = ["ops", "Placer", "make_place"]; - let place_pointer = ["ops", "Place", "pointer"]; - let move_val_init = ["intrinsics", "move_val_init"]; - let inplace_finalize = ["ops", "InPlace", "finalize"]; - - let make_call = |lctx: &LoweringContext, p, args| { - let path = core_path(lctx, e.span, p); - let path = expr_path(lctx, path, None); - expr_call(lctx, e.span, path, args, None) - }; - - let mk_stmt_let = |lctx: &LoweringContext, bind, expr| { - stmt_let(lctx, e.span, false, bind, expr, None) - }; - - let mk_stmt_let_mut = |lctx: &LoweringContext, bind, expr| { - stmt_let(lctx, e.span, true, bind, expr, None) - }; - - // let placer = ; - let (s1, placer_binding) = { - let placer_expr = signal_block_expr(lctx, - hir_vec![], - placer_expr, - e.span, - hir::PopUnstableBlock, - None); - mk_stmt_let(lctx, placer_ident, placer_expr) - }; - - // let mut place = Placer::make_place(placer); - let (s2, place_binding) = { - let placer = expr_ident(lctx, e.span, placer_ident, None, placer_binding); - let call = make_call(lctx, &make_place, hir_vec![placer]); - mk_stmt_let_mut(lctx, place_ident, call) - }; - - // let p_ptr = Place::pointer(&mut place); - let (s3, p_ptr_binding) = { - let agent = expr_ident(lctx, e.span, place_ident, None, place_binding); - let args = hir_vec![expr_mut_addr_of(lctx, e.span, agent, None)]; - let call = make_call(lctx, &place_pointer, args); - mk_stmt_let(lctx, p_ptr_ident, call) - }; - - // pop_unsafe!(EXPR)); - let pop_unsafe_expr = { - let value_expr = signal_block_expr(lctx, - hir_vec![], - value_expr, - e.span, - hir::PopUnstableBlock, - None); - signal_block_expr(lctx, - hir_vec![], - value_expr, - e.span, - hir::PopUnsafeBlock(hir::CompilerGenerated), None) - }; - - // push_unsafe!({ - // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); - // InPlace::finalize(place) - // }) - let expr = { - let ptr = expr_ident(lctx, e.span, p_ptr_ident, None, p_ptr_binding); - let call_move_val_init = - hir::StmtSemi( - make_call(lctx, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), - lctx.next_id()); - let call_move_val_init = respan(e.span, call_move_val_init); - - let place = expr_ident(lctx, e.span, place_ident, None, place_binding); - let call = make_call(lctx, &inplace_finalize, hir_vec![place]); - signal_block_expr(lctx, - hir_vec![call_move_val_init], - call, - e.span, - hir::PushUnsafeBlock(hir::CompilerGenerated), None) - }; - - return signal_block_expr(lctx, - hir_vec![s1, s2, s3], - expr, - e.span, - hir::PushUnstableBlock, - e.attrs.clone()); - } + // let value = $value; + // unsafe { + // ::std::ptr::write(raw_place, value); + // Boxed::finalize(place) + // } + // + // But for now there are type-inference issues doing that. + ExprKind::Box(ref e) => { + hir::ExprBox(self.lower_expr(e)) + } - ExprKind::Vec(ref exprs) => { - hir::ExprVec(exprs.iter().map(|x| lower_expr(lctx, x)).collect()) - } - ExprKind::Repeat(ref expr, ref count) => { - let expr = lower_expr(lctx, expr); - let count = lower_expr(lctx, count); - hir::ExprRepeat(expr, count) - } - ExprKind::Tup(ref elts) => { - hir::ExprTup(elts.iter().map(|x| lower_expr(lctx, x)).collect()) - } - ExprKind::Call(ref f, ref args) => { - let f = lower_expr(lctx, f); - hir::ExprCall(f, args.iter().map(|x| lower_expr(lctx, x)).collect()) - } - ExprKind::MethodCall(i, ref tps, ref args) => { - let tps = tps.iter().map(|x| lower_ty(lctx, x)).collect(); - let args = args.iter().map(|x| lower_expr(lctx, x)).collect(); - hir::ExprMethodCall(respan(i.span, i.node.name), tps, args) - } - ExprKind::Binary(binop, ref lhs, ref rhs) => { - let binop = lower_binop(lctx, binop); - let lhs = lower_expr(lctx, lhs); - let rhs = lower_expr(lctx, rhs); - hir::ExprBinary(binop, lhs, rhs) - } - ExprKind::Unary(op, ref ohs) => { - let op = lower_unop(lctx, op); - let ohs = lower_expr(lctx, ohs); - hir::ExprUnary(op, ohs) - } - ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())), - ExprKind::Cast(ref expr, ref ty) => { - let expr = lower_expr(lctx, expr); - hir::ExprCast(expr, lower_ty(lctx, ty)) - } - ExprKind::Type(ref expr, ref ty) => { - let expr = lower_expr(lctx, expr); - hir::ExprType(expr, lower_ty(lctx, ty)) - } - ExprKind::AddrOf(m, ref ohs) => { - let m = lower_mutability(lctx, m); - let ohs = lower_expr(lctx, ohs); - hir::ExprAddrOf(m, ohs) - } - // More complicated than you might expect because the else branch - // might be `if let`. - ExprKind::If(ref cond, ref blk, ref else_opt) => { - let else_opt = else_opt.as_ref().map(|els| { - match els.node { - ExprKind::IfLet(..) => { - // wrap the if-let expr in a block - let span = els.span; - let els = lower_expr(lctx, els); - let id = lctx.next_id(); - let blk = P(hir::Block { - stmts: hir_vec![], - expr: Some(els), - id: id, - rules: hir::DefaultBlock, - span: span, - }); - expr_block(lctx, blk, None) - } - _ => lower_expr(lctx, els), - } - }); + // Desugar ExprBox: `in (PLACE) EXPR` + ExprKind::InPlace(ref placer, ref value_expr) => { + // to: + // + // let p = PLACE; + // let mut place = Placer::make_place(p); + // let raw_place = Place::pointer(&mut place); + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let placer_expr = self.lower_expr(placer); + let value_expr = self.lower_expr(value_expr); + + let placer_ident = self.str_to_ident("placer"); + let place_ident = self.str_to_ident("place"); + let p_ptr_ident = self.str_to_ident("p_ptr"); + + let make_place = ["ops", "Placer", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let move_val_init = ["intrinsics", "move_val_init"]; + let inplace_finalize = ["ops", "InPlace", "finalize"]; + + let make_call = |this: &mut LoweringContext, p, args| { + let path = this.core_path(e.span, p); + let path = this.expr_path(path, None); + this.expr_call(e.span, path, args, None) + }; - hir::ExprIf(lower_expr(lctx, cond), lower_block(lctx, blk), else_opt) - } - ExprKind::While(ref cond, ref body, opt_ident) => { - hir::ExprWhile(lower_expr(lctx, cond), lower_block(lctx, body), - opt_ident.map(|ident| lower_ident(lctx, ident))) - } - ExprKind::Loop(ref body, opt_ident) => { - hir::ExprLoop(lower_block(lctx, body), - opt_ident.map(|ident| lower_ident(lctx, ident))) - } - ExprKind::Match(ref expr, ref arms) => { - hir::ExprMatch(lower_expr(lctx, expr), - arms.iter().map(|x| lower_arm(lctx, x)).collect(), - hir::MatchSource::Normal) - } - ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - lctx.with_parent_def(e.id, || { - hir::ExprClosure(lower_capture_clause(lctx, capture_clause), - lower_fn_decl(lctx, decl), - lower_block(lctx, body), - fn_decl_span) - }) - } - ExprKind::Block(ref blk) => hir::ExprBlock(lower_block(lctx, blk)), - ExprKind::Assign(ref el, ref er) => { - hir::ExprAssign(lower_expr(lctx, el), lower_expr(lctx, er)) - } - ExprKind::AssignOp(op, ref el, ref er) => { - hir::ExprAssignOp(lower_binop(lctx, op), - lower_expr(lctx, el), - lower_expr(lctx, er)) - } - ExprKind::Field(ref el, ident) => { - hir::ExprField(lower_expr(lctx, el), respan(ident.span, ident.node.name)) - } - ExprKind::TupField(ref el, ident) => { - hir::ExprTupField(lower_expr(lctx, el), ident) - } - ExprKind::Index(ref el, ref er) => { - hir::ExprIndex(lower_expr(lctx, el), lower_expr(lctx, er)) - } - ExprKind::Range(ref e1, ref e2, lims) => { - fn make_struct(lctx: &LoweringContext, - ast_expr: &Expr, - path: &[&str], - fields: &[(&str, &P)]) -> P { - let strs = std_path(lctx, &iter::once(&"ops") - .chain(path) - .map(|s| *s) - .collect::>()); - - let structpath = path_global(ast_expr.span, strs); - - let hir_expr = if fields.len() == 0 { - expr_path(lctx, - structpath, - ast_expr.attrs.clone()) - } else { - expr_struct(lctx, - ast_expr.span, - structpath, - fields.into_iter().map(|&(s, e)| { - field(token::intern(s), - signal_block_expr(lctx, - hir_vec![], - lower_expr(lctx, &**e), + let mk_stmt_let = |this: &mut LoweringContext, bind, expr| { + this.stmt_let(e.span, false, bind, expr, None) + }; + + let mk_stmt_let_mut = |this: &mut LoweringContext, bind, expr| { + this.stmt_let(e.span, true, bind, expr, None) + }; + + // let placer = ; + let (s1, placer_binding) = { + let placer_expr = self.signal_block_expr(hir_vec![], + placer_expr, + e.span, + hir::PopUnstableBlock, + None); + mk_stmt_let(self, placer_ident, placer_expr) + }; + + // let mut place = Placer::make_place(placer); + let (s2, place_binding) = { + let placer = self.expr_ident(e.span, placer_ident, None, placer_binding); + let call = make_call(self, &make_place, hir_vec![placer]); + mk_stmt_let_mut(self, place_ident, call) + }; + + // let p_ptr = Place::pointer(&mut place); + let (s3, p_ptr_binding) = { + let agent = self.expr_ident(e.span, place_ident, None, place_binding); + let args = hir_vec![self.expr_mut_addr_of(e.span, agent, None)]; + let call = make_call(self, &place_pointer, args); + mk_stmt_let(self, p_ptr_ident, call) + }; + + // pop_unsafe!(EXPR)); + let pop_unsafe_expr = { + let value_expr = self.signal_block_expr(hir_vec![], + value_expr, e.span, hir::PopUnstableBlock, - None), - ast_expr.span) - }).collect(), - None, - ast_expr.attrs.clone()) + None); + self.signal_block_expr(hir_vec![], + value_expr, + e.span, + hir::PopUnsafeBlock(hir::CompilerGenerated), None) }; - signal_block_expr(lctx, - hir_vec![], - hir_expr, - ast_expr.span, - hir::PushUnstableBlock, - None) + // push_unsafe!({ + // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR )); + // InPlace::finalize(place) + // }) + let expr = { + let ptr = self.expr_ident(e.span, p_ptr_ident, None, p_ptr_binding); + let call_move_val_init = + hir::StmtSemi( + make_call(self, &move_val_init, hir_vec![ptr, pop_unsafe_expr]), + self.next_id()); + let call_move_val_init = respan(e.span, call_move_val_init); + + let place = self.expr_ident(e.span, place_ident, None, place_binding); + let call = make_call(self, &inplace_finalize, hir_vec![place]); + self.signal_block_expr(hir_vec![call_move_val_init], + call, + e.span, + hir::PushUnsafeBlock(hir::CompilerGenerated), None) + }; + + return self.signal_block_expr(hir_vec![s1, s2, s3], + expr, + e.span, + hir::PushUnstableBlock, + e.attrs.clone()); } - use syntax::ast::RangeLimits::*; + ExprKind::Vec(ref exprs) => { + hir::ExprVec(exprs.iter().map(|x| self.lower_expr(x)).collect()) + } + ExprKind::Repeat(ref expr, ref count) => { + let expr = self.lower_expr(expr); + let count = self.lower_expr(count); + hir::ExprRepeat(expr, count) + } + ExprKind::Tup(ref elts) => { + hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect()) + } + ExprKind::Call(ref f, ref args) => { + let f = self.lower_expr(f); + hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect()) + } + ExprKind::MethodCall(i, ref tps, ref args) => { + let tps = tps.iter().map(|x| self.lower_ty(x)).collect(); + let args = args.iter().map(|x| self.lower_expr(x)).collect(); + hir::ExprMethodCall(respan(i.span, i.node.name), tps, args) + } + ExprKind::Binary(binop, ref lhs, ref rhs) => { + let binop = self.lower_binop(binop); + let lhs = self.lower_expr(lhs); + let rhs = self.lower_expr(rhs); + hir::ExprBinary(binop, lhs, rhs) + } + ExprKind::Unary(op, ref ohs) => { + let op = self.lower_unop(op); + let ohs = self.lower_expr(ohs); + hir::ExprUnary(op, ohs) + } + ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())), + ExprKind::Cast(ref expr, ref ty) => { + let expr = self.lower_expr(expr); + hir::ExprCast(expr, self.lower_ty(ty)) + } + ExprKind::Type(ref expr, ref ty) => { + let expr = self.lower_expr(expr); + hir::ExprType(expr, self.lower_ty(ty)) + } + ExprKind::AddrOf(m, ref ohs) => { + let m = self.lower_mutability(m); + let ohs = self.lower_expr(ohs); + hir::ExprAddrOf(m, ohs) + } + // More complicated than you might expect because the else branch + // might be `if let`. + ExprKind::If(ref cond, ref blk, ref else_opt) => { + let else_opt = else_opt.as_ref().map(|els| { + match els.node { + ExprKind::IfLet(..) => { + // wrap the if-let expr in a block + let span = els.span; + let els = self.lower_expr(els); + let id = self.next_id(); + let blk = P(hir::Block { + stmts: hir_vec![], + expr: Some(els), + id: id, + rules: hir::DefaultBlock, + span: span, + }); + self.expr_block(blk, None) + } + _ => self.lower_expr(els), + } + }); + + hir::ExprIf(self.lower_expr(cond), self.lower_block(blk), else_opt) + } + ExprKind::While(ref cond, ref body, opt_ident) => { + hir::ExprWhile(self.lower_expr(cond), self.lower_block(body), + opt_ident.map(|ident| self.lower_ident(ident))) + } + ExprKind::Loop(ref body, opt_ident) => { + hir::ExprLoop(self.lower_block(body), + opt_ident.map(|ident| self.lower_ident(ident))) + } + ExprKind::Match(ref expr, ref arms) => { + hir::ExprMatch(self.lower_expr(expr), + arms.iter().map(|x| self.lower_arm(x)).collect(), + hir::MatchSource::Normal) + } + ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { + self.with_parent_def(e.id, |this| { + hir::ExprClosure(this.lower_capture_clause(capture_clause), + this.lower_fn_decl(decl), + this.lower_block(body), + fn_decl_span) + }) + } + ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)), + ExprKind::Assign(ref el, ref er) => { + hir::ExprAssign(self.lower_expr(el), self.lower_expr(er)) + } + ExprKind::AssignOp(op, ref el, ref er) => { + hir::ExprAssignOp(self.lower_binop(op), + self.lower_expr(el), + self.lower_expr(er)) + } + ExprKind::Field(ref el, ident) => { + hir::ExprField(self.lower_expr(el), respan(ident.span, ident.node.name)) + } + ExprKind::TupField(ref el, ident) => { + hir::ExprTupField(self.lower_expr(el), ident) + } + ExprKind::Index(ref el, ref er) => { + hir::ExprIndex(self.lower_expr(el), self.lower_expr(er)) + } + ExprKind::Range(ref e1, ref e2, lims) => { + fn make_struct(this: &mut LoweringContext, + ast_expr: &Expr, + path: &[&str], + fields: &[(&str, &P)]) -> P { + let strs = this.std_path(&iter::once(&"ops") + .chain(path) + .map(|s| *s) + .collect::>()); + + let structpath = this.path_global(ast_expr.span, strs); + + let hir_expr = if fields.len() == 0 { + this.expr_path(structpath, ast_expr.attrs.clone()) + } else { + let fields = fields.into_iter().map(|&(s, e)| { + let expr = this.lower_expr(&e); + let signal_block = this.signal_block_expr(hir_vec![], + expr, + e.span, + hir::PopUnstableBlock, + None); + this.field(token::intern(s), signal_block, ast_expr.span) + }).collect(); + let attrs = ast_expr.attrs.clone(); + + this.expr_struct(ast_expr.span, structpath, fields, None, attrs) + }; + + this.signal_block_expr(hir_vec![], + hir_expr, + ast_expr.span, + hir::PushUnstableBlock, + None) + } - return match (e1, e2, lims) { - (&None, &None, HalfOpen) => - make_struct(lctx, e, &["RangeFull"], - &[]), + use syntax::ast::RangeLimits::*; - (&Some(ref e1), &None, HalfOpen) => - make_struct(lctx, e, &["RangeFrom"], - &[("start", e1)]), + return match (e1, e2, lims) { + (&None, &None, HalfOpen) => + make_struct(self, e, &["RangeFull"], &[]), - (&None, &Some(ref e2), HalfOpen) => - make_struct(lctx, e, &["RangeTo"], - &[("end", e2)]), + (&Some(ref e1), &None, HalfOpen) => + make_struct(self, e, &["RangeFrom"], + &[("start", e1)]), - (&Some(ref e1), &Some(ref e2), HalfOpen) => - make_struct(lctx, e, &["Range"], - &[("start", e1), ("end", e2)]), + (&None, &Some(ref e2), HalfOpen) => + make_struct(self, e, &["RangeTo"], + &[("end", e2)]), - (&None, &Some(ref e2), Closed) => - make_struct(lctx, e, &["RangeToInclusive"], - &[("end", e2)]), + (&Some(ref e1), &Some(ref e2), HalfOpen) => + make_struct(self, e, &["Range"], + &[("start", e1), ("end", e2)]), - (&Some(ref e1), &Some(ref e2), Closed) => - make_struct(lctx, e, &["RangeInclusive", "NonEmpty"], - &[("start", e1), ("end", e2)]), + (&None, &Some(ref e2), Closed) => + make_struct(self, e, &["RangeToInclusive"], + &[("end", e2)]), - _ => panic!(lctx.diagnostic().span_fatal(e.span, - "inclusive range with no end")) - }; - } - ExprKind::Path(ref qself, ref path) => { - let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| { - hir::QSelf { - ty: lower_ty(lctx, ty), - position: position, - } - }); - hir::ExprPath(hir_qself, lower_path_full(lctx, path, qself.is_none())) - } - ExprKind::Break(opt_ident) => hir::ExprBreak(opt_ident.map(|sp_ident| { - respan(sp_ident.span, lower_ident(lctx, sp_ident.node)) - })), - ExprKind::Again(opt_ident) => hir::ExprAgain(opt_ident.map(|sp_ident| { - respan(sp_ident.span, lower_ident(lctx, sp_ident.node)) - })), - ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(lctx, x))), - ExprKind::InlineAsm(InlineAsm { - ref inputs, - ref outputs, - ref asm, - asm_str_style, - ref clobbers, - volatile, - alignstack, - dialect, - expn_id, - }) => hir::ExprInlineAsm(hir::InlineAsm { - inputs: inputs.iter().map(|&(ref c, _)| c.clone()).collect(), - outputs: outputs.iter() - .map(|out| { - hir::InlineAsmOutput { - constraint: out.constraint.clone(), - is_rw: out.is_rw, - is_indirect: out.is_indirect, - } - }) - .collect(), - asm: asm.clone(), - asm_str_style: asm_str_style, - clobbers: clobbers.clone().into(), - volatile: volatile, - alignstack: alignstack, - dialect: dialect, - expn_id: expn_id, - }, outputs.iter().map(|out| lower_expr(lctx, &out.expr)).collect(), - inputs.iter().map(|&(_, ref input)| lower_expr(lctx, input)).collect()), - ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - hir::ExprStruct(lower_path(lctx, path), - fields.iter().map(|x| lower_field(lctx, x)).collect(), - maybe_expr.as_ref().map(|x| lower_expr(lctx, x))) - } - ExprKind::Paren(ref ex) => { - // merge attributes into the inner expression. - return lower_expr(lctx, ex).map(|mut ex| { - ex.attrs.update(|attrs| { - attrs.prepend(e.attrs.clone()) + (&Some(ref e1), &Some(ref e2), Closed) => + make_struct(self, e, &["RangeInclusive", "NonEmpty"], + &[("start", e1), ("end", e2)]), + + _ => panic!(self.id_assigner.diagnostic() + .span_fatal(e.span, "inclusive range with no end")), + }; + } + ExprKind::Path(ref qself, ref path) => { + let hir_qself = qself.as_ref().map(|&QSelf { ref ty, position }| { + hir::QSelf { + ty: self.lower_ty(ty), + position: position, + } }); - ex - }); - } + hir::ExprPath(hir_qself, self.lower_path_full(path, qself.is_none())) + } + ExprKind::Break(opt_ident) => hir::ExprBreak(opt_ident.map(|sp_ident| { + respan(sp_ident.span, self.lower_ident(sp_ident.node)) + })), + ExprKind::Again(opt_ident) => hir::ExprAgain(opt_ident.map(|sp_ident| { + respan(sp_ident.span, self.lower_ident(sp_ident.node)) + })), + ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| self.lower_expr(x))), + ExprKind::InlineAsm(InlineAsm { + ref inputs, + ref outputs, + ref asm, + asm_str_style, + ref clobbers, + volatile, + alignstack, + dialect, + expn_id, + }) => hir::ExprInlineAsm(hir::InlineAsm { + inputs: inputs.iter().map(|&(ref c, _)| c.clone()).collect(), + outputs: outputs.iter() + .map(|out| { + hir::InlineAsmOutput { + constraint: out.constraint.clone(), + is_rw: out.is_rw, + is_indirect: out.is_indirect, + } + }) + .collect(), + asm: asm.clone(), + asm_str_style: asm_str_style, + clobbers: clobbers.clone().into(), + volatile: volatile, + alignstack: alignstack, + dialect: dialect, + expn_id: expn_id, + }, outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(), + inputs.iter().map(|&(_, ref input)| self.lower_expr(input)).collect()), + ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { + hir::ExprStruct(self.lower_path(path), + fields.iter().map(|x| self.lower_field(x)).collect(), + maybe_expr.as_ref().map(|x| self.lower_expr(x))) + } + ExprKind::Paren(ref ex) => { + // merge attributes into the inner expression. + return self.lower_expr(ex).map(|mut ex| { + ex.attrs.update(|attrs| { + attrs.prepend(e.attrs.clone()) + }); + ex + }); + } - // Desugar ExprIfLet - // From: `if let = []` - ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { - // to: - // - // match { - // => , - // [_ if => ,] - // _ => [ | ()] - // } - - // ` => ` - let pat_arm = { - let body = lower_block(lctx, body); - let body_expr = expr_block(lctx, body, None); - arm(hir_vec![lower_pat(lctx, pat)], body_expr) - }; - - // `[_ if => ,]` - let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e)); - let else_if_arms = { - let mut arms = vec![]; - loop { - let else_opt_continue = else_opt.and_then(|els| { - els.and_then(|els| { - match els.node { - // else if - hir::ExprIf(cond, then, else_opt) => { - let pat_under = pat_wild(lctx, e.span); - arms.push(hir::Arm { - attrs: hir_vec![], - pats: hir_vec![pat_under], - guard: Some(cond), - body: expr_block(lctx, then, None), - }); - else_opt.map(|else_opt| (else_opt, true)) + // Desugar ExprIfLet + // From: `if let = []` + ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { + // to: + // + // match { + // => , + // [_ if => ,] + // _ => [ | ()] + // } + + // ` => ` + let pat_arm = { + let body = self.lower_block(body); + let body_expr = self.expr_block(body, None); + let pat = self.lower_pat(pat); + self.arm(hir_vec![pat], body_expr) + }; + + // `[_ if => ,]` + let mut else_opt = else_opt.as_ref().map(|e| self.lower_expr(e)); + let else_if_arms = { + let mut arms = vec![]; + loop { + let else_opt_continue = else_opt.and_then(|els| { + els.and_then(|els| { + match els.node { + // else if + hir::ExprIf(cond, then, else_opt) => { + let pat_under = self.pat_wild(e.span); + arms.push(hir::Arm { + attrs: hir_vec![], + pats: hir_vec![pat_under], + guard: Some(cond), + body: self.expr_block(then, None), + }); + else_opt.map(|else_opt| (else_opt, true)) + } + _ => Some((P(els), false)), } - _ => Some((P(els), false)), + }) + }); + match else_opt_continue { + Some((e, true)) => { + else_opt = Some(e); + } + Some((e, false)) => { + else_opt = Some(e); + break; + } + None => { + else_opt = None; + break; } - }) - }); - match else_opt_continue { - Some((e, true)) => { - else_opt = Some(e); - } - Some((e, false)) => { - else_opt = Some(e); - break; - } - None => { - else_opt = None; - break; } } - } - arms - }; - - let contains_else_clause = else_opt.is_some(); - - // `_ => [ | ()]` - let else_arm = { - let pat_under = pat_wild(lctx, e.span); - let else_expr = - else_opt.unwrap_or_else( - || expr_tuple(lctx, e.span, hir_vec![], None)); - arm(hir_vec![pat_under], else_expr) - }; - - let mut arms = Vec::with_capacity(else_if_arms.len() + 2); - arms.push(pat_arm); - arms.extend(else_if_arms); - arms.push(else_arm); - - let sub_expr = lower_expr(lctx, sub_expr); - // add attributes to the outer returned expr node - return expr(lctx, - e.span, - hir::ExprMatch(sub_expr, - arms.into(), - hir::MatchSource::IfLetDesugar { - contains_else_clause: contains_else_clause, - }), - e.attrs.clone()); - } - - // Desugar ExprWhileLet - // From: `[opt_ident]: while let = ` - ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => { - // to: - // - // [opt_ident]: loop { - // match { - // => , - // _ => break - // } - // } - - // ` => ` - let pat_arm = { - let body = lower_block(lctx, body); - let body_expr = expr_block(lctx, body, None); - arm(hir_vec![lower_pat(lctx, pat)], body_expr) - }; - - // `_ => break` - let break_arm = { - let pat_under = pat_wild(lctx, e.span); - let break_expr = expr_break(lctx, e.span, None); - arm(hir_vec![pat_under], break_expr) - }; - - // `match { ... }` - let arms = hir_vec![pat_arm, break_arm]; - let sub_expr = lower_expr(lctx, sub_expr); - let match_expr = expr(lctx, - e.span, - hir::ExprMatch(sub_expr, - arms, - hir::MatchSource::WhileLetDesugar), - None); - - // `[opt_ident]: loop { ... }` - let loop_block = block_expr(lctx, match_expr); - let loop_expr = hir::ExprLoop(loop_block, - opt_ident.map(|ident| lower_ident(lctx, ident))); - // add attributes to the outer returned expr node - let attrs = e.attrs.clone(); - return P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs }); - } - - // Desugar ExprForLoop - // From: `[opt_ident]: for in ` - ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => { - // to: - // - // { - // let result = match ::std::iter::IntoIterator::into_iter() { - // mut iter => { - // [opt_ident]: loop { - // match ::std::iter::Iterator::next(&mut iter) { - // ::std::option::Option::Some() => , - // ::std::option::Option::None => break - // } - // } - // } - // }; - // result - // } - - // expand - let head = lower_expr(lctx, head); - - let iter = lctx.str_to_ident("iter"); - - // `::std::option::Option::Some() => ` - let pat_arm = { - let body_block = lower_block(lctx, body); - let body_span = body_block.span; - let body_expr = P(hir::Expr { - id: lctx.next_id(), - node: hir::ExprBlock(body_block), - span: body_span, - attrs: None, - }); - let pat = lower_pat(lctx, pat); - let some_pat = pat_some(lctx, e.span, pat); - - arm(hir_vec![some_pat], body_expr) - }; + arms + }; - // `::std::option::Option::None => break` - let break_arm = { - let break_expr = expr_break(lctx, e.span, None); + let contains_else_clause = else_opt.is_some(); - arm(hir_vec![pat_none(lctx, e.span)], break_expr) - }; + // `_ => [ | ()]` + let else_arm = { + let pat_under = self.pat_wild(e.span); + let else_expr = + else_opt.unwrap_or_else(|| self.expr_tuple(e.span, hir_vec![], None)); + self.arm(hir_vec![pat_under], else_expr) + }; - // `mut iter` - let iter_pat = - pat_ident_binding_mode(lctx, e.span, iter, hir::BindByValue(hir::MutMutable)); + let mut arms = Vec::with_capacity(else_if_arms.len() + 2); + arms.push(pat_arm); + arms.extend(else_if_arms); + arms.push(else_arm); + + let sub_expr = self.lower_expr(sub_expr); + // add attributes to the outer returned expr node + return self.expr(e.span, + hir::ExprMatch(sub_expr, + arms.into(), + hir::MatchSource::IfLetDesugar { + contains_else_clause: contains_else_clause, + }), + e.attrs.clone()); + } - // `match ::std::iter::Iterator::next(&mut iter) { ... }` - let match_expr = { - let next_path = { - let strs = std_path(lctx, &["iter", "Iterator", "next"]); + // Desugar ExprWhileLet + // From: `[opt_ident]: while let = ` + ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => { + // to: + // + // [opt_ident]: loop { + // match { + // => , + // _ => break + // } + // } + + // ` => ` + let pat_arm = { + let body = self.lower_block(body); + let body_expr = self.expr_block(body, None); + let pat = self.lower_pat(pat); + self.arm(hir_vec![pat], body_expr) + }; - path_global(e.span, strs) + // `_ => break` + let break_arm = { + let pat_under = self.pat_wild(e.span); + let break_expr = self.expr_break(e.span, None); + self.arm(hir_vec![pat_under], break_expr) }; - let iter = expr_ident(lctx, e.span, iter, None, iter_pat.id); - let ref_mut_iter = expr_mut_addr_of(lctx, e.span, iter, None); - let next_path = expr_path(lctx, next_path, None); - let next_expr = expr_call(lctx, - e.span, - next_path, - hir_vec![ref_mut_iter], - None); + + // `match { ... }` let arms = hir_vec![pat_arm, break_arm]; + let sub_expr = self.lower_expr(sub_expr); + let match_expr = self.expr(e.span, + hir::ExprMatch(sub_expr, + arms, + hir::MatchSource::WhileLetDesugar), + None); + + // `[opt_ident]: loop { ... }` + let loop_block = self.block_expr(match_expr); + let loop_expr = hir::ExprLoop(loop_block, + opt_ident.map(|ident| self.lower_ident(ident))); + // add attributes to the outer returned expr node + let attrs = e.attrs.clone(); + return P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs }); + } - expr(lctx, - e.span, - hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar), - None) - }; + // Desugar ExprForLoop + // From: `[opt_ident]: for in ` + ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => { + // to: + // + // { + // let result = match ::std::iter::IntoIterator::into_iter() { + // mut iter => { + // [opt_ident]: loop { + // match ::std::iter::Iterator::next(&mut iter) { + // ::std::option::Option::Some() => , + // ::std::option::Option::None => break + // } + // } + // } + // }; + // result + // } + + // expand + let head = self.lower_expr(head); + + let iter = self.str_to_ident("iter"); + + // `::std::option::Option::Some() => ` + let pat_arm = { + let body_block = self.lower_block(body); + let body_span = body_block.span; + let body_expr = P(hir::Expr { + id: self.next_id(), + node: hir::ExprBlock(body_block), + span: body_span, + attrs: None, + }); + let pat = self.lower_pat(pat); + let some_pat = self.pat_some(e.span, pat); - // `[opt_ident]: loop { ... }` - let loop_block = block_expr(lctx, match_expr); - let loop_expr = hir::ExprLoop(loop_block, - opt_ident.map(|ident| lower_ident(lctx, ident))); - let loop_expr = - P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: None }); + self.arm(hir_vec![some_pat], body_expr) + }; - // `mut iter => { ... }` - let iter_arm = arm(hir_vec![iter_pat], loop_expr); + // `::std::option::Option::None => break` + let break_arm = { + let break_expr = self.expr_break(e.span, None); + let pat = self.pat_none(e.span); + self.arm(hir_vec![pat], break_expr) + }; - // `match ::std::iter::IntoIterator::into_iter() { ... }` - let into_iter_expr = { - let into_iter_path = { - let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]); + // `mut iter` + let iter_pat = self.pat_ident_binding_mode(e.span, iter, + hir::BindByValue(hir::MutMutable)); + + // `match ::std::iter::Iterator::next(&mut iter) { ... }` + let match_expr = { + let next_path = { + let strs = self.std_path(&["iter", "Iterator", "next"]); + + self.path_global(e.span, strs) + }; + let iter = self.expr_ident(e.span, iter, None, iter_pat.id); + let ref_mut_iter = self.expr_mut_addr_of(e.span, iter, None); + let next_path = self.expr_path(next_path, None); + let next_expr = self.expr_call(e.span, + next_path, + hir_vec![ref_mut_iter], + None); + let arms = hir_vec![pat_arm, break_arm]; - path_global(e.span, strs) + self.expr(e.span, + hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar), + None) }; - let into_iter = expr_path(lctx, into_iter_path, None); - expr_call(lctx, e.span, into_iter, hir_vec![head], None) - }; + // `[opt_ident]: loop { ... }` + let loop_block = self.block_expr(match_expr); + let loop_expr = hir::ExprLoop(loop_block, + opt_ident.map(|ident| self.lower_ident(ident))); + let loop_expr = + P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: None }); - let match_expr = expr_match(lctx, - e.span, - into_iter_expr, - hir_vec![iter_arm], - hir::MatchSource::ForLoopDesugar, - None); + // `mut iter => { ... }` + let iter_arm = self.arm(hir_vec![iter_pat], loop_expr); - // `{ let _result = ...; _result }` - // underscore prevents an unused_variables lint if the head diverges - let result_ident = lctx.str_to_ident("_result"); - let (let_stmt, let_stmt_binding) = - stmt_let(lctx, e.span, false, result_ident, match_expr, None); + // `match ::std::iter::IntoIterator::into_iter() { ... }` + let into_iter_expr = { + let into_iter_path = { + let strs = self.std_path(&["iter", "IntoIterator", "into_iter"]); - let result = expr_ident(lctx, e.span, result_ident, None, let_stmt_binding); - let block = block_all(lctx, e.span, hir_vec![let_stmt], Some(result)); - // add the attributes to the outer returned expr node - return expr_block(lctx, block, e.attrs.clone()); - } + self.path_global(e.span, strs) + }; - // Desugar ExprKind::Try - // From: `?` - ExprKind::Try(ref sub_expr) => { - // to: - // - // { - // match { - // Ok(val) => val, - // Err(err) => { - // return Err(From::from(err)) - // } - // } - // } - - // expand - let sub_expr = lower_expr(lctx, sub_expr); - - // Ok(val) => val - let ok_arm = { - let val_ident = lctx.str_to_ident("val"); - let val_pat = pat_ident(lctx, e.span, val_ident); - let val_expr = expr_ident(lctx, e.span, val_ident, None, val_pat.id); - let ok_pat = pat_ok(lctx, e.span, val_pat); - - arm(hir_vec![ok_pat], val_expr) - }; - - // Err(err) => return Err(From::from(err)) - let err_arm = { - let err_ident = lctx.str_to_ident("err"); - let err_local = pat_ident(lctx, e.span, err_ident); - let from_expr = { - let path = std_path(lctx, &["convert", "From", "from"]); - let path = path_global(e.span, path); - let from = expr_path(lctx, path, None); - let err_expr = expr_ident(lctx, e.span, err_ident, None, err_local.id); - - expr_call(lctx, e.span, from, hir_vec![err_expr], None) + let into_iter = self.expr_path(into_iter_path, None); + self.expr_call(e.span, into_iter, hir_vec![head], None) }; - let err_expr = { - let path = std_path(lctx, &["result", "Result", "Err"]); - let path = path_global(e.span, path); - let err_ctor = expr_path(lctx, path, None); - expr_call(lctx, e.span, err_ctor, hir_vec![from_expr], None) + + let match_expr = self.expr_match(e.span, + into_iter_expr, + hir_vec![iter_arm], + hir::MatchSource::ForLoopDesugar, + None); + + // `{ let _result = ...; _result }` + // underscore prevents an unused_variables lint if the head diverges + let result_ident = self.str_to_ident("_result"); + let (let_stmt, let_stmt_binding) = + self.stmt_let(e.span, false, result_ident, match_expr, None); + + let result = self.expr_ident(e.span, result_ident, None, let_stmt_binding); + let block = self.block_all(e.span, hir_vec![let_stmt], Some(result)); + // add the attributes to the outer returned expr node + return self.expr_block(block, e.attrs.clone()); + } + + // Desugar ExprKind::Try + // From: `?` + ExprKind::Try(ref sub_expr) => { + // to: + // + // { + // match { + // Ok(val) => val, + // Err(err) => { + // return Err(From::from(err)) + // } + // } + // } + + // expand + let sub_expr = self.lower_expr(sub_expr); + + // Ok(val) => val + let ok_arm = { + let val_ident = self.str_to_ident("val"); + let val_pat = self.pat_ident(e.span, val_ident); + let val_expr = self.expr_ident(e.span, val_ident, None, val_pat.id); + let ok_pat = self.pat_ok(e.span, val_pat); + + self.arm(hir_vec![ok_pat], val_expr) }; - let err_pat = pat_err(lctx, e.span, err_local); - let ret_expr = expr(lctx, e.span, - hir::Expr_::ExprRet(Some(err_expr)), None); - arm(hir_vec![err_pat], ret_expr) - }; + // Err(err) => return Err(From::from(err)) + let err_arm = { + let err_ident = self.str_to_ident("err"); + let err_local = self.pat_ident(e.span, err_ident); + let from_expr = { + let path = self.std_path(&["convert", "From", "from"]); + let path = self.path_global(e.span, path); + let from = self.expr_path(path, None); + let err_expr = self.expr_ident(e.span, err_ident, None, err_local.id); + + self.expr_call(e.span, from, hir_vec![err_expr], None) + }; + let err_expr = { + let path = self.std_path(&["result", "Result", "Err"]); + let path = self.path_global(e.span, path); + let err_ctor = self.expr_path(path, None); + self.expr_call(e.span, err_ctor, hir_vec![from_expr], None) + }; + let err_pat = self.pat_err(e.span, err_local); + let ret_expr = self.expr(e.span, + hir::Expr_::ExprRet(Some(err_expr)), None); + + self.arm(hir_vec![err_pat], ret_expr) + }; - return expr_match(lctx, e.span, sub_expr, hir_vec![err_arm, ok_arm], - hir::MatchSource::TryDesugar, None); - } + return self.expr_match(e.span, sub_expr, hir_vec![err_arm, ok_arm], + hir::MatchSource::TryDesugar, None); + } - ExprKind::Mac(_) => panic!("Shouldn't exist here"), - }, - span: e.span, - attrs: e.attrs.clone(), - }) -} + ExprKind::Mac(_) => panic!("Shouldn't exist here"), + }, + span: e.span, + attrs: e.attrs.clone(), + }) + } -pub fn lower_stmt(lctx: &LoweringContext, s: &Stmt) -> hir::Stmt { - match s.node { - StmtKind::Decl(ref d, id) => { - Spanned { - node: hir::StmtDecl(lower_decl(lctx, d), id), - span: s.span, + fn lower_stmt(&mut self, s: &Stmt) -> hir::Stmt { + match s.node { + StmtKind::Decl(ref d, id) => { + Spanned { + node: hir::StmtDecl(self.lower_decl(d), id), + span: s.span, + } } - } - StmtKind::Expr(ref e, id) => { - Spanned { - node: hir::StmtExpr(lower_expr(lctx, e), id), - span: s.span, + StmtKind::Expr(ref e, id) => { + Spanned { + node: hir::StmtExpr(self.lower_expr(e), id), + span: s.span, + } } - } - StmtKind::Semi(ref e, id) => { - Spanned { - node: hir::StmtSemi(lower_expr(lctx, e), id), - span: s.span, + StmtKind::Semi(ref e, id) => { + Spanned { + node: hir::StmtSemi(self.lower_expr(e), id), + span: s.span, + } } + StmtKind::Mac(..) => panic!("Shouldn't exist here"), } - StmtKind::Mac(..) => panic!("Shouldn't exist here"), } -} -pub fn lower_capture_clause(_lctx: &LoweringContext, c: CaptureBy) -> hir::CaptureClause { - match c { - CaptureBy::Value => hir::CaptureByValue, - CaptureBy::Ref => hir::CaptureByRef, + fn lower_capture_clause(&mut self, c: CaptureBy) -> hir::CaptureClause { + match c { + CaptureBy::Value => hir::CaptureByValue, + CaptureBy::Ref => hir::CaptureByRef, + } } -} -pub fn lower_visibility(lctx: &LoweringContext, v: &Visibility) -> hir::Visibility { - match *v { - Visibility::Public => hir::Public, - Visibility::Crate(_) => hir::Visibility::Crate, - Visibility::Restricted { ref path, id } => - hir::Visibility::Restricted { path: P(lower_path(lctx, path)), id: id }, - Visibility::Inherited => hir::Inherited, + fn lower_visibility(&mut self, v: &Visibility) -> hir::Visibility { + match *v { + Visibility::Public => hir::Public, + Visibility::Crate(_) => hir::Visibility::Crate, + Visibility::Restricted { ref path, id } => + hir::Visibility::Restricted { path: P(self.lower_path(path)), id: id }, + Visibility::Inherited => hir::Inherited, + } } -} -pub fn lower_defaultness(_lctx: &LoweringContext, d: Defaultness) -> hir::Defaultness { - match d { - Defaultness::Default => hir::Defaultness::Default, - Defaultness::Final => hir::Defaultness::Final, + fn lower_defaultness(&mut self, d: Defaultness) -> hir::Defaultness { + match d { + Defaultness::Default => hir::Defaultness::Default, + Defaultness::Final => hir::Defaultness::Final, + } } -} -pub fn lower_block_check_mode(lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode { - match *b { - BlockCheckMode::Default => hir::DefaultBlock, - BlockCheckMode::Unsafe(u) => hir::UnsafeBlock(lower_unsafe_source(lctx, u)), + fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode { + match *b { + BlockCheckMode::Default => hir::DefaultBlock, + BlockCheckMode::Unsafe(u) => hir::UnsafeBlock(self.lower_unsafe_source(u)), + } } -} -pub fn lower_binding_mode(lctx: &LoweringContext, b: &BindingMode) -> hir::BindingMode { - match *b { - BindingMode::ByRef(m) => hir::BindByRef(lower_mutability(lctx, m)), - BindingMode::ByValue(m) => hir::BindByValue(lower_mutability(lctx, m)), + fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingMode { + match *b { + BindingMode::ByRef(m) => hir::BindByRef(self.lower_mutability(m)), + BindingMode::ByValue(m) => hir::BindByValue(self.lower_mutability(m)), + } } -} -pub fn lower_unsafe_source(_lctx: &LoweringContext, u: UnsafeSource) -> hir::UnsafeSource { - match u { - CompilerGenerated => hir::CompilerGenerated, - UserProvided => hir::UserProvided, + fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource { + match u { + CompilerGenerated => hir::CompilerGenerated, + UserProvided => hir::UserProvided, + } } -} -pub fn lower_impl_polarity(_lctx: &LoweringContext, i: ImplPolarity) -> hir::ImplPolarity { - match i { - ImplPolarity::Positive => hir::ImplPolarity::Positive, - ImplPolarity::Negative => hir::ImplPolarity::Negative, + fn lower_impl_polarity(&mut self, i: ImplPolarity) -> hir::ImplPolarity { + match i { + ImplPolarity::Positive => hir::ImplPolarity::Positive, + ImplPolarity::Negative => hir::ImplPolarity::Negative, + } } -} -pub fn lower_trait_bound_modifier(_lctx: &LoweringContext, - f: TraitBoundModifier) - -> hir::TraitBoundModifier { - match f { - TraitBoundModifier::None => hir::TraitBoundModifier::None, - TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, + fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier { + match f { + TraitBoundModifier::None => hir::TraitBoundModifier::None, + TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, + } } -} -// Helper methods for building HIR. + // Helper methods for building HIR. -fn arm(pats: hir::HirVec>, expr: P) -> hir::Arm { - hir::Arm { - attrs: hir_vec![], - pats: pats, - guard: None, - body: expr, + fn arm(&mut self, pats: hir::HirVec>, expr: P) -> hir::Arm { + hir::Arm { + attrs: hir_vec![], + pats: pats, + guard: None, + body: expr, + } } -} -fn field(name: Name, expr: P, span: Span) -> hir::Field { - hir::Field { - name: Spanned { - node: name, + fn field(&mut self, name: Name, expr: P, span: Span) -> hir::Field { + hir::Field { + name: Spanned { + node: name, + span: span, + }, span: span, - }, - span: span, - expr: expr, + expr: expr, + } } -} -fn expr_break(lctx: &LoweringContext, span: Span, - attrs: ThinAttributes) -> P { - expr(lctx, span, hir::ExprBreak(None), attrs) -} + fn expr_break(&mut self, span: Span, attrs: ThinAttributes) -> P { + self.expr(span, hir::ExprBreak(None), attrs) + } -fn expr_call(lctx: &LoweringContext, - span: Span, - e: P, - args: hir::HirVec>, - attrs: ThinAttributes) - -> P { - expr(lctx, span, hir::ExprCall(e, args), attrs) -} + fn expr_call(&mut self, + span: Span, + e: P, + args: hir::HirVec>, + attrs: ThinAttributes) + -> P { + self.expr(span, hir::ExprCall(e, args), attrs) + } -fn expr_ident(lctx: &LoweringContext, span: Span, id: hir::Ident, - attrs: ThinAttributes, binding: NodeId) -> P { - let expr = expr(lctx, span, hir::ExprPath(None, path_ident(span, id)), attrs); + fn expr_ident(&mut self, span: Span, id: hir::Ident, attrs: ThinAttributes, binding: NodeId) + -> P { + let expr_path = hir::ExprPath(None, self.path_ident(span, id)); + let expr = self.expr(span, expr_path, attrs); - let mut resolver = lctx.resolver.borrow_mut(); - let def = resolver.definitions().map(|defs| Def::Local(defs.local_def_id(binding), binding)) - .unwrap_or(Def::Err); - resolver.record_resolution(expr.id, def); + let def = self.resolver.definitions().map(|defs| { + Def::Local(defs.local_def_id(binding), binding) + }).unwrap_or(Def::Err); + self.resolver.record_resolution(expr.id, def); - expr -} + expr + } -fn expr_mut_addr_of(lctx: &LoweringContext, span: Span, e: P, - attrs: ThinAttributes) -> P { - expr(lctx, span, hir::ExprAddrOf(hir::MutMutable, e), attrs) -} + fn expr_mut_addr_of(&mut self, span: Span, e: P, attrs: ThinAttributes) + -> P { + self.expr(span, hir::ExprAddrOf(hir::MutMutable, e), attrs) + } -fn expr_path(lctx: &LoweringContext, path: hir::Path, - attrs: ThinAttributes) -> P { - let def = lctx.resolver.borrow_mut().resolve_generated_global_path(&path, true); - let expr = expr(lctx, path.span, hir::ExprPath(None, path), attrs); - lctx.resolver.borrow_mut().record_resolution(expr.id, def); - expr -} + fn expr_path(&mut self, path: hir::Path, attrs: ThinAttributes) -> P { + let def = self.resolver.resolve_generated_global_path(&path, true); + let expr = self.expr(path.span, hir::ExprPath(None, path), attrs); + self.resolver.record_resolution(expr.id, def); + expr + } -fn expr_match(lctx: &LoweringContext, - span: Span, - arg: P, - arms: hir::HirVec, - source: hir::MatchSource, - attrs: ThinAttributes) - -> P { - expr(lctx, span, hir::ExprMatch(arg, arms, source), attrs) -} + fn expr_match(&mut self, + span: Span, + arg: P, + arms: hir::HirVec, + source: hir::MatchSource, + attrs: ThinAttributes) + -> P { + self.expr(span, hir::ExprMatch(arg, arms, source), attrs) + } -fn expr_block(lctx: &LoweringContext, b: P, - attrs: ThinAttributes) -> P { - expr(lctx, b.span, hir::ExprBlock(b), attrs) -} + fn expr_block(&mut self, b: P, attrs: ThinAttributes) -> P { + self.expr(b.span, hir::ExprBlock(b), attrs) + } -fn expr_tuple(lctx: &LoweringContext, sp: Span, exprs: hir::HirVec>, - attrs: ThinAttributes) -> P { - expr(lctx, sp, hir::ExprTup(exprs), attrs) -} + fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec>, attrs: ThinAttributes) + -> P { + self.expr(sp, hir::ExprTup(exprs), attrs) + } -fn expr_struct(lctx: &LoweringContext, - sp: Span, - path: hir::Path, - fields: hir::HirVec, - e: Option>, - attrs: ThinAttributes) -> P { - let def = lctx.resolver.borrow_mut().resolve_generated_global_path(&path, false); - let expr = expr(lctx, sp, hir::ExprStruct(path, fields, e), attrs); - lctx.resolver.borrow_mut().record_resolution(expr.id, def); - expr + fn expr_struct(&mut self, + sp: Span, + path: hir::Path, + fields: hir::HirVec, + e: Option>, + attrs: ThinAttributes) -> P { + let def = self.resolver.resolve_generated_global_path(&path, false); + let expr = self.expr(sp, hir::ExprStruct(path, fields, e), attrs); + self.resolver.record_resolution(expr.id, def); + expr + } -} + fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinAttributes) -> P { + P(hir::Expr { + id: self.next_id(), + node: node, + span: span, + attrs: attrs, + }) + } -fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_, - attrs: ThinAttributes) -> P { - P(hir::Expr { - id: lctx.next_id(), - node: node, - span: span, - attrs: attrs, - }) -} + fn stmt_let(&mut self, + sp: Span, + mutbl: bool, + ident: hir::Ident, + ex: P, + attrs: ThinAttributes) + -> (hir::Stmt, NodeId) { + let pat = if mutbl { + self.pat_ident_binding_mode(sp, ident, hir::BindByValue(hir::MutMutable)) + } else { + self.pat_ident(sp, ident) + }; + let pat_id = pat.id; + let local = P(hir::Local { + pat: pat, + ty: None, + init: Some(ex), + id: self.next_id(), + span: sp, + attrs: attrs, + }); + let decl = respan(sp, hir::DeclLocal(local)); + (respan(sp, hir::StmtDecl(P(decl), self.next_id())), pat_id) + } -fn stmt_let(lctx: &LoweringContext, - sp: Span, - mutbl: bool, - ident: hir::Ident, - ex: P, - attrs: ThinAttributes) - -> (hir::Stmt, NodeId) { - let pat = if mutbl { - pat_ident_binding_mode(lctx, sp, ident, hir::BindByValue(hir::MutMutable)) - } else { - pat_ident(lctx, sp, ident) - }; - let pat_id = pat.id; - let local = P(hir::Local { - pat: pat, - ty: None, - init: Some(ex), - id: lctx.next_id(), - span: sp, - attrs: attrs, - }); - let decl = respan(sp, hir::DeclLocal(local)); - (respan(sp, hir::StmtDecl(P(decl), lctx.next_id())), pat_id) -} + fn block_expr(&mut self, expr: P) -> P { + self.block_all(expr.span, hir::HirVec::new(), Some(expr)) + } -fn block_expr(lctx: &LoweringContext, expr: P) -> P { - block_all(lctx, expr.span, hir::HirVec::new(), Some(expr)) -} + fn block_all(&mut self, span: Span, stmts: hir::HirVec, expr: Option>) + -> P { + P(hir::Block { + stmts: stmts, + expr: expr, + id: self.next_id(), + rules: hir::DefaultBlock, + span: span, + }) + } -fn block_all(lctx: &LoweringContext, - span: Span, - stmts: hir::HirVec, - expr: Option>) - -> P { - P(hir::Block { - stmts: stmts, - expr: expr, - id: lctx.next_id(), - rules: hir::DefaultBlock, - span: span, - }) -} + fn pat_ok(&mut self, span: Span, pat: P) -> P { + let ok = self.std_path(&["result", "Result", "Ok"]); + let path = self.path_global(span, ok); + self.pat_enum(span, path, hir_vec![pat]) + } -fn pat_ok(lctx: &LoweringContext, span: Span, pat: P) -> P { - let ok = std_path(lctx, &["result", "Result", "Ok"]); - let path = path_global(span, ok); - pat_enum(lctx, span, path, hir_vec![pat]) -} + fn pat_err(&mut self, span: Span, pat: P) -> P { + let err = self.std_path(&["result", "Result", "Err"]); + let path = self.path_global(span, err); + self.pat_enum(span, path, hir_vec![pat]) + } -fn pat_err(lctx: &LoweringContext, span: Span, pat: P) -> P { - let err = std_path(lctx, &["result", "Result", "Err"]); - let path = path_global(span, err); - pat_enum(lctx, span, path, hir_vec![pat]) -} + fn pat_some(&mut self, span: Span, pat: P) -> P { + let some = self.std_path(&["option", "Option", "Some"]); + let path = self.path_global(span, some); + self.pat_enum(span, path, hir_vec![pat]) + } -fn pat_some(lctx: &LoweringContext, span: Span, pat: P) -> P { - let some = std_path(lctx, &["option", "Option", "Some"]); - let path = path_global(span, some); - pat_enum(lctx, span, path, hir_vec![pat]) -} + fn pat_none(&mut self, span: Span) -> P { + let none = self.std_path(&["option", "Option", "None"]); + let path = self.path_global(span, none); + self.pat_enum(span, path, hir_vec![]) + } -fn pat_none(lctx: &LoweringContext, span: Span) -> P { - let none = std_path(lctx, &["option", "Option", "None"]); - let path = path_global(span, none); - pat_enum(lctx, span, path, hir_vec![]) -} + fn pat_enum(&mut self, span: Span, path: hir::Path, subpats: hir::HirVec>) + -> P { + let def = self.resolver.resolve_generated_global_path(&path, true); + let pt = if subpats.is_empty() { + hir::PatKind::Path(path) + } else { + hir::PatKind::TupleStruct(path, Some(subpats)) + }; + let pat = self.pat(span, pt); + self.resolver.record_resolution(pat.id, def); + pat + } -fn pat_enum(lctx: &LoweringContext, - span: Span, - path: hir::Path, - subpats: hir::HirVec>) - -> P { - let def = lctx.resolver.borrow_mut().resolve_generated_global_path(&path, true); - let pt = if subpats.is_empty() { - hir::PatKind::Path(path) - } else { - hir::PatKind::TupleStruct(path, Some(subpats)) - }; - let pat = pat(lctx, span, pt); - lctx.resolver.borrow_mut().record_resolution(pat.id, def); - pat -} + fn pat_ident(&mut self, span: Span, ident: hir::Ident) -> P { + self.pat_ident_binding_mode(span, ident, hir::BindByValue(hir::MutImmutable)) + } -fn pat_ident(lctx: &LoweringContext, span: Span, ident: hir::Ident) -> P { - pat_ident_binding_mode(lctx, span, ident, hir::BindByValue(hir::MutImmutable)) -} + fn pat_ident_binding_mode(&mut self, span: Span, ident: hir::Ident, bm: hir::BindingMode) + -> P { + let pat_ident = hir::PatKind::Ident(bm, + Spanned { + span: span, + node: ident, + }, + None); -fn pat_ident_binding_mode(lctx: &LoweringContext, - span: Span, - ident: hir::Ident, - bm: hir::BindingMode) - -> P { - let pat_ident = hir::PatKind::Ident(bm, - Spanned { - span: span, - node: ident, - }, - None); - - let pat = pat(lctx, span, pat_ident); - - let mut resolver = lctx.resolver.borrow_mut(); - let def = resolver.definitions().map(|defs| { - let def_path_data = DefPathData::Binding(ident.name); - let def_index = defs.create_def_with_parent(lctx.parent_def.get(), pat.id, def_path_data); - Def::Local(DefId::local(def_index), pat.id) - }).unwrap_or(Def::Err); - resolver.record_resolution(pat.id, def); - - pat -} + let pat = self.pat(span, pat_ident); -fn pat_wild(lctx: &LoweringContext, span: Span) -> P { - pat(lctx, span, hir::PatKind::Wild) -} + let parent_def = self.parent_def; + let def = self.resolver.definitions().map(|defs| { + let def_path_data = DefPathData::Binding(ident.name); + let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data); + Def::Local(DefId::local(def_index), pat.id) + }).unwrap_or(Def::Err); + self.resolver.record_resolution(pat.id, def); -fn pat(lctx: &LoweringContext, span: Span, pat: hir::PatKind) -> P { - P(hir::Pat { - id: lctx.next_id(), - node: pat, - span: span, - }) -} + pat + } -fn path_ident(span: Span, id: hir::Ident) -> hir::Path { - path(span, vec![id]) -} + fn pat_wild(&mut self, span: Span) -> P { + self.pat(span, hir::PatKind::Wild) + } -fn path(span: Span, strs: Vec) -> hir::Path { - path_all(span, false, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) -} + fn pat(&mut self, span: Span, pat: hir::PatKind) -> P { + P(hir::Pat { + id: self.next_id(), + node: pat, + span: span, + }) + } -fn path_global(span: Span, strs: Vec) -> hir::Path { - path_all(span, true, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) -} + fn path_ident(&mut self, span: Span, id: hir::Ident) -> hir::Path { + self.path(span, vec![id]) + } -fn path_all(sp: Span, - global: bool, - mut idents: Vec, - lifetimes: hir::HirVec, - types: hir::HirVec>, - bindings: hir::HirVec) - -> hir::Path { - let last_identifier = idents.pop().unwrap(); - let mut segments: Vec = idents.into_iter() - .map(|ident| { - hir::PathSegment { - identifier: ident, - parameters: hir::PathParameters::none(), - } - }) - .collect(); - segments.push(hir::PathSegment { - identifier: last_identifier, - parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { - lifetimes: lifetimes, - types: types, - bindings: bindings, - }), - }); - hir::Path { - span: sp, - global: global, - segments: segments.into(), + fn path(&mut self, span: Span, strs: Vec) -> hir::Path { + self.path_all(span, false, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) } -} -fn std_path(lctx: &LoweringContext, components: &[&str]) -> Vec { - let mut v = Vec::new(); - if let Some(s) = lctx.crate_root { - v.push(hir::Ident::from_name(token::intern(s))); + fn path_global(&mut self, span: Span, strs: Vec) -> hir::Path { + self.path_all(span, true, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new()) } - v.extend(components.iter().map(|s| hir::Ident::from_name(token::intern(s)))); - return v; -} -// Given suffix ["b","c","d"], returns path `::std::b::c::d` when -// `fld.cx.use_std`, and `::core::b::c::d` otherwise. -fn core_path(lctx: &LoweringContext, span: Span, components: &[&str]) -> hir::Path { - let idents = std_path(lctx, components); - path_global(span, idents) -} + fn path_all(&mut self, + sp: Span, + global: bool, + mut idents: Vec, + lifetimes: hir::HirVec, + types: hir::HirVec>, + bindings: hir::HirVec) + -> hir::Path { + let last_identifier = idents.pop().unwrap(); + let mut segments: Vec = idents.into_iter().map(|ident| { + hir::PathSegment { + identifier: ident, + parameters: hir::PathParameters::none(), + } + }).collect(); + + segments.push(hir::PathSegment { + identifier: last_identifier, + parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData { + lifetimes: lifetimes, + types: types, + bindings: bindings, + }), + }); + hir::Path { + span: sp, + global: global, + segments: segments.into(), + } + } -fn signal_block_expr(lctx: &LoweringContext, - stmts: hir::HirVec, - expr: P, - span: Span, - rule: hir::BlockCheckMode, - attrs: ThinAttributes) - -> P { - let id = lctx.next_id(); - expr_block(lctx, - P(hir::Block { - rules: rule, - span: span, - id: id, - stmts: stmts, - expr: Some(expr), - }), - attrs) + fn std_path(&mut self, components: &[&str]) -> Vec { + let mut v = Vec::new(); + if let Some(s) = self.crate_root { + v.push(hir::Ident::from_name(token::intern(s))); + } + v.extend(components.iter().map(|s| hir::Ident::from_name(token::intern(s)))); + return v; + } + + // Given suffix ["b","c","d"], returns path `::std::b::c::d` when + // `fld.cx.use_std`, and `::core::b::c::d` otherwise. + fn core_path(&mut self, span: Span, components: &[&str]) -> hir::Path { + let idents = self.std_path(components); + self.path_global(span, idents) + } + + fn signal_block_expr(&mut self, + stmts: hir::HirVec, + expr: P, + span: Span, + rule: hir::BlockCheckMode, + attrs: ThinAttributes) + -> P { + let id = self.next_id(); + let block = P(hir::Block { + rules: rule, + span: span, + id: id, + stmts: stmts, + expr: Some(expr), + }); + self.expr_block(block, attrs) + } } diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 92f8c9249c842..f0eb580cfd57e 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -196,7 +196,7 @@ pub struct Map<'ast> { /// plain old integers. map: RefCell>>, - definitions: &'ast RefCell, + definitions: RefCell, } impl<'ast> Map<'ast> { @@ -790,7 +790,7 @@ pub fn collect_definitions<'ast>(krate: &'ast ast::Crate) -> Definitions { } pub fn map_crate<'ast>(forest: &'ast mut Forest, - definitions: &'ast RefCell) + definitions: Definitions) -> Map<'ast> { let mut collector = NodeCollector::root(&forest.krate); intravisit::walk_crate(&mut collector, &forest.krate); @@ -816,7 +816,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest, forest: forest, dep_graph: forest.dep_graph.clone(), map: RefCell::new(map), - definitions: definitions, + definitions: RefCell::new(definitions), } } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index c0af457ed236c..17b5778994789 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -33,9 +33,8 @@ use mir::mir_map::MirMap; use session::Session; use session::config::PanicStrategy; use session::search_paths::PathKind; -use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; +use util::nodemap::{FnvHashMap, NodeSet, DefIdMap}; use std::any::Any; -use std::cell::RefCell; use std::rc::Rc; use std::path::PathBuf; use syntax::ast; @@ -174,7 +173,6 @@ pub trait CrateStore<'tcx> : Any { fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx>; fn item_attrs(&self, def_id: DefId) -> Vec; - fn item_symbol(&self, def: DefId) -> String; fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>; fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>; fn method_arg_names(&self, did: DefId) -> Vec; @@ -210,6 +208,7 @@ pub trait CrateStore<'tcx> : Any { fn is_impl(&self, did: DefId) -> bool; fn is_default_impl(&self, impl_did: DefId) -> bool; fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool; + fn is_foreign_item(&self, did: DefId) -> bool; fn is_static_method(&self, did: DefId) -> bool; fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool; fn is_typedef(&self, did: DefId) -> bool; @@ -275,7 +274,6 @@ pub trait CrateStore<'tcx> : Any { fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, - item_symbols: &RefCell>, link_meta: &LinkMeta, reachable: &NodeSet, mir_map: &MirMap<'tcx>, @@ -353,7 +351,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } - fn item_symbol(&self, def: DefId) -> String { bug!("item_symbol") } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx> { bug!("trait_def") } fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> @@ -394,6 +391,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") } fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool { bug!("is_extern_item") } + fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") } fn is_static_method(&self, did: DefId) -> bool { bug!("is_static_method") } fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false } fn is_typedef(&self, did: DefId) -> bool { bug!("is_typedef") } @@ -476,7 +474,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { None } fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, - item_symbols: &RefCell>, link_meta: &LinkMeta, reachable: &NodeSet, mir_map: &MirMap<'tcx>, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 7d1d5dba39839..08e422e47877b 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1103,7 +1103,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let no_analysis = debugging_opts.no_analysis; let mut output_types = HashMap::new(); - if !debugging_opts.parse_only && !no_trans { + if !debugging_opts.parse_only { for list in matches.opt_strs("emit") { for output_type in list.split(',') { let mut parts = output_type.splitn(2, '='); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 1bea01c4849e7..2e4cbfd86279b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use hir::def_id::DefIndex; +use hir::svh::Svh; use lint; use middle::cstore::CrateStore; use middle::dependency_format; @@ -310,6 +312,14 @@ impl Session { pub fn nonzeroing_move_hints(&self) -> bool { self.opts.debugging_opts.enable_nonzeroing_move_hints } + + /// Returns the symbol name for the registrar function, + /// given the crate Svh and the function DefIndex. + pub fn generate_plugin_registrar_symbol(&self, svh: &Svh, index: DefIndex) + -> String { + format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize()) + } + pub fn sysroot<'a>(&'a self) -> &'a Path { match self.opts.maybe_sysroot { Some (ref sysroot) => sysroot, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index f606d73a5493f..65df056fd424b 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -239,7 +239,7 @@ pub enum Vtable<'tcx, N> { VtableParam(Vec), /// Virtual calls through an object - VtableObject(VtableObjectData<'tcx>), + VtableObject(VtableObjectData<'tcx, N>), /// Successful resolution for a builtin trait. VtableBuiltin(VtableBuiltinData), @@ -250,7 +250,7 @@ pub enum Vtable<'tcx, N> { VtableClosure(VtableClosureData<'tcx, N>), /// Same as above, but for a fn pointer type with the given signature. - VtableFnPointer(ty::Ty<'tcx>), + VtableFnPointer(VtableFnPointerData<'tcx, N>), } /// Identifies a particular impl in the source, along with a set of @@ -293,14 +293,22 @@ pub struct VtableBuiltinData { /// A vtable for some object-safe trait `Foo` automatically derived /// for the object type `Foo`. #[derive(PartialEq,Eq,Clone)] -pub struct VtableObjectData<'tcx> { +pub struct VtableObjectData<'tcx, N> { /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`. pub upcast_trait_ref: ty::PolyTraitRef<'tcx>, /// The vtable is formed by concatenating together the method lists of /// the base object trait and all supertraits; this is the start of /// `upcast_trait_ref`'s methods in that vtable. - pub vtable_base: usize + pub vtable_base: usize, + + pub nested: Vec, +} + +#[derive(Clone, PartialEq, Eq)] +pub struct VtableFnPointerData<'tcx, N> { + pub fn_ty: ty::Ty<'tcx>, + pub nested: Vec } /// Creates predicate obligations from the generic bounds. @@ -569,7 +577,20 @@ impl<'tcx, N> Vtable<'tcx, N> { VtableBuiltin(i) => i.nested, VtableDefaultImpl(d) => d.nested, VtableClosure(c) => c.nested, - VtableObject(_) | VtableFnPointer(..) => vec![] + VtableObject(d) => d.nested, + VtableFnPointer(d) => d.nested, + } + } + + fn nested_obligations_mut(&mut self) -> &mut Vec { + match self { + &mut VtableImpl(ref mut i) => &mut i.nested, + &mut VtableParam(ref mut n) => n, + &mut VtableBuiltin(ref mut i) => &mut i.nested, + &mut VtableDefaultImpl(ref mut d) => &mut d.nested, + &mut VtableClosure(ref mut c) => &mut c.nested, + &mut VtableObject(ref mut d) => &mut d.nested, + &mut VtableFnPointer(ref mut d) => &mut d.nested, } } @@ -578,18 +599,25 @@ impl<'tcx, N> Vtable<'tcx, N> { VtableImpl(i) => VtableImpl(VtableImplData { impl_def_id: i.impl_def_id, substs: i.substs, - nested: i.nested.into_iter().map(f).collect() + nested: i.nested.into_iter().map(f).collect(), }), VtableParam(n) => VtableParam(n.into_iter().map(f).collect()), VtableBuiltin(i) => VtableBuiltin(VtableBuiltinData { - nested: i.nested.into_iter().map(f).collect() + nested: i.nested.into_iter().map(f).collect(), + }), + VtableObject(o) => VtableObject(VtableObjectData { + upcast_trait_ref: o.upcast_trait_ref, + vtable_base: o.vtable_base, + nested: o.nested.into_iter().map(f).collect(), }), - VtableObject(o) => VtableObject(o), VtableDefaultImpl(d) => VtableDefaultImpl(VtableDefaultImplData { trait_def_id: d.trait_def_id, - nested: d.nested.into_iter().map(f).collect() + nested: d.nested.into_iter().map(f).collect(), + }), + VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData { + fn_ty: p.fn_ty, + nested: p.nested.into_iter().map(f).collect(), }), - VtableFnPointer(f) => VtableFnPointer(f), VtableClosure(c) => VtableClosure(VtableClosureData { closure_def_id: c.closure_def_id, substs: c.substs, diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 4c338219ffbf7..9abb179f28896 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -19,6 +19,7 @@ use super::PredicateObligation; use super::SelectionContext; use super::SelectionError; use super::VtableClosureData; +use super::VtableFnPointerData; use super::VtableImplData; use super::util; @@ -158,7 +159,7 @@ enum ProjectionTyCandidate<'tcx> { Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>), // fn pointer return type - FnPointer(Ty<'tcx>), + FnPointer(VtableFnPointerData<'tcx, PredicateObligation<'tcx>>), } struct ProjectionTyCandidateSet<'tcx> { @@ -218,10 +219,7 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( obligation.cause.clone(), obligation.recursion_depth) { Some(n) => n, - None => { - consider_unification_despite_ambiguity(selcx, obligation); - return Ok(None); - } + None => return Ok(None), }; debug!("project_and_unify_type: normalized_ty={:?} obligations={:?}", @@ -240,59 +238,6 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( } } -fn consider_unification_despite_ambiguity<'cx, 'gcx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, - obligation: &ProjectionObligation<'tcx>) -{ - debug!("consider_unification_despite_ambiguity(obligation={:?})", - obligation); - - let def_id = obligation.predicate.projection_ty.trait_ref.def_id; - match selcx.tcx().lang_items.fn_trait_kind(def_id) { - Some(_) => { } - None => { return; } - } - - let infcx = selcx.infcx(); - let self_ty = obligation.predicate.projection_ty.trait_ref.self_ty(); - let self_ty = infcx.shallow_resolve(self_ty); - debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}", - self_ty.sty); - match self_ty.sty { - ty::TyClosure(closure_def_id, substs) => { - let closure_typer = selcx.closure_typer(); - let closure_type = closure_typer.closure_type(closure_def_id, substs); - let ty::Binder((_, ret_type)) = - infcx.tcx.closure_trait_ref_and_return_type(def_id, - self_ty, - &closure_type.sig, - util::TupleArgumentsFlag::No); - // We don't have to normalize the return type here - this is only - // reached for TyClosure: Fn inputs where the closure kind is - // still unknown, which should only occur in typeck where the - // closure type is already normalized. - let (ret_type, _) = - infcx.replace_late_bound_regions_with_fresh_var( - obligation.cause.span, - infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name), - &ty::Binder(ret_type)); - - debug!("consider_unification_despite_ambiguity: ret_type={:?}", - ret_type); - let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span); - let obligation_ty = obligation.predicate.ty; - match infcx.eq_types(true, origin, obligation_ty, ret_type) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); - } - Err(_) => { /* ignore errors */ } - } - } - _ => { } - } -} - /// Normalizes any associated type projections in `value`, replacing /// them with a fully resolved type where possible. The return value /// combines the normalized result and any additional obligations that @@ -929,9 +874,9 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( candidate_set.vec.push( ProjectionTyCandidate::Closure(data)); } - super::VtableFnPointer(fn_type) => { + super::VtableFnPointer(data) => { candidate_set.vec.push( - ProjectionTyCandidate::FnPointer(fn_type)); + ProjectionTyCandidate::FnPointer(data)); } super::VtableParam(..) => { // This case tell us nothing about the value of an @@ -997,8 +942,8 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>( confirm_closure_candidate(selcx, obligation, closure_vtable) } - ProjectionTyCandidate::FnPointer(fn_type) => { - confirm_fn_pointer_candidate(selcx, obligation, fn_type) + ProjectionTyCandidate::FnPointer(fn_pointer_vtable) => { + confirm_fn_pointer_candidate(selcx, obligation, fn_pointer_vtable) } } } @@ -1006,10 +951,13 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>( fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - fn_type: Ty<'tcx>) + fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>) -> (Ty<'tcx>, Vec>) { - let fn_type = selcx.infcx().shallow_resolve(fn_type); + // FIXME(#32730) propagate obligations (fn pointer vtable nested obligations ONLY come from + // unification in inference) + assert!(fn_pointer_vtable.nested.is_empty()); + let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); let sig = fn_type.fn_sig(); confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 7d9a256a6e080..5307749b87b6a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -30,7 +30,7 @@ use super::SelectionResult; use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, VtableFnPointer, VtableObject, VtableDefaultImpl}; use super::{VtableImplData, VtableObjectData, VtableBuiltinData, - VtableClosureData, VtableDefaultImplData}; + VtableClosureData, VtableDefaultImplData, VtableFnPointerData}; use super::util; use hir::def_id::DefId; @@ -42,13 +42,24 @@ use traits; use ty::fast_reject; use ty::relate::TypeRelation; +use rustc_data_structures::snapshot_vec::{SnapshotVecDelegate, SnapshotVec}; use std::cell::RefCell; use std::fmt; +use std::marker::PhantomData; use std::rc::Rc; use syntax::abi::Abi; use hir; use util::nodemap::FnvHashMap; +struct InferredObligationsSnapshotVecDelegate<'tcx> { + phantom: PhantomData<&'tcx i32>, +} +impl<'tcx> SnapshotVecDelegate for InferredObligationsSnapshotVecDelegate<'tcx> { + type Value = PredicateObligation<'tcx>; + type Undo = (); + fn reverse(_: &mut Vec, _: Self::Undo) {} +} + pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, @@ -74,6 +85,8 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { /// there is no type that the user could *actually name* that /// would satisfy it. This avoids crippling inference, basically. intercrate: bool, + + inferred_obligations: SnapshotVec>, } // A stack that walks back up the stack frame. @@ -300,6 +313,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { infcx: infcx, freshener: infcx.freshener(), intercrate: false, + inferred_obligations: SnapshotVec::new(), } } @@ -308,6 +322,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { infcx: infcx, freshener: infcx.freshener(), intercrate: true, + inferred_obligations: SnapshotVec::new(), } } @@ -331,6 +346,46 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.projection_mode() } + /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection + /// context's self. + fn in_snapshot(&mut self, f: F) -> R + where F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> R + { + // The irrefutable nature of the operation means we don't need to snapshot the + // inferred_obligations vector. + self.infcx.in_snapshot(|snapshot| f(self, snapshot)) + } + + /// Wraps a probe s.t. obligations collected during it are ignored and old obligations are + /// retained. + fn probe(&mut self, f: F) -> R + where F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> R + { + let inferred_obligations_snapshot = self.inferred_obligations.start_snapshot(); + let result = self.infcx.probe(|snapshot| f(self, snapshot)); + self.inferred_obligations.rollback_to(inferred_obligations_snapshot); + result + } + + /// Wraps a commit_if_ok s.t. obligations collected during it are not returned in selection if + /// the transaction fails and s.t. old obligations are retained. + fn commit_if_ok(&mut self, f: F) -> Result where + F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> Result + { + let inferred_obligations_snapshot = self.inferred_obligations.start_snapshot(); + match self.infcx.commit_if_ok(|snapshot| f(self, snapshot)) { + Ok(ok) => { + self.inferred_obligations.commit(inferred_obligations_snapshot); + Ok(ok) + }, + Err(err) => { + self.inferred_obligations.rollback_to(inferred_obligations_snapshot); + Err(err) + } + } + } + + /////////////////////////////////////////////////////////////////////////// // Selection // @@ -359,7 +414,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let stack = self.push_stack(TraitObligationStackList::empty(), obligation); match self.candidate_from_obligation(&stack)? { None => Ok(None), - Some(candidate) => Ok(Some(self.confirm_candidate(obligation, candidate)?)), + Some(candidate) => { + let mut candidate = self.confirm_candidate(obligation, candidate)?; + // FIXME(#32730) remove this assertion once inferred obligations are propagated + // from inference + assert!(self.inferred_obligations.len() == 0); + let inferred_obligations = (*self.inferred_obligations).into_iter().cloned(); + candidate.nested_obligations_mut().extend(inferred_obligations); + Ok(Some(candidate)) + }, } } @@ -381,8 +444,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("evaluate_obligation({:?})", obligation); - self.infcx.probe(|_| { - self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + self.probe(|this, _| { + this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) .may_apply() }) } @@ -397,8 +460,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("evaluate_obligation_conservatively({:?})", obligation); - self.infcx.probe(|_| { - self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + self.probe(|this, _| { + this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) == EvaluatedToOk }) } @@ -460,8 +523,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // does this code ever run? match self.infcx.equality_predicate(obligation.cause.span, p) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.inferred_obligations.extend(obligations); EvaluatedToOk }, Err(_) => EvaluatedToErr @@ -643,11 +705,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("evaluate_candidate: depth={} candidate={:?}", stack.obligation.recursion_depth, candidate); - let result = self.infcx.probe(|_| { + let result = self.probe(|this, _| { let candidate = (*candidate).clone(); - match self.confirm_candidate(stack.obligation, candidate) { + match this.confirm_candidate(stack.obligation, candidate) { Ok(selection) => { - self.evaluate_predicates_recursively( + this.evaluate_predicates_recursively( stack.list(), selection.nested_obligations().iter()) } @@ -1107,8 +1169,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("assemble_candidates_for_projected_tys: trait_def_id={:?}", trait_def_id); - let result = self.infcx.probe(|snapshot| { - self.match_projection_obligation_against_bounds_from_trait(obligation, + let result = self.probe(|this, snapshot| { + this.match_projection_obligation_against_bounds_from_trait(obligation, snapshot) }); @@ -1156,12 +1218,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { util::elaborate_predicates(self.tcx(), bounds.predicates.into_vec()) .filter_to_traits() .find( - |bound| self.infcx.probe( - |_| self.match_projection(obligation, - bound.clone(), - skol_trait_predicate.trait_ref.clone(), - &skol_map, - snapshot))); + |bound| self.probe( + |this, _| this.match_projection(obligation, + bound.clone(), + skol_trait_predicate.trait_ref.clone(), + &skol_map, + snapshot))); debug!("match_projection_obligation_against_bounds_from_trait: \ matching_bound={:?}", @@ -1196,8 +1258,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { trait_bound.clone(), ty::Binder(skol_trait_ref.clone())) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.inferred_obligations.extend(obligations); } Err(_) => { return false; } } @@ -1239,10 +1300,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { where_clause_trait_ref: ty::PolyTraitRef<'tcx>) -> EvaluationResult { - self.infcx().probe(move |_| { - match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { + self.probe(move |this, _| { + match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - self.evaluate_predicates_recursively(stack.list(), obligations.iter()) + this.evaluate_predicates_recursively(stack.list(), obligations.iter()) } Err(()) => EvaluatedToErr } @@ -1361,8 +1422,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.tcx(), obligation.predicate.0.trait_ref.self_ty(), |impl_def_id| { - self.infcx.probe(|snapshot| { - if let Ok(_) = self.match_impl(impl_def_id, obligation, snapshot) { + self.probe(|this, snapshot| { + if let Ok(_) = this.match_impl(impl_def_id, obligation, snapshot) { candidates.vec.push(ImplCandidate(impl_def_id)); } }); @@ -1448,12 +1509,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return; } - self.infcx.in_snapshot(|snapshot| { + self.probe(|this, snapshot| { let (self_ty, _) = - self.infcx().skolemize_late_bound_regions(&obligation.self_ty(), snapshot); + this.infcx().skolemize_late_bound_regions(&obligation.self_ty(), snapshot); let poly_trait_ref = match self_ty.sty { ty::TyTrait(ref data) => { - match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { + match this.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) { Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => { if data.bounds.builtin_bounds.contains(&bound) { debug!("assemble_candidates_from_object_ty: matched builtin bound, \ @@ -1465,7 +1526,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { _ => {} } - data.principal_trait_ref_with_self_ty(self.tcx(), self_ty) + data.principal_trait_ref_with_self_ty(this.tcx(), self_ty) } ty::TyInfer(ty::TyVar(_)) => { debug!("assemble_candidates_from_object_ty: ambiguous"); @@ -1486,11 +1547,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // For example, we may be trying to upcast `Foo` to `Bar`, // but `Foo` is declared as `trait Foo : Bar`. let upcast_trait_refs = - util::supertraits(self.tcx(), poly_trait_ref) + util::supertraits(this.tcx(), poly_trait_ref) .filter(|upcast_trait_ref| { - self.infcx.probe(|_| { + this.probe(|this, _| { let upcast_trait_ref = upcast_trait_ref.clone(); - self.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok() + this.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok() }) }) .count(); @@ -1894,23 +1955,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { types.skip_binder().into_iter().flat_map(|ty| { // binder moved -\ let ty: ty::Binder> = ty::Binder(ty); // <----------/ - self.infcx.in_snapshot(|snapshot| { + self.in_snapshot(|this, snapshot| { let (skol_ty, skol_map) = - self.infcx().skolemize_late_bound_regions(&ty, snapshot); + this.infcx().skolemize_late_bound_regions(&ty, snapshot); let Normalized { value: normalized_ty, mut obligations } = - project::normalize_with_depth(self, + project::normalize_with_depth(this, cause.clone(), recursion_depth, &skol_ty); let skol_obligation = - self.tcx().predicate_for_trait_def( + this.tcx().predicate_for_trait_def( cause.clone(), trait_def_id, recursion_depth, normalized_ty, vec![]); obligations.push(skol_obligation); - self.infcx().plug_leaks(skol_map, snapshot, &obligations) + this.infcx().plug_leaks(skol_map, snapshot, &obligations) }) }).collect() } @@ -1977,9 +2038,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } FnPointerCandidate => { - let fn_type = + let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(VtableFnPointer(fn_type)) + Ok(VtableFnPointer(data)) } ProjectionCandidate => { @@ -1997,9 +2058,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - self.infcx.in_snapshot(|snapshot| { + self.in_snapshot(|this, snapshot| { let result = - self.match_projection_obligation_against_bounds_from_trait(obligation, + this.match_projection_obligation_against_bounds_from_trait(obligation, snapshot); assert!(result); }) @@ -2140,12 +2201,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { trait_def_id, nested); - let trait_obligations = self.infcx.in_snapshot(|snapshot| { + let trait_obligations = self.in_snapshot(|this, snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let (trait_ref, skol_map) = - self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); - let cause = self.derived_cause(obligation, ImplDerivedObligation); - self.impl_or_trait_obligations(cause, + this.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); + let cause = this.derived_cause(obligation, ImplDerivedObligation); + this.impl_or_trait_obligations(cause, obligation.recursion_depth + 1, trait_def_id, &trait_ref.substs, @@ -2174,13 +2235,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.infcx.in_snapshot(|snapshot| { + self.in_snapshot(|this, snapshot| { let (substs, skol_map) = - self.rematch_impl(impl_def_id, obligation, + this.rematch_impl(impl_def_id, obligation, snapshot); debug!("confirm_impl_candidate substs={:?}", substs); - let cause = self.derived_cause(obligation, ImplDerivedObligation); - self.vtable_impl(impl_def_id, substs, cause, + let cause = this.derived_cause(obligation, ImplDerivedObligation); + this.vtable_impl(impl_def_id, substs, cause, obligation.recursion_depth + 1, skol_map, snapshot) }) @@ -2227,7 +2288,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn confirm_object_candidate(&mut self, obligation: &TraitObligation<'tcx>) - -> VtableObjectData<'tcx> + -> VtableObjectData<'tcx, PredicateObligation<'tcx>> { debug!("confirm_object_candidate({:?})", obligation); @@ -2251,6 +2312,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let vtable_base; { + let tcx = self.tcx(); + // We want to find the first supertrait in the list of // supertraits that we can unify with, and do that // unification. We know that there is exactly one in the list @@ -2258,11 +2321,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // reported an ambiguity. (When we do find a match, also // record it for later.) let nonmatching = - util::supertraits(self.tcx(), poly_trait_ref) + util::supertraits(tcx, poly_trait_ref) .take_while(|&t| { match - self.infcx.commit_if_ok( - |_| self.match_poly_trait_ref(obligation, t)) + self.commit_if_ok( + |this, _| this.match_poly_trait_ref(obligation, t)) { Ok(_) => { upcast_trait_ref = Some(t); false } Err(_) => { true } @@ -2274,7 +2337,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // entries, so that we can compute the offset for the selected // trait. vtable_base = - nonmatching.map(|t| self.tcx().count_own_vtable_entries(t)) + nonmatching.map(|t| tcx.count_own_vtable_entries(t)) .sum(); } @@ -2282,12 +2345,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base: vtable_base, + nested: vec![] } } - fn confirm_fn_pointer_candidate(&mut self, - obligation: &TraitObligation<'tcx>) - -> Result,SelectionError<'tcx>> + fn confirm_fn_pointer_candidate(&mut self, obligation: &TraitObligation<'tcx>) + -> Result>, SelectionError<'tcx>> { debug!("confirm_fn_pointer_candidate({:?})", obligation); @@ -2305,7 +2368,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.confirm_poly_trait_refs(obligation.cause.clone(), obligation.predicate.to_poly_trait_ref(), trait_ref)?; - Ok(self_ty) + Ok(VtableFnPointerData { fn_ty: self_ty, nested: vec![] }) } fn confirm_closure_candidate(&mut self, @@ -2384,8 +2447,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { origin, expected_trait_ref.clone(), obligation_trait_ref.clone()) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) + .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) } @@ -2420,8 +2482,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, new_trait, target) .map_err(|_| Unimplemented)?; - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.inferred_obligations.extend(obligations); // Register one obligation for 'a: 'b. let cause = ObligationCause::new(obligation.cause.span, @@ -2494,8 +2555,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, a, b) .map_err(|_| Unimplemented)?; - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.inferred_obligations.extend(obligations); } // Struct -> Struct. @@ -2554,8 +2614,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, new_struct, target) .map_err(|_| Unimplemented)?; - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.inferred_obligations.extend(obligations); // Construct the nested Field: Unsize> predicate. nested.push(tcx.predicate_for_trait_def( @@ -2649,8 +2708,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("match_impl: failed eq_trait_refs due to `{}`", e); () })?; - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.inferred_obligations.extend(obligations); if let Err(e) = self.infcx.leak_check(false, &skol_map, snapshot) { debug!("match_impl: failed leak check due to `{}`", e); @@ -2703,7 +2761,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// Returns `Ok` if `poly_trait_ref` being true implies that the /// obligation is satisfied. - fn match_poly_trait_ref(&self, + fn match_poly_trait_ref(&mut self, obligation: &TraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Result<(),()> @@ -2717,8 +2775,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { origin, poly_trait_ref, obligation.predicate.to_poly_trait_ref()) - // FIXME(#32730) propagate obligations - .map(|InferOk { obligations, .. }| assert!(obligations.is_empty())) + .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) .map_err(|_| ()) } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 1495ae72ab344..e210d2da94cfd 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -99,11 +99,20 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableDefaultImplData { } } -impl<'tcx> fmt::Debug for traits::VtableObjectData<'tcx> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableObject(upcast={:?}, vtable_base={})", + write!(f, "VtableObject(upcast={:?}, vtable_base={}, nested={:?})", self.upcast_trait_ref, - self.vtable_base) + self.vtable_base, + self.nested) + } +} + +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableFnPointer(fn_ty={:?}, nested={:?})", + self.fn_ty, + self.nested) } } @@ -185,19 +194,26 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { }) }) } - traits::VtableFnPointer(ty) => { - tcx.lift(&ty).map(traits::VtableFnPointer) + traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { + tcx.lift(&fn_ty).map(|fn_ty| { + traits::VtableFnPointer(traits::VtableFnPointerData { + fn_ty: fn_ty, + nested: nested, + }) + }) } traits::VtableParam(n) => Some(traits::VtableParam(n)), traits::VtableBuiltin(d) => Some(traits::VtableBuiltin(d)), traits::VtableObject(traits::VtableObjectData { upcast_trait_ref, - vtable_base + vtable_base, + nested }) => { tcx.lift(&upcast_trait_ref).map(|trait_ref| { traits::VtableObject(traits::VtableObjectData { upcast_trait_ref: trait_ref, - vtable_base: vtable_base + vtable_base: vtable_base, + nested: nested }) }) } @@ -276,16 +292,30 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinDa } } -impl<'tcx> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx> { +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx, N> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { traits::VtableObjectData { upcast_trait_ref: self.upcast_trait_ref.fold_with(folder), - vtable_base: self.vtable_base + vtable_base: self.vtable_base, + nested: self.nested.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.upcast_trait_ref.visit_with(visitor) || self.nested.visit_with(visitor) + } +} + +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableFnPointerData<'tcx, N> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + traits::VtableFnPointerData { + fn_ty: self.fn_ty.fold_with(folder), + nested: self.nested.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.upcast_trait_ref.visit_with(visitor) + self.fn_ty.visit_with(visitor) || self.nested.visit_with(visitor) } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 010add012379d..f8149565aa66b 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -473,9 +473,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Given an upcast trait object described by `object`, returns the /// index of the method `method_def_id` (which should be part of /// `object.upcast_trait_ref`) within the vtable for `object`. - pub fn get_vtable_index_of_object_method(self, - object: &super::VtableObjectData<'tcx>, - method_def_id: DefId) -> usize { + pub fn get_vtable_index_of_object_method(self, + object: &super::VtableObjectData<'tcx, N>, + method_def_id: DefId) -> usize { // Count number of methods preceding the one we are selecting and // add them to the total offset. // Skip over associated types and constants. diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 5246c6739d960..9aaffd76d3984 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -14,12 +14,38 @@ use hir::def_id::{DefId, CRATE_DEF_INDEX}; use ty::{self, Ty, TyCtxt}; use syntax::ast; +use std::cell::Cell; + +thread_local! { + static FORCE_ABSOLUTE: Cell = Cell::new(false) +} + +/// Enforces that item_path_str always returns an absolute path. +/// This is useful when building symbols that contain types, +/// where we want the crate name to be part of the symbol. +pub fn with_forced_absolute_paths R, R>(f: F) -> R { + FORCE_ABSOLUTE.with(|force| { + let old = force.get(); + force.set(true); + let result = f(); + force.set(old); + result + }) +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns a string identifying this def-id. This string is /// suitable for user output. It is relative to the current crate - /// root. + /// root, unless with_forced_absolute_paths was used. pub fn item_path_str(self, def_id: DefId) -> String { - let mut buffer = LocalPathBuffer::new(RootMode::Local); + let mode = FORCE_ABSOLUTE.with(|force| { + if force.get() { + RootMode::Absolute + } else { + RootMode::Local + } + }); + let mut buffer = LocalPathBuffer::new(mode); self.push_item_path(&mut buffer, def_id); buffer.into_string() } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 005d83da38dbf..114e81721ab28 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1260,7 +1260,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { match tcx.map.find(id) { Some(ast_map::NodeImplItem(ref impl_item)) => { match impl_item.node { - hir::ImplItemKind::Type(_) => { + hir::ImplItemKind::Type(_) | hir::ImplItemKind::Const(_, _) => { // associated types don't have their own entry (for some reason), // so for now just grab environment for the impl let impl_id = tcx.map.get_parent(id); @@ -1272,15 +1272,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { &predicates, tcx.region_maps.item_extent(id)) } - hir::ImplItemKind::Const(_, _) => { - let def_id = tcx.map.local_def_id(id); - let scheme = tcx.lookup_item_type(def_id); - let predicates = tcx.lookup_predicates(def_id); - tcx.construct_parameter_environment(impl_item.span, - &scheme.generics, - &predicates, - tcx.region_maps.item_extent(id)) - } hir::ImplItemKind::Method(_, ref body) => { let method_def_id = tcx.map.local_def_id(id); match tcx.impl_or_trait_item(method_def_id) { @@ -1303,7 +1294,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { } Some(ast_map::NodeTraitItem(trait_item)) => { match trait_item.node { - hir::TypeTraitItem(..) => { + hir::TypeTraitItem(..) | hir::ConstTraitItem(..) => { // associated types don't have their own entry (for some reason), // so for now just grab environment for the trait let trait_id = tcx.map.get_parent(id); @@ -1315,15 +1306,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { &predicates, tcx.region_maps.item_extent(id)) } - hir::ConstTraitItem(..) => { - let def_id = tcx.map.local_def_id(id); - let scheme = tcx.lookup_item_type(def_id); - let predicates = tcx.lookup_predicates(def_id); - tcx.construct_parameter_environment(trait_item.span, - &scheme.generics, - &predicates, - tcx.region_maps.item_extent(id)) - } hir::MethodTraitItem(_, ref body) => { // Use call-site for extent (unless this is a // trait method with no default; then fallback diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 0687faa112f5e..092a5196a531f 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -378,6 +378,53 @@ let c = &i; // still ok! ``` "##, +E0500: r##" +A borrowed variable was used in another closure. Example of erroneous code: + +```compile_fail +fn you_know_nothing(jon_snow: &mut i32) { + let nights_watch = || { + *jon_snow = 2; + }; + let starks = || { + *jon_snow = 3; // error: closure requires unique access to `jon_snow` + // but it is already borrowed + }; +} + +In here, `jon_snow` is already borrowed by the `nights_watch` closure, so it +cannot be borrowed by the `starks` closure at the same time. To fix this issue, +you can put the closure in its own scope: + +``` +fn you_know_nothing(jon_snow: &mut i32) { + { + let nights_watch = || { + *jon_snow = 2; + }; + } // At this point, `jon_snow` is free. + let starks = || { + *jon_snow = 3; + }; +} +``` + +Or, if the type implements the `Clone` trait, you can clone it between +closures: + +``` +fn you_know_nothing(jon_snow: &mut i32) { + let mut jon_copy = jon_snow.clone(); + let nights_watch = || { + jon_copy = 2; + }; + let starks = || { + *jon_snow = 3; + }; +} +``` +"##, + E0501: r##" This error indicates that a mutable variable is being used while it is still captured by a closure. Because the closure has borrowed the variable, it is not @@ -857,7 +904,6 @@ fn main() { register_diagnostics! { E0385, // {} in an aliasable location E0388, // {} in a static location - E0500, // closure requires unique access to `..` but .. is already borrowed E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ... E0503, // cannot use `..` because it was mutably borrowed E0505, // cannot move out of `..` because it is borrowed diff --git a/src/librustc_data_structures/snapshot_vec.rs b/src/librustc_data_structures/snapshot_vec.rs index 614e7aae74bbc..dac074ab91e1b 100644 --- a/src/librustc_data_structures/snapshot_vec.rs +++ b/src/librustc_data_structures/snapshot_vec.rs @@ -213,3 +213,11 @@ impl ops::IndexMut for SnapshotVec { self.get_mut(index) } } + +impl Extend for SnapshotVec { + fn extend(&mut self, iterable: T) where T: IntoIterator { + for item in iterable { + self.push(item); + } + } +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f0c2de2932775..b269ecfb8651e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -28,7 +28,7 @@ use rustc_borrowck as borrowck; use rustc_incremental; use rustc_resolve as resolve; use rustc_metadata::macro_import; -use rustc_metadata::creader::LocalCrateReader; +use rustc_metadata::creader::read_local_crates; use rustc_metadata::cstore::CStore; use rustc_trans::back::link; use rustc_trans::back::write; @@ -37,7 +37,7 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc::hir::lowering::{lower_crate, LoweringContext}; +use rustc::hir::lowering::lower_crate; use rustc_passes::{no_asm, loops, consts, rvalues, static_recursion}; use rustc_const_eval::check_match; use super::Compilation; @@ -142,22 +142,21 @@ pub fn compile_input(sess: &Session, let dep_graph = DepGraph::new(sess.opts.build_dep_graph()); // Collect defintions for def ids. - let defs = &RefCell::new(time(sess.time_passes(), - "collecting defs", - || hir_map::collect_definitions(&expanded_crate))); + let mut defs = time(sess.time_passes(), + "collecting defs", + || hir_map::collect_definitions(&expanded_crate)); time(sess.time_passes(), "external crate/lib resolution", - || LocalCrateReader::new(sess, &cstore, defs, &expanded_crate, &id) - .read_crates(&dep_graph)); + || read_local_crates(sess, &cstore, &defs, &expanded_crate, &id, &dep_graph)); time(sess.time_passes(), "early lint checks", || lint::check_ast_crate(sess, &expanded_crate)); let (analysis, resolutions, mut hir_forest) = { - let defs = &mut *defs.borrow_mut(); - lower_and_resolve(sess, &id, defs, &expanded_crate, dep_graph, control.make_glob_map) + lower_and_resolve(sess, &id, &mut defs, &expanded_crate, dep_graph, + control.make_glob_map) }; // Discard MTWT tables that aren't required past lowering to HIR. @@ -787,8 +786,7 @@ pub fn lower_and_resolve<'a>(sess: &Session, // Lower ast -> hir. let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || { - let lcx = LoweringContext::new(sess, Some(krate), &mut resolver); - hir_map::Forest::new(lower_crate(&lcx, krate), dep_graph) + hir_map::Forest::new(lower_crate(krate, sess, &mut resolver), dep_graph) }); (ty::CrateAnalysis { @@ -1009,7 +1007,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks); passes.push_pass(box mir::transform::erase_regions::EraseRegions); - passes.push_pass(box mir::transform::break_critical_edges::BreakCriticalEdges); + passes.push_pass(box mir::transform::break_cleanup_edges::BreakCleanupEdges); passes.run_passes(tcx, &mut mir_map); }); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4da36be94e009..c863ff21b2c7a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -504,10 +504,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.after_write_deps.stop = Compilation::Stop; } - if sess.opts.no_trans { - control.after_analysis.stop = Compilation::Stop; - } - if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) { control.after_llvm.stop = Compilation::Stop; } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 9bbf250b9714e..bbda1965c7fac 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -26,10 +26,9 @@ use rustc::traits::ProjectionMode; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::infer::{self, InferOk, InferResult, TypeOrigin}; use rustc_metadata::cstore::CStore; -use rustc_metadata::creader::LocalCrateReader; +use rustc_metadata::creader::read_local_crates; use rustc::hir::map as hir_map; use rustc::session::{self, config}; -use std::cell::RefCell; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; @@ -120,13 +119,13 @@ fn test_env(source_string: &str, let dep_graph = DepGraph::new(false); let krate = driver::assign_node_ids(&sess, krate); - let defs = &RefCell::new(hir_map::collect_definitions(&krate)); - LocalCrateReader::new(&sess, &cstore, defs, &krate, "test_crate").read_crates(&dep_graph); + let mut defs = hir_map::collect_definitions(&krate); + read_local_crates(&sess, &cstore, &defs, &krate, "test_crate", &dep_graph); let _ignore = dep_graph.in_ignore(); let (_, resolutions, mut hir_forest) = { - let (defs, dep_graph) = (&mut *defs.borrow_mut(), dep_graph.clone()); - driver::lower_and_resolve(&sess, "test-crate", defs, &krate, dep_graph, MakeGlobMap::No) + driver::lower_and_resolve(&sess, "test-crate", &mut defs, &krate, dep_graph.clone(), + MakeGlobMap::No) }; let arenas = ty::CtxtArenas::new(); diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 6da2e5b17a5e8..ad0e8e1c37623 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -57,7 +57,7 @@ use rustc_serialize::{Encodable, EncoderHelpers}; #[cfg(test)] use syntax::parse; #[cfg(test)] use syntax::ast::NodeId; #[cfg(test)] use rustc::hir::print as pprust; -#[cfg(test)] use rustc::hir::lowering::{lower_item, LoweringContext, DummyResolver}; +#[cfg(test)] use rustc::hir::lowering::{LoweringContext, DummyResolver}; struct DecodeContext<'a, 'b, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1319,11 +1319,11 @@ fn mk_ctxt() -> parse::ParseSess { } #[cfg(test)] -fn with_testing_context T>(f: F) -> T { +fn with_testing_context T>(f: F) -> T { let assigner = FakeNodeIdAssigner; let mut resolver = DummyResolver; - let lcx = LoweringContext::new(&assigner, None, &mut resolver); - f(lcx) + let mut lcx = LoweringContext::testing_context(&assigner, &mut resolver); + f(&mut lcx) } #[cfg(test)] @@ -1340,7 +1340,7 @@ fn roundtrip(in_item: hir::Item) { fn test_basic() { let cx = mk_ctxt(); with_testing_context(|lcx| { - roundtrip(lower_item(&lcx, "e_item!(&cx, + roundtrip(lcx.lower_item("e_item!(&cx, fn foo() {} ).unwrap())); }); @@ -1350,7 +1350,7 @@ fn test_basic() { fn test_smalltalk() { let cx = mk_ctxt(); with_testing_context(|lcx| { - roundtrip(lower_item(&lcx, "e_item!(&cx, + roundtrip(lcx.lower_item("e_item!(&cx, fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed. ).unwrap())); }); @@ -1360,7 +1360,7 @@ fn test_smalltalk() { fn test_more() { let cx = mk_ctxt(); with_testing_context(|lcx| { - roundtrip(lower_item(&lcx, "e_item!(&cx, + roundtrip(lcx.lower_item("e_item!(&cx, fn foo(x: usize, y: usize) -> usize { let z = x + y; return z; @@ -1380,10 +1380,10 @@ fn test_simplification() { ).unwrap(); let cx = mk_ctxt(); with_testing_context(|lcx| { - let hir_item = lower_item(&lcx, &item); + let hir_item = lcx.lower_item(&item); let item_in = InlinedItemRef::Item(&hir_item); let item_out = simplify_ast(item_in); - let item_exp = InlinedItem::Item(P(lower_item(&lcx, "e_item!(&cx, + let item_exp = InlinedItem::Item(P(lcx.lower_item("e_item!(&cx, fn new_int_alist() -> alist { return alist {eq_fn: eq_int, data: Vec::new()}; } diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 2b972af07ff91..74f97de265898 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -33,7 +33,7 @@ pub const tag_items_data_item_family: usize = 0x24; pub const tag_items_data_item_type: usize = 0x25; -pub const tag_items_data_item_symbol: usize = 0x26; +// GAP 0x26 pub const tag_items_data_item_variant: usize = 0x27; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 190e8552d199a..c78a3a0be74de 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -17,6 +17,7 @@ use cstore::{self, CStore, CrateSource, MetadataBlob}; use decoder; use loader::{self, CratePaths}; +use rustc::hir::def_id::DefIndex; use rustc::hir::svh::Svh; use rustc::dep_graph::{DepGraph, DepNode}; use rustc::session::{config, Session}; @@ -41,12 +42,12 @@ use syntax::parse::token::InternedString; use syntax::visit; use log; -pub struct LocalCrateReader<'a> { +struct LocalCrateReader<'a> { sess: &'a Session, cstore: &'a CStore, creader: CrateReader<'a>, krate: &'a ast::Crate, - defintions: &'a RefCell, + definitions: &'a hir_map::Definitions, } pub struct CrateReader<'a> { @@ -578,9 +579,10 @@ impl<'a> CrateReader<'a> { macros } - /// Look for a plugin registrar. Returns library path and symbol name. + /// Look for a plugin registrar. Returns library path, crate + /// SVH and DefIndex of the registrar function. pub fn find_plugin_registrar(&mut self, span: Span, name: &str) - -> Option<(PathBuf, String)> { + -> Option<(PathBuf, Svh, DefIndex)> { let ekrate = self.read_extension_crate(span, &CrateInfo { name: name.to_string(), ident: name.to_string(), @@ -598,12 +600,14 @@ impl<'a> CrateReader<'a> { span_fatal!(self.sess, span, E0456, "{}", &message[..]); } + let svh = decoder::get_crate_hash(ekrate.metadata.as_slice()); let registrar = - decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()) - .map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id)); + decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()); match (ekrate.dylib.as_ref(), registrar) { - (Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)), + (Some(dylib), Some(reg)) => { + Some((dylib.to_path_buf(), svh, reg)) + } (None, Some(_)) => { span_err!(self.sess, span, E0457, "plugin `{}` only found in rlib format, but must be available \ @@ -841,25 +845,25 @@ impl<'a> CrateReader<'a> { } impl<'a> LocalCrateReader<'a> { - pub fn new(sess: &'a Session, - cstore: &'a CStore, - defs: &'a RefCell, - krate: &'a ast::Crate, - local_crate_name: &str) - -> LocalCrateReader<'a> { + fn new(sess: &'a Session, + cstore: &'a CStore, + defs: &'a hir_map::Definitions, + krate: &'a ast::Crate, + local_crate_name: &str) + -> LocalCrateReader<'a> { LocalCrateReader { sess: sess, cstore: cstore, creader: CrateReader::new(sess, cstore, local_crate_name), krate: krate, - defintions: defs, + definitions: defs, } } // Traverses an AST, reading all the information about use'd crates and // extern libraries necessary for later resolving, typechecking, linking, // etc. - pub fn read_crates(&mut self, dep_graph: &DepGraph) { + fn read_crates(&mut self, dep_graph: &DepGraph) { let _task = dep_graph.in_task(DepNode::CrateReader); self.process_crate(self.krate); @@ -902,9 +906,8 @@ impl<'a> LocalCrateReader<'a> { PathKind::Crate, true); - let defs = self.defintions.borrow(); - let def_id = defs.opt_local_def_id(i.id).unwrap(); - let len = defs.def_path(def_id.index).data.len(); + let def_id = self.definitions.opt_local_def_id(i.id).unwrap(); + let len = self.definitions.def_path(def_id.index).data.len(); self.creader.update_extern_crate(cnum, ExternCrate { @@ -982,6 +985,17 @@ impl<'a> LocalCrateReader<'a> { } } +/// Traverses an AST, reading all the information about use'd crates and extern +/// libraries necessary for later resolving, typechecking, linking, etc. +pub fn read_local_crates(sess: & Session, + cstore: & CStore, + defs: & hir_map::Definitions, + krate: & ast::Crate, + local_crate_name: &str, + dep_graph: &DepGraph) { + LocalCrateReader::new(sess, cstore, defs, krate, local_crate_name).read_crates(dep_graph) +} + /// Imports the codemap from an external crate into the codemap of the crate /// currently being compiled (the "local crate"). /// diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 8d464099783a6..6461869344d65 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -23,7 +23,7 @@ use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::map as hir_map; use rustc::mir::repr::Mir; use rustc::mir::mir_map::MirMap; -use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; +use rustc::util::nodemap::{FnvHashMap, NodeSet, DefIdMap}; use rustc::session::config::PanicStrategy; use std::cell::RefCell; @@ -105,12 +105,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_item_attrs(&cdata, def_id.index) } - fn item_symbol(&self, def: DefId) -> String - { - let cdata = self.get_crate_data(def.krate); - decoder::get_symbol(&cdata, def.index) - } - fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef<'tcx> { let cdata = self.get_crate_data(def.krate); @@ -252,6 +246,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::is_extern_item(&cdata, did.index, tcx) } + fn is_foreign_item(&self, did: DefId) -> bool { + let cdata = self.get_crate_data(did.krate); + decoder::is_foreign_item(&cdata, did.index) + } + fn is_static_method(&self, def: DefId) -> bool { let cdata = self.get_crate_data(def.krate); @@ -512,7 +511,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, - item_symbols: &RefCell>, link_meta: &LinkMeta, reachable: &NodeSet, mir_map: &MirMap<'tcx>, @@ -522,7 +520,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { diag: tcx.sess.diagnostic(), tcx: tcx, reexports: reexports, - item_symbols: item_symbols, link_meta: link_meta, cstore: self, reachable: reachable, diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e233dda7e91ee..2c1114e3ee713 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -186,10 +186,6 @@ fn item_sort(item: rbml::Doc) -> Option { }) } -fn item_symbol(item: rbml::Doc) -> String { - reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string() -} - fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { let id = reader::doc_as_u64(d); let index = DefIndex::new((id & 0xFFFF_FFFF) as usize); @@ -609,18 +605,6 @@ pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd, } } -pub fn get_symbol(cdata: Cmd, id: DefIndex) -> String { - return item_symbol(cdata.lookup_item(id)); -} - -/// If you have a crate_metadata, call get_symbol instead -pub fn get_symbol_from_buf(data: &[u8], id: DefIndex) -> String { - let index = load_index(data); - let pos = index.lookup_item(data, id).unwrap(); - let doc = reader::doc_at(data, pos as usize).unwrap().doc; - item_symbol(doc) -} - /// Iterates over the language items in the given crate. pub fn each_lang_item(cdata: Cmd, mut f: F) -> bool where F: FnMut(DefIndex, usize) -> bool, @@ -1611,6 +1595,16 @@ pub fn is_extern_item<'a, 'tcx>(cdata: Cmd, } } +pub fn is_foreign_item(cdata: Cmd, id: DefIndex) -> bool { + let item_doc = cdata.lookup_item(id); + let parent_item_id = match item_parent_item(cdata, item_doc) { + None => return false, + Some(item_id) => item_id, + }; + let parent_item_doc = cdata.lookup_item(parent_item_id.index); + item_family(parent_item_doc) == ForeignMod +} + pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool { let item_doc = cdata.lookup_item(id); match item_family(item_doc) { diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 8fa23de9a2d16..ae9f500c5de59 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -26,6 +26,27 @@ name. Example: ``` "##, +E0455: r##" +Linking with `kind=framework` is only supported when targeting OS X, +as frameworks are specific to that operating system. + +Erroneous code example: + +```compile_fail" +#[link(name = "FooCoreServices", kind = "framework")] extern {} +// OS used to compile is Linux for example +``` + +To solve this error you can use conditional compilation: + +``` +#[cfg_attr(target="macos", link(name = "FooCoreServices", kind = "framework"))] +extern {} +``` + +See more: https://doc.rust-lang.org/book/conditional-compilation.html +"##, + E0458: r##" An unknown "kind" was specified for a link attribute. Erroneous code example: @@ -73,7 +94,6 @@ well, and you link to them the same way. } register_diagnostics! { - E0455, // native frameworks are only available on OSX targets E0456, // plugin `..` is not available for triple `..` E0457, // plugin `..` only found in rlib format, but must be available... E0514, // metadata version mismatch diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 020f12d753e63..80c139b1be124 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -33,7 +33,7 @@ use rustc::ty::util::IntTypeExt; use rustc::hir::svh::Svh; use rustc::mir::mir_map::MirMap; use rustc::session::config::{self, PanicStrategy}; -use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet}; +use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::Encodable; use std::cell::RefCell; @@ -58,7 +58,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> { pub diag: &'a Handler, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub reexports: &'a def::ExportMap, - pub item_symbols: &'a RefCell>, pub link_meta: &'a LinkMeta, pub cstore: &'a cstore::CStore, pub type_abbrevs: tyencode::abbrev_map<'tcx>, @@ -204,20 +203,6 @@ fn encode_region(ecx: &EncodeContext, rbml_w.end_tag(); } -fn encode_symbol(ecx: &EncodeContext, - rbml_w: &mut Encoder, - id: NodeId) { - match ecx.item_symbols.borrow().get(&id) { - Some(x) => { - debug!("encode_symbol(id={}, str={})", id, *x); - rbml_w.wr_tagged_str(tag_items_data_item_symbol, x); - } - None => { - bug!("encode_symbol: id not found {}", id); - } - } -} - fn encode_disr_val(_: &EncodeContext, rbml_w: &mut Encoder, disr_val: ty::Disr) { @@ -512,10 +497,6 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_name(rbml_w, name); encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id)); - if ecx.item_symbols.borrow().contains_key(&ctor_id) { - encode_symbol(ecx, rbml_w, ctor_id); - } - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(ctor_id)); let depr= ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(ctor_id)); encode_stability(rbml_w, stab); @@ -704,10 +685,6 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } encode_constness(rbml_w, sig.constness); encode_defaultness(rbml_w, impl_item.defaultness); - if !any_types { - let m_id = ecx.local_id(m.def_id); - encode_symbol(ecx, rbml_w, m_id); - } encode_method_argument_names(rbml_w, &sig.decl); } } @@ -885,7 +862,6 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_family(rbml_w, 'c'); } encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id); - encode_symbol(ecx, rbml_w, item.id); encode_name(rbml_w, item.name); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); @@ -922,9 +898,6 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); encode_mir(ecx, rbml_w, item.id); } - if tps_len == 0 { - encode_symbol(ecx, rbml_w, item.id); - } encode_constness(rbml_w, constness); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); @@ -1344,6 +1317,8 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, index.record(def_id, rbml_w); rbml_w.start_tag(tag_items_data_item); encode_def_id_and_key(ecx, rbml_w, def_id); + let parent_id = ecx.tcx.map.get_parent(nitem.id); + encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); encode_visibility(rbml_w, &nitem.vis); match nitem.node { hir::ForeignItemFn(ref fndecl, _) => { @@ -1353,8 +1328,6 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem)); encode_mir(ecx, rbml_w, nitem.id); - } else { - encode_symbol(ecx, rbml_w, nitem.id); } encode_attributes(rbml_w, &nitem.attrs); let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); @@ -1375,7 +1348,6 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); encode_stability(rbml_w, stab); encode_deprecation(rbml_w, depr); - encode_symbol(ecx, rbml_w, nitem.id); encode_name(rbml_w, nitem.name); } } diff --git a/src/librustc_mir/transform/break_cleanup_edges.rs b/src/librustc_mir/transform/break_cleanup_edges.rs new file mode 100644 index 0000000000000..0eb6223a71e54 --- /dev/null +++ b/src/librustc_mir/transform/break_cleanup_edges.rs @@ -0,0 +1,111 @@ +// Copyright 2016 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. + +use rustc::ty::TyCtxt; +use rustc::mir::repr::*; +use rustc::mir::transform::{MirPass, MirSource, Pass}; + +use rustc_data_structures::bitvec::BitVector; + +use pretty; + +use traversal; + +pub struct BreakCleanupEdges; + +/** + * Breaks outgoing critical edges for call terminators in the MIR. + * + * Critical edges are edges that are neither the only edge leaving a + * block, nor the only edge entering one. + * + * When you want something to happen "along" an edge, you can either + * do at the end of the predecessor block, or at the start of the + * successor block. Critical edges have to be broken in order to prevent + * "edge actions" from affecting other edges. We need this for calls that are + * translated to LLVM invoke instructions, because invoke is a block terminator + * in LLVM so we can't insert any code to handle the call's result into the + * block that performs the call. + * + * This function will break those edges by inserting new blocks along them. + * + * NOTE: Simplify CFG will happily undo most of the work this pass does. + * + */ + +impl<'tcx> MirPass<'tcx> for BreakCleanupEdges { + fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { + let mut pred_count = vec![0u32; mir.basic_blocks.len()]; + + // Build the precedecessor map for the MIR + for (_, data) in traversal::preorder(mir) { + if let Some(ref term) = data.terminator { + for &tgt in term.successors().iter() { + pred_count[tgt.index()] += 1; + } + } + } + + let cleanup_map : BitVector = mir.basic_blocks + .iter().map(|bb| bb.is_cleanup).collect(); + + // We need a place to store the new blocks generated + let mut new_blocks = Vec::new(); + + let bbs = mir.all_basic_blocks(); + let cur_len = mir.basic_blocks.len(); + + for &bb in &bbs { + let data = mir.basic_block_data_mut(bb); + + if let Some(ref mut term) = data.terminator { + if term_is_invoke(term) { + let term_span = term.span; + let term_scope = term.scope; + let succs = term.successors_mut(); + for tgt in succs { + let num_preds = pred_count[tgt.index()]; + if num_preds > 1 { + // It's a critical edge, break it + let goto = Terminator { + span: term_span, + scope: term_scope, + kind: TerminatorKind::Goto { target: *tgt } + }; + let mut data = BasicBlockData::new(Some(goto)); + data.is_cleanup = cleanup_map.contains(tgt.index()); + + // Get the index it will be when inserted into the MIR + let idx = cur_len + new_blocks.len(); + new_blocks.push(data); + *tgt = BasicBlock::new(idx); + } + } + } + } + } + + pretty::dump_mir(tcx, "break_cleanup_edges", &0, src, mir, None); + debug!("Broke {} N edges", new_blocks.len()); + + mir.basic_blocks.extend_from_slice(&new_blocks); + } +} + +impl Pass for BreakCleanupEdges {} + +// Returns true if the terminator is a call that would use an invoke in LLVM. +fn term_is_invoke(term: &Terminator) -> bool { + match term.kind { + TerminatorKind::Call { cleanup: Some(_), .. } | + TerminatorKind::Drop { unwind: Some(_), .. } => true, + _ => false + } +} diff --git a/src/librustc_mir/transform/break_critical_edges.rs b/src/librustc_mir/transform/break_critical_edges.rs deleted file mode 100644 index a6af30b7eec08..0000000000000 --- a/src/librustc_mir/transform/break_critical_edges.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2016 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. - -use rustc::ty::TyCtxt; -use rustc::mir::repr::*; -use rustc::mir::transform::{MirPass, MirSource, Pass}; - -use rustc_data_structures::bitvec::BitVector; - -use traversal; - -pub struct BreakCriticalEdges; - -/** - * Breaks critical edges in the MIR. - * - * Critical edges are edges that are neither the only edge leaving a - * block, nor the only edge entering one. - * - * When you want something to happen "along" an edge, you can either - * do at the end of the predecessor block, or at the start of the - * successor block. Critical edges have to be broken in order to prevent - * "edge actions" from affecting other edges. - * - * This function will break those edges by inserting new blocks along them. - * - * A special case is Drop and Call terminators with unwind/cleanup successors, - * They use `invoke` in LLVM, which terminates a block, meaning that code cannot - * be inserted after them, so even if an edge is the only edge leaving a block - * like that, we still insert blocks if the edge is one of many entering the - * target. - * - * NOTE: Simplify CFG will happily undo most of the work this pass does. - * - */ - -impl<'tcx> MirPass<'tcx> for BreakCriticalEdges { - fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, - _: MirSource, mir: &mut Mir<'tcx>) { - break_critical_edges(mir); - } -} - -impl Pass for BreakCriticalEdges {} - -fn break_critical_edges(mir: &mut Mir) { - let mut pred_count = vec![0u32; mir.basic_blocks.len()]; - - // Build the precedecessor map for the MIR - for (_, data) in traversal::preorder(mir) { - if let Some(ref term) = data.terminator { - for &tgt in term.successors().iter() { - pred_count[tgt.index()] += 1; - } - } - } - - let cleanup_map : BitVector = mir.basic_blocks - .iter().map(|bb| bb.is_cleanup).collect(); - - // We need a place to store the new blocks generated - let mut new_blocks = Vec::new(); - - let bbs = mir.all_basic_blocks(); - let cur_len = mir.basic_blocks.len(); - - for &bb in &bbs { - let data = mir.basic_block_data_mut(bb); - - if let Some(ref mut term) = data.terminator { - let is_invoke = term_is_invoke(term); - let term_span = term.span; - let term_scope = term.scope; - let succs = term.successors_mut(); - if succs.len() > 1 || (succs.len() > 0 && is_invoke) { - for tgt in succs { - let num_preds = pred_count[tgt.index()]; - if num_preds > 1 { - // It's a critical edge, break it - let goto = Terminator { - span: term_span, - scope: term_scope, - kind: TerminatorKind::Goto { target: *tgt } - }; - let mut data = BasicBlockData::new(Some(goto)); - data.is_cleanup = cleanup_map.contains(tgt.index()); - - // Get the index it will be when inserted into the MIR - let idx = cur_len + new_blocks.len(); - new_blocks.push(data); - *tgt = BasicBlock::new(idx); - } - } - } - } - } - - debug!("Broke {} N edges", new_blocks.len()); - - mir.basic_blocks.extend_from_slice(&new_blocks); -} - -// Returns true if the terminator would use an invoke in LLVM. -fn term_is_invoke(term: &Terminator) -> bool { - match term.kind { - TerminatorKind::Call { cleanup: Some(_), .. } | - TerminatorKind::Drop { unwind: Some(_), .. } => true, - _ => false - } -} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 51f5c3cd7f53d..0dcb7ef84d01d 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -13,6 +13,6 @@ pub mod simplify_cfg; pub mod erase_regions; pub mod no_landing_pads; pub mod type_check; -pub mod break_critical_edges; +pub mod break_cleanup_edges; pub mod promote_consts; pub mod qualify_consts; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 54ac04bea9c4c..4eda1ed23b757 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -64,13 +64,18 @@ bitflags! { // pointer comparisons, ptr-to-int casts, etc. const NOT_CONST = 1 << 6, + // Refers to temporaries which cannot be promoted as + // promote_consts decided they weren't simple enough. + const NOT_PROMOTABLE = 1 << 7, + // Borrows of temporaries can be promoted only // if they have none of the above qualifications. - const UNPROMOTABLE = !0, + const NEVER_PROMOTE = !0, // Const items can only have MUTABLE_INTERIOR - // without producing an error. - const CONST_ERROR = !Qualif::MUTABLE_INTERIOR.bits + // and NOT_PROMOTABLE without producing an error. + const CONST_ERROR = !Qualif::MUTABLE_INTERIOR.bits & + !Qualif::NOT_PROMOTABLE.bits } } @@ -503,6 +508,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.add(Qualif::NOT_CONST); } Lvalue::Temp(index) => { + if !self.temp_promotion_state[index as usize].is_promotable() { + self.add(Qualif::NOT_PROMOTABLE); + } + if let Some(qualif) = self.temp_qualif[index as usize] { self.add(qualif); } else { @@ -688,8 +697,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // We might have a candidate for promotion. let candidate = Candidate::Ref(self.location); if self.mode == Mode::Fn || self.mode == Mode::ConstFn { - if !self.qualif.intersects(Qualif::UNPROMOTABLE) { - self.promotion_candidates.push(candidate); + if !self.qualif.intersects(Qualif::NEVER_PROMOTE) { + // We can only promote direct borrows of temps. + if let Lvalue::Temp(_) = *lvalue { + self.promotion_candidates.push(candidate); + } } } } @@ -781,7 +793,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { this.visit_operand(arg); if is_shuffle && i == 2 && this.mode == Mode::Fn { let candidate = Candidate::ShuffleIndices(bb); - if !this.qualif.intersects(Qualif::UNPROMOTABLE) { + if !this.qualif.intersects(Qualif::NEVER_PROMOTE) { this.promotion_candidates.push(candidate); } else { span_err!(this.tcx.sess, this.span, E0526, diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index fa897384a542a..526157a49c734 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -8,73 +8,155 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_data_structures::bitvec::BitVector; use rustc::middle::const_val::ConstVal; use rustc::ty::TyCtxt; use rustc::mir::repr::*; use rustc::mir::transform::{MirPass, MirSource, Pass}; use pretty; +use std::mem; use super::remove_dead_blocks::RemoveDeadBlocks; +use traversal; + pub struct SimplifyCfg; impl SimplifyCfg { pub fn new() -> SimplifyCfg { SimplifyCfg } +} + +impl<'tcx> MirPass<'tcx> for SimplifyCfg { + fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) { + simplify_branches(mir); + RemoveDeadBlocks.run_pass(tcx, src, mir); + merge_consecutive_blocks(mir); + RemoveDeadBlocks.run_pass(tcx, src, mir); + pretty::dump_mir(tcx, "simplify_cfg", &0, src, mir, None); + + // FIXME: Should probably be moved into some kind of pass manager + mir.basic_blocks.shrink_to_fit(); + } +} + +impl Pass for SimplifyCfg {} + +fn merge_consecutive_blocks(mir: &mut Mir) { + // Build the precedecessor map for the MIR + let mut pred_count = vec![0u32; mir.basic_blocks.len()]; + for (_, data) in traversal::preorder(mir) { + if let Some(ref term) = data.terminator { + for &tgt in term.successors().iter() { + pred_count[tgt.index()] += 1; + } + } + } + + loop { + let mut changed = false; + let mut seen = BitVector::new(mir.basic_blocks.len()); + let mut worklist = vec![START_BLOCK]; + while let Some(bb) = worklist.pop() { + // Temporarily take ownership of the terminator we're modifying to keep borrowck happy + let mut terminator = mir.basic_block_data_mut(bb).terminator.take() + .expect("invalid terminator state"); + + // See if we can merge the target block into this one + loop { + let mut inner_change = false; - fn remove_goto_chains(&self, mir: &mut Mir) -> bool { - // Find the target at the end of the jump chain, return None if there is a loop - fn final_target(mir: &Mir, mut target: BasicBlock) -> Option { - // Keep track of already seen blocks to detect loops - let mut seen: Vec = Vec::with_capacity(8); - - while mir.basic_block_data(target).statements.is_empty() { - // NB -- terminator may have been swapped with `None` - // below, in which case we have a cycle and just want - // to stop - if let Some(ref terminator) = mir.basic_block_data(target).terminator { - match terminator.kind { - TerminatorKind::Goto { target: next } => { - if seen.contains(&next) { - return None; + if let TerminatorKind::Goto { target } = terminator.kind { + // Don't bother trying to merge a block into itself + if target == bb { + break; + } + + let num_insts = mir.basic_block_data(target).statements.len(); + match mir.basic_block_data(target).terminator().kind { + TerminatorKind::Goto { target: new_target } if num_insts == 0 => { + inner_change = true; + terminator.kind = TerminatorKind::Goto { target: new_target }; + pred_count[target.index()] -= 1; + pred_count[new_target.index()] += 1; + } + _ if pred_count[target.index()] == 1 => { + inner_change = true; + let mut stmts = Vec::new(); + { + let target_data = mir.basic_block_data_mut(target); + mem::swap(&mut stmts, &mut target_data.statements); + mem::swap(&mut terminator, target_data.terminator_mut()); } - seen.push(next); - target = next; + + mir.basic_block_data_mut(bb).statements.append(&mut stmts); } - _ => break + _ => {} + }; + } + + for target in terminator.successors_mut() { + let new_target = match final_target(mir, *target) { + Some(new_target) => new_target, + None if mir.basic_block_data(bb).statements.is_empty() => bb, + None => continue + }; + if *target != new_target { + inner_change = true; + pred_count[target.index()] -= 1; + pred_count[new_target.index()] += 1; + *target = new_target; } - } else { - break + } + + changed |= inner_change; + if !inner_change { + break; } } - Some(target) + mir.basic_block_data_mut(bb).terminator = Some(terminator); + + for succ in mir.basic_block_data(bb).terminator().successors().iter() { + if seen.insert(succ.index()) { + worklist.push(*succ); + } + } } - let mut changed = false; - for bb in mir.all_basic_blocks() { - // Temporarily take ownership of the terminator we're modifying to keep borrowck happy - let mut terminator = mir.basic_block_data_mut(bb).terminator.take() - .expect("invalid terminator state"); - - debug!("remove_goto_chains: bb={:?} terminator={:?}", bb, terminator); - - for target in terminator.successors_mut() { - let new_target = match final_target(mir, *target) { - Some(new_target) => new_target, - None if mir.basic_block_data(bb).statements.is_empty() => bb, - None => continue - }; - changed |= *target != new_target; - *target = new_target; + if !changed { + break; + } + } +} + +// Find the target at the end of the jump chain, return None if there is a loop +fn final_target(mir: &Mir, mut target: BasicBlock) -> Option { + // Keep track of already seen blocks to detect loops + let mut seen: Vec = Vec::with_capacity(8); + + while mir.basic_block_data(target).statements.is_empty() { + // NB -- terminator may have been swapped with `None` in + // merge_consecutive_blocks, in which case we have a cycle and just want + // to stop + match mir.basic_block_data(target).terminator { + Some(Terminator { kind: TerminatorKind::Goto { target: next }, .. }) => { + if seen.contains(&next) { + return None; + } + seen.push(next); + target = next; } - mir.basic_block_data_mut(bb).terminator = Some(terminator); + _ => break } - changed } - fn simplify_branches(&self, mir: &mut Mir) -> bool { + Some(target) +} + +fn simplify_branches(mir: &mut Mir) { + loop { let mut changed = false; for bb in mir.all_basic_blocks() { @@ -106,25 +188,8 @@ impl SimplifyCfg { } } - changed - } -} - -impl<'tcx> MirPass<'tcx> for SimplifyCfg { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, mir: &mut Mir<'tcx>) { - let mut counter = 0; - let mut changed = true; - while changed { - pretty::dump_mir(tcx, "simplify_cfg", &counter, src, mir, None); - counter += 1; - changed = self.simplify_branches(mir); - changed |= self.remove_goto_chains(mir); - RemoveDeadBlocks.run_pass(tcx, src, mir); + if !changed { + break; } - // FIXME: Should probably be moved into some kind of pass manager - mir.basic_blocks.shrink_to_fit(); } } - -impl Pass for SimplifyCfg {} diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 036e46c380398..11e1841f7493e 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -101,7 +101,8 @@ impl<'a> PluginLoader<'a> { fn load_plugin(&mut self, span: Span, name: &str, args: Vec>) { let registrar = self.reader.find_plugin_registrar(span, name); - if let Some((lib, symbol)) = registrar { + if let Some((lib, svh, index)) = registrar { + let symbol = self.sess.generate_plugin_registrar_symbol(&svh, index); let fun = self.dylink_registrar(span, lib, symbol); self.plugins.push(PluginRegistrar { fun: fun, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fc048c86dc9dd..a1a966ea65a15 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1949,9 +1949,7 @@ impl<'a> Resolver<'a> { this.check_trait_item(impl_item.ident.name, impl_item.span, |n, s| ResolutionError::ConstNotMemberOfTrait(n, s)); - this.with_constant_rib(|this| { - visit::walk_impl_item(this, impl_item); - }); + visit::walk_impl_item(this, impl_item); } ImplItemKind::Method(ref sig, _) => { // If this is a trait impl, ensure the method @@ -2544,6 +2542,8 @@ impl<'a> Resolver<'a> { /// returned value. See `hir::def::PathResolution` for more info. fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace: Namespace) -> Result { + debug!("resolve_path(id={:?} path={:?}, path_depth={:?})", id, path, path_depth); + let span = path.span; let segments = &path.segments[..path.segments.len() - path_depth]; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 00d9658cb5943..c54432c6e5838 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -9,7 +9,7 @@ // except according to those terms. use super::archive::{ArchiveBuilder, ArchiveConfig}; -use super::linker::{Linker, GnuLinker, MsvcLinker}; +use super::linker::Linker; use super::rpath::RPathConfig; use super::rpath; use super::msvc; @@ -634,13 +634,9 @@ fn link_natively(sess: &Session, dylib: bool, } { - let mut linker = if sess.target.target.options.is_like_msvc { - Box::new(MsvcLinker { cmd: &mut cmd, sess: &sess }) as Box - } else { - Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box - }; + let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); link_args(&mut *linker, sess, dylib, tmpdir, - objects, out_filename, trans, outputs); + objects, out_filename, outputs); if !sess.target.target.options.no_compiler_rt { linker.link_staticlib("compiler-rt"); } @@ -709,7 +705,6 @@ fn link_args(cmd: &mut Linker, tmpdir: &Path, objects: &[PathBuf], out_filename: &Path, - trans: &CrateTranslation, outputs: &OutputFilenames) { // The default library location, we need this to find the runtime. @@ -728,7 +723,7 @@ fn link_args(cmd: &mut Linker, // If we're building a dynamic library then some platforms need to make sure // that all symbols are exported correctly from the dynamic library. if dylib { - cmd.export_symbols(sess, trans, tmpdir); + cmd.export_symbols(tmpdir); } // When linking a dynamic library, we put the metadata into a section of the diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 8055e97034e3f..858fe65c0fc7f 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -9,19 +9,91 @@ // except according to those terms. use std::ffi::OsString; +use std::fmt::Write as FmtWrite; use std::fs::{self, File}; use std::io::{self, BufWriter}; use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; +use context::SharedCrateContext; +use monomorphize::Instance; + use back::archive; use middle::dependency_format::Linkage; use session::Session; use session::config::CrateTypeDylib; use session::config; use syntax::ast; -use CrateTranslation; + +/// For all the linkers we support, and information they might +/// need out of the shared crate context before we get rid of it. +pub enum LinkerInfo { + Gnu, + Msvc { + dylib_exports: String + } +} + +impl<'a, 'tcx> LinkerInfo { + pub fn new(scx: &SharedCrateContext<'a, 'tcx>, + reachable: &[String]) -> LinkerInfo { + if scx.sess().target.target.options.is_like_msvc { + let mut exports = String::new(); + if scx.sess().crate_types.borrow().contains(&CrateTypeDylib) { + for sym in reachable { + writeln!(exports, " {}", sym).unwrap(); + } + + // Take a look at how all upstream crates are linked into this + // dynamic library. For all statically linked libraries we take all + // their reachable symbols and emit them as well. + let cstore = &scx.sess().cstore; + let formats = scx.sess().dependency_formats.borrow(); + let symbols = formats[&CrateTypeDylib].iter(); + let symbols = symbols.enumerate().filter_map(|(i, f)| { + if *f == Linkage::Static { + Some((i + 1) as ast::CrateNum) + } else { + None + } + }).flat_map(|cnum| { + cstore.reachable_ids(cnum) + }).map(|did| -> String { + Instance::mono(scx.tcx(), did).symbol_name(scx) + }); + for symbol in symbols { + writeln!(exports, " {}", symbol).unwrap(); + } + } + LinkerInfo::Msvc { + dylib_exports: exports + } + } else { + LinkerInfo::Gnu + } + } + + pub fn to_linker(&'a self, + cmd: &'a mut Command, + sess: &'a Session) -> Box { + match *self { + LinkerInfo::Gnu => { + Box::new(GnuLinker { + cmd: cmd, + sess: sess + }) as Box + } + LinkerInfo::Msvc { ref dylib_exports } => { + Box::new(MsvcLinker { + cmd: cmd, + sess: sess, + dylib_exports: dylib_exports + }) as Box + } + } + } +} /// Linker abstraction used by back::link to build up the command to invoke a /// linker. @@ -53,13 +125,12 @@ pub trait Linker { fn hint_dynamic(&mut self); fn whole_archives(&mut self); fn no_whole_archives(&mut self); - fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation, - tmpdir: &Path); + fn export_symbols(&mut self, tmpdir: &Path); } pub struct GnuLinker<'a> { - pub cmd: &'a mut Command, - pub sess: &'a Session, + cmd: &'a mut Command, + sess: &'a Session, } impl<'a> GnuLinker<'a> { @@ -198,14 +269,15 @@ impl<'a> Linker for GnuLinker<'a> { self.cmd.arg("-Wl,-Bdynamic"); } - fn export_symbols(&mut self, _: &Session, _: &CrateTranslation, _: &Path) { + fn export_symbols(&mut self, _: &Path) { // noop, visibility in object files takes care of this } } pub struct MsvcLinker<'a> { - pub cmd: &'a mut Command, - pub sess: &'a Session, + cmd: &'a mut Command, + sess: &'a Session, + dylib_exports: &'a str } impl<'a> Linker for MsvcLinker<'a> { @@ -322,8 +394,7 @@ impl<'a> Linker for MsvcLinker<'a> { // crates. Upstream rlibs may be linked statically to this dynamic library, // in which case they may continue to transitively be used and hence need // their symbols exported. - fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation, - tmpdir: &Path) { + fn export_symbols(&mut self, tmpdir: &Path) { let path = tmpdir.join("lib.def"); let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); @@ -332,37 +403,11 @@ impl<'a> Linker for MsvcLinker<'a> { // straight to exports. writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - - // Write out all our local symbols - for sym in trans.reachable.iter() { - writeln!(f, " {}", sym)?; - } - - // Take a look at how all upstream crates are linked into this - // dynamic library. For all statically linked libraries we take all - // their reachable symbols and emit them as well. - let cstore = &sess.cstore; - let formats = sess.dependency_formats.borrow(); - let symbols = formats[&CrateTypeDylib].iter(); - let symbols = symbols.enumerate().filter_map(|(i, f)| { - if *f == Linkage::Static { - Some((i + 1) as ast::CrateNum) - } else { - None - } - }).flat_map(|cnum| { - cstore.reachable_ids(cnum) - }).map(|did| { - cstore.item_symbol(did) - }); - for symbol in symbols { - writeln!(f, " {}", symbol)?; - } - + f.write(self.dylib_exports.as_bytes())?; Ok(()) })(); if let Err(e) = res { - sess.fatal(&format!("failed to write lib.def file: {}", e)); + self.sess.fatal(&format!("failed to write lib.def file: {}", e)); } let mut arg = OsString::from("/DEF:"); arg.push(path); diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 0cf82d66b2b68..49c7225306b25 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -97,17 +97,19 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -use common::{CrateContext, gensym_name}; +use common::{CrateContext, SharedCrateContext, gensym_name}; use monomorphize::Instance; use util::sha2::{Digest, Sha256}; -use rustc::middle::cstore; +use rustc::middle::{cstore, weak_lang_items}; use rustc::hir::def_id::DefId; +use rustc::hir::map as hir_map; use rustc::ty::{self, TyCtxt, TypeFoldable}; -use rustc::ty::item_path::{ItemPathBuffer, RootMode}; +use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::hir::map::definitions::{DefPath, DefPathData}; use std::fmt::Write; +use syntax::attr; use syntax::parse::token::{self, InternedString}; use serialize::hex::ToHex; @@ -116,7 +118,7 @@ pub fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> def_path_to_string(tcx, &def_path) } -pub fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefPath) -> String { +fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefPath) -> String { let mut s = String::with_capacity(def_path.data.len() * 16); s.push_str(&tcx.crate_name(def_path.krate)); @@ -134,7 +136,7 @@ pub fn def_path_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path: &DefP s } -fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, +fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // path to the item this name is for def_path: &DefPath, @@ -152,9 +154,9 @@ fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("get_symbol_hash(def_path={:?}, parameters={:?})", def_path, parameters); - let tcx = ccx.tcx(); + let tcx = scx.tcx(); - let mut hash_state = ccx.symbol_hasher().borrow_mut(); + let mut hash_state = scx.symbol_hasher().borrow_mut(); hash_state.reset(); @@ -187,66 +189,100 @@ fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: &Instance<'tcx>, - suffix: Option<&str>) - -> String { - let &Instance { def: mut def_id, ref substs } = instance; +impl<'a, 'tcx> Instance<'tcx> { + pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String { + let Instance { def: def_id, ref substs } = self; - debug!("exported_name_with_opt_suffix(def_id={:?}, substs={:?}, suffix={:?})", - def_id, substs, suffix); + debug!("symbol_name(def_id={:?}, substs={:?})", + def_id, substs); - if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) { - if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) { - def_id = src_def_id; + let node_id = scx.tcx().map.as_local_node_id(def_id); + + if let Some(id) = node_id { + if scx.sess().plugin_registrar_fn.get() == Some(id) { + let svh = &scx.link_meta().crate_hash; + let idx = def_id.index; + return scx.sess().generate_plugin_registrar_symbol(svh, idx); + } } - } - let def_path = ccx.tcx().def_path(def_id); - assert_eq!(def_path.krate, def_id.krate); - - // We want to compute the "type" of this item. Unfortunately, some - // kinds of items (e.g., closures) don't have an entry in the - // item-type array. So walk back up the find the closest parent - // that DOES have an entry. - let mut ty_def_id = def_id; - let instance_ty; - loop { - let key = ccx.tcx().def_key(ty_def_id); - match key.disambiguated_data.data { - DefPathData::TypeNs(_) | - DefPathData::ValueNs(_) => { - instance_ty = ccx.tcx().lookup_item_type(ty_def_id); - break; + // FIXME(eddyb) Precompute a custom symbol name based on attributes. + let attrs = scx.tcx().get_attrs(def_id); + let is_foreign = if let Some(id) = node_id { + match scx.tcx().map.get(id) { + hir_map::NodeForeignItem(_) => true, + _ => false } - _ => { - // if we're making a symbol for something, there ought - // to be a value or type-def or something in there - // *somewhere* - ty_def_id.index = key.parent.unwrap_or_else(|| { - bug!("finding type for {:?}, encountered def-id {:?} with no \ - parent", def_id, ty_def_id); - }); + } else { + scx.sess().cstore.is_foreign_item(def_id) + }; + + if let Some(name) = weak_lang_items::link_name(&attrs) { + return name.to_string(); + } + + if is_foreign { + if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") { + return name.to_string(); } + // Don't mangle foreign items. + return scx.tcx().item_name(def_id).as_str().to_string(); } - } - // Erase regions because they may not be deterministic when hashed - // and should not matter anyhow. - let instance_ty = ccx.tcx().erase_regions(&instance_ty.ty); + if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) { + // Use provided name + return name.to_string(); + } - let hash = get_symbol_hash(ccx, &def_path, instance_ty, substs.types.as_slice()); + if attr::contains_name(&attrs, "no_mangle") { + // Don't mangle + return scx.tcx().item_name(def_id).as_str().to_string(); + } - let mut buffer = SymbolPathBuffer { - names: Vec::with_capacity(def_path.data.len()) - }; - ccx.tcx().push_item_path(&mut buffer, def_id); + let def_path = scx.tcx().def_path(def_id); + + // We want to compute the "type" of this item. Unfortunately, some + // kinds of items (e.g., closures) don't have an entry in the + // item-type array. So walk back up the find the closest parent + // that DOES have an entry. + let mut ty_def_id = def_id; + let instance_ty; + loop { + let key = scx.tcx().def_key(ty_def_id); + match key.disambiguated_data.data { + DefPathData::TypeNs(_) | + DefPathData::ValueNs(_) => { + instance_ty = scx.tcx().lookup_item_type(ty_def_id); + break; + } + _ => { + // if we're making a symbol for something, there ought + // to be a value or type-def or something in there + // *somewhere* + ty_def_id.index = key.parent.unwrap_or_else(|| { + bug!("finding type for {:?}, encountered def-id {:?} with no \ + parent", def_id, ty_def_id); + }); + } + } + } - if let Some(suffix) = suffix { - buffer.push(suffix); - } + // Erase regions because they may not be deterministic when hashed + // and should not matter anyhow. + let instance_ty = scx.tcx().erase_regions(&instance_ty.ty); + + let hash = get_symbol_hash(scx, &def_path, instance_ty, substs.types.as_slice()); + + let mut buffer = SymbolPathBuffer { + names: Vec::with_capacity(def_path.data.len()) + }; - mangle(buffer.names.into_iter(), Some(&hash[..])) + item_path::with_forced_absolute_paths(|| { + scx.tcx().push_item_path(&mut buffer, def_id); + }); + + mangle(buffer.names.into_iter(), Some(&hash[..])) + } } struct SymbolPathBuffer { @@ -264,19 +300,6 @@ impl ItemPathBuffer for SymbolPathBuffer { } } -pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: &Instance<'tcx>) - -> String { - exported_name_with_opt_suffix(ccx, instance, None) -} - -pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: &Instance<'tcx>, - suffix: &str) - -> String { - exported_name_with_opt_suffix(ccx, instance, Some(suffix)) -} - /// Only symbols that are invisible outside their compilation unit should use a /// name generated by this function. pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, @@ -289,7 +312,7 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx> data: vec![], krate: cstore::LOCAL_CRATE, }; - let hash = get_symbol_hash(ccx, &def_path, t, &[]); + let hash = get_symbol_hash(ccx.shared(), &def_path, t, &[]); mangle(path.iter().cloned(), Some(&hash[..])) } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 7665b730caddf..2185ec9a7252c 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -30,14 +30,14 @@ pub use self::ValueOrigin::*; use super::CrateTranslation; use super::ModuleTranslation; -use back::{link, symbol_names}; +use back::link; +use back::linker::LinkerInfo; use lint; use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; use rustc::cfg; use rustc::hir::def_id::DefId; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; -use middle::weak_lang_items; use rustc::hir::pat_util::simple_name; use rustc::ty::subst::{self, Substs}; use rustc::traits; @@ -2336,15 +2336,6 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) { set_global_section(ccx, g, item); update_linkage(ccx, g, Some(item.id), OriginalTranslation); } - hir::ItemForeignMod(ref m) => { - if m.abi == Abi::RustIntrinsic || m.abi == Abi::PlatformIntrinsic { - return; - } - for fi in &m.items { - let lname = imported_name(fi.name, &fi.attrs).to_string(); - ccx.item_symbols().borrow_mut().insert(fi.id, lname); - } - } _ => {} } } @@ -2429,60 +2420,11 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { } } -pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>, - attrs: &[ast::Attribute]) - -> String { - let id = ccx.tcx().map.as_local_node_id(instance.def).unwrap(); - - match ccx.external_srcs().borrow().get(&id) { - Some(&did) => { - let sym = ccx.sess().cstore.item_symbol(did); - debug!("found item {} in other crate...", sym); - return sym; - } - None => {} - } - - match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) { - // Use provided name - Some(name) => name.to_string(), - _ => { - if attr::contains_name(attrs, "no_mangle") { - // Don't mangle - ccx.tcx().map.name(id).as_str().to_string() - } else { - match weak_lang_items::link_name(attrs) { - Some(name) => name.to_string(), - None => { - // Usual name mangling - symbol_names::exported_name(ccx, &instance) - } - } - } - } - } -} - -pub fn imported_name(name: ast::Name, attrs: &[ast::Attribute]) -> InternedString { - match attr::first_attr_value_str_by_name(attrs, "link_name") { - Some(ln) => ln.clone(), - None => match weak_lang_items::link_name(attrs) { - Some(name) => name, - None => name.as_str(), - } - } -} - fn contains_null(s: &str) -> bool { s.bytes().any(|b| b == 0) } -pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, - krate: &hir::Crate, - reachable: &NodeSet, - mir_map: &MirMap<'tcx>) - -> Vec { +pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>) -> Vec { use flate; let any_library = cx.sess() @@ -2497,11 +2439,10 @@ pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>, let cstore = &cx.tcx().sess.cstore; let metadata = cstore.encode_metadata(cx.tcx(), cx.export_map(), - cx.item_symbols(), cx.link_meta(), - reachable, - mir_map, - krate); + cx.reachable(), + cx.mir_map(), + cx.tcx().map.krate()); let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); @@ -2664,10 +2605,7 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter { /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. pub fn filter_reachable_ids(scx: &SharedCrateContext) -> NodeSet { - scx.reachable().iter().map(|x| *x).filter(|id| { - // First, only worry about nodes which have a symbol name - scx.item_symbols().borrow().contains_key(id) - }).filter(|&id| { + scx.reachable().iter().map(|x| *x).filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two // categories: @@ -2685,7 +2623,18 @@ pub fn filter_reachable_ids(scx: &SharedCrateContext) -> NodeSet { hir_map::NodeForeignItem(..) => { scx.sess().cstore.is_statically_included_foreign_item(id) } - _ => true, + + // Only consider nodes that actually have exported symbols. + hir_map::NodeItem(&hir::Item { + node: hir::ItemStatic(..), .. }) | + hir_map::NodeItem(&hir::Item { + node: hir::ItemFn(..), .. }) | + hir_map::NodeTraitItem(&hir::TraitItem { + node: hir::MethodTraitItem(_, Some(_)), .. }) | + hir_map::NodeImplItem(&hir::ImplItem { + node: hir::ImplItemKind::Method(..), .. }) => true, + + _ => false } }).collect() } @@ -2726,6 +2675,16 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable, check_overflow, check_dropflag); + // Translate the metadata. + let metadata = time(tcx.sess.time_passes(), "write metadata", || { + write_metadata(&shared_ccx) + }); + + let metadata_module = ModuleTranslation { + llcx: shared_ccx.metadata_llcx(), + llmod: shared_ccx.metadata_llmod(), + }; + let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); let codegen_units = collect_and_partition_translation_items(&shared_ccx); let codegen_unit_count = codegen_units.len(); @@ -2734,6 +2693,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let crate_context_list = CrateContextList::new(&shared_ccx, codegen_units); + let modules = crate_context_list.iter() + .map(|ccx| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() }) + .collect(); + + // Skip crate items and just output metadata in -Z no-trans mode. + if tcx.sess.opts.no_trans { + let linker_info = LinkerInfo::new(&shared_ccx, &[]); + return CrateTranslation { + modules: modules, + metadata_module: metadata_module, + link: link_meta, + metadata: metadata, + reachable: vec![], + no_builtins: no_builtins, + linker_info: linker_info + }; + } + { let ccx = crate_context_list.get_ccx(0); @@ -2765,10 +2742,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let reachable_symbol_ids = filter_reachable_ids(&shared_ccx); - // Translate the metadata. - let metadata = time(tcx.sess.time_passes(), "write metadata", || { - write_metadata(&shared_ccx, krate, &reachable_symbol_ids, mir_map) - }); if shared_ccx.sess().trans_stats() { let stats = shared_ccx.stats(); @@ -2799,13 +2772,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let modules = crate_context_list.iter() - .map(|ccx| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() }) - .collect(); - let sess = shared_ccx.sess(); - let mut reachable_symbols = reachable_symbol_ids.iter().map(|id| { - shared_ccx.item_symbols().borrow()[id].to_string() + let mut reachable_symbols = reachable_symbol_ids.iter().map(|&id| { + let def_id = shared_ccx.tcx().map.local_def_id(id); + Instance::mono(shared_ccx.tcx(), def_id).symbol_name(&shared_ccx) }).collect::>(); if sess.entry_fn.borrow().is_some() { reachable_symbols.push("main".to_string()); @@ -2820,7 +2790,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable_symbols.extend(syms.into_iter().filter(|did| { sess.cstore.is_extern_item(shared_ccx.tcx(), *did) }).map(|did| { - sess.cstore.item_symbol(did) + Instance::mono(shared_ccx.tcx(), did).symbol_name(&shared_ccx) })); } } @@ -2835,12 +2805,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, create_imps(&crate_context_list); } - let metadata_module = ModuleTranslation { - llcx: shared_ccx.metadata_llcx(), - llmod: shared_ccx.metadata_llmod(), - }; - let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); - + let linker_info = LinkerInfo::new(&shared_ccx, &reachable_symbols); CrateTranslation { modules: modules, metadata_module: metadata_module, @@ -2848,6 +2813,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, metadata: metadata, reachable: reachable_symbols, no_builtins: no_builtins, + linker_info: linker_info } } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 3fb8605412075..5d28c53f31660 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -188,9 +188,9 @@ impl<'tcx> Callee<'tcx> { }; Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty)) } - traits::VtableFnPointer(fn_ty) => { + traits::VtableFnPointer(vtable_fn_pointer) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); - let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty); + let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty); let method_ty = def_ty(tcx, def_id, substs); let fn_ptr_ty = match method_ty.sty { @@ -499,43 +499,20 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return immediate_rvalue(llfn, fn_ptr_ty); } - let attrs; let local_id = ccx.tcx().map.as_local_node_id(def_id); - let maybe_node = local_id.and_then(|id| tcx.map.find(id)); - let (sym, attrs, local_item) = match maybe_node { + let local_item = match local_id.and_then(|id| tcx.map.find(id)) { Some(hir_map::NodeItem(&hir::Item { - ref attrs, id, span, node: hir::ItemFn(..), .. + span, node: hir::ItemFn(..), .. })) | Some(hir_map::NodeTraitItem(&hir::TraitItem { - ref attrs, id, span, node: hir::MethodTraitItem(_, Some(_)), .. + span, node: hir::MethodTraitItem(_, Some(_)), .. })) | Some(hir_map::NodeImplItem(&hir::ImplItem { - ref attrs, id, span, node: hir::ImplItemKind::Method(..), .. + span, node: hir::ImplItemKind::Method(..), .. })) => { - let sym = exported_name(ccx, instance, attrs); - - if declare::get_defined_value(ccx, &sym).is_some() { - ccx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", sym)); - } - - (sym, &attrs[..], Some(id)) - } - - Some(hir_map::NodeForeignItem(&hir::ForeignItem { - ref attrs, name, node: hir::ForeignItemFn(..), .. - })) => { - (imported_name(name, attrs).to_string(), &attrs[..], None) - } - - None => { - attrs = ccx.sess().cstore.item_attrs(def_id); - (ccx.sess().cstore.item_symbol(def_id), &attrs[..], None) - } - - ref variant => { - bug!("get_fn: unexpected variant: {:?}", variant) + Some(span) } + _ => None }; // This is subtle and surprising, but sometimes we have to bitcast @@ -562,8 +539,16 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. + let sym = instance.symbol_name(ccx.shared()); let llptrty = type_of::type_of(ccx, fn_ptr_ty); let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) { + if let Some(span) = local_item { + if declare::get_defined_value(ccx, &sym).is_some() { + ccx.sess().span_fatal(span, + &format!("symbol `{}` is already defined", sym)); + } + } + if common::val_ty(llfn) != llptrty { if local_item.is_some() { bug!("symbol `{}` previously declared as {:?}, now wanted as {:?}", @@ -580,7 +565,8 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert_eq!(common::val_ty(llfn), llptrty); debug!("get_fn: not casting pointer!"); - attributes::from_fn_attrs(ccx, attrs, llfn); + let attrs = ccx.tcx().get_attrs(def_id); + attributes::from_fn_attrs(ccx, &attrs, llfn); if local_item.is_some() { // FIXME(eddyb) Doubt all extern fn should allow unwinding. attributes::unwind(llfn, true); @@ -589,11 +575,6 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn }; - // Always insert into item_symbols, in case this item is exported. - if let Some(id) = local_item { - ccx.item_symbols().borrow_mut().insert(id, sym); - } - ccx.instances().borrow_mut().insert(instance, llfn); immediate_rvalue(llfn, fn_ptr_ty) diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index 1c393f8091eee..5e0d34c2a674d 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -150,7 +150,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return llfn; } - let symbol = symbol_names::exported_name(ccx, &instance); + let symbol = instance.symbol_name(ccx.shared()); // Compute the rust-call form of the closure call method. let sig = &tcx.closure_type(closure_id, substs).sig; diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 7775ed3fc68ae..f93edeb511a99 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -19,7 +19,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::map as hir_map; use {abi, adt, closure, debuginfo, expr, machine}; -use base::{self, exported_name, imported_name, push_ctxt}; +use base::{self, push_ctxt}; use callee::Callee; use collector::{self, TransItem}; use common::{type_is_sized, C_nil, const_get_elt}; @@ -1016,34 +1016,31 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) return Datum::new(g, ty, Lvalue::new("static")); } + let sym = instance.symbol_name(ccx.shared()); + let g = if let Some(id) = ccx.tcx().map.as_local_node_id(def_id) { let llty = type_of::type_of(ccx, ty); match ccx.tcx().map.get(id) { hir_map::NodeItem(&hir::Item { - ref attrs, span, node: hir::ItemStatic(..), .. + span, node: hir::ItemStatic(..), .. }) => { // If this static came from an external crate, then // we need to get the symbol from metadata instead of // using the current crate's name/version // information in the hash of the symbol - let sym = exported_name(ccx, instance, attrs); debug!("making {}", sym); // Create the global before evaluating the initializer; // this is necessary to allow recursive statics. - let g = declare::define_global(ccx, &sym, llty).unwrap_or_else(|| { + declare::define_global(ccx, &sym, llty).unwrap_or_else(|| { ccx.sess().span_fatal(span, &format!("symbol `{}` is already defined", sym)) - }); - - ccx.item_symbols().borrow_mut().insert(id, sym); - g + }) } hir_map::NodeForeignItem(&hir::ForeignItem { - ref attrs, name, span, node: hir::ForeignItemStatic(..), .. + ref attrs, span, node: hir::ForeignItemStatic(..), .. }) => { - let ident = imported_name(name, attrs); let g = if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "linkage") { // If this is a static with a linkage specified, then we need to handle @@ -1065,7 +1062,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) }; unsafe { // Declare a symbol `foo` with the desired linkage. - let g1 = declare::declare_global(ccx, &ident, llty2); + let g1 = declare::declare_global(ccx, &sym, llty2); llvm::SetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which @@ -1075,10 +1072,10 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) // `extern_with_linkage_foo` will instead be initialized to // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); - real_name.push_str(&ident); + real_name.push_str(&sym); let g2 = declare::define_global(ccx, &real_name, llty).unwrap_or_else(||{ ccx.sess().span_fatal(span, - &format!("symbol `{}` is already defined", ident)) + &format!("symbol `{}` is already defined", sym)) }); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); @@ -1086,7 +1083,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) } } else { // Generate an external declaration. - declare::declare_global(ccx, &ident, llty) + declare::declare_global(ccx, &sym, llty) }; for attr in attrs { @@ -1103,8 +1100,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) } else { // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? // FIXME(nagisa): investigate whether it can be changed into define_global - let name = ccx.sess().cstore.item_symbol(def_id); - let g = declare::declare_global(ccx, &name, type_of::type_of(ccx, ty)); + let g = declare::declare_global(ccx, &sym, type_of::type_of(ccx, ty)); // 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 diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 61137d7f377c2..40018840a8b83 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -70,7 +70,6 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { export_map: ExportMap, reachable: NodeSet, - item_symbols: RefCell>, link_meta: LinkMeta, symbol_hasher: RefCell, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -394,7 +393,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { metadata_llcx: metadata_llcx, export_map: export_map, reachable: reachable, - item_symbols: RefCell::new(NodeMap()), link_meta: link_meta, symbol_hasher: RefCell::new(symbol_hasher), tcx: tcx, @@ -438,10 +436,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.reachable } - pub fn item_symbols<'a>(&'a self) -> &'a RefCell> { - &self.item_symbols - } - pub fn trait_cache(&self) -> &RefCell>> { &self.trait_cache } @@ -487,6 +481,14 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn translation_items(&self) -> &RefCell, TransItemState>> { &self.translation_items } + + pub fn symbol_hasher(&self) -> &RefCell { + &self.symbol_hasher + } + + pub fn mir_map(&self) -> &MirMap<'tcx> { + &self.mir_map + } } impl<'tcx> LocalCrateContext<'tcx> { @@ -694,10 +696,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.shared.reachable } - pub fn item_symbols<'a>(&'a self) -> &'a RefCell> { - &self.shared.item_symbols - } - pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { &self.shared.link_meta } diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs index b87456318cd16..186781547f98c 100644 --- a/src/librustc_trans/expr.rs +++ b/src/librustc_trans/expr.rs @@ -63,7 +63,6 @@ use cleanup::{self, CleanupMethods, DropHintMethods}; use common::*; use datum::*; use debuginfo::{self, DebugLoc, ToDebugLoc}; -use declare; use glue; use machine; use tvec; @@ -1593,7 +1592,6 @@ fn trans_scalar_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, { let _icx = push_ctxt("trans_scalar_binop"); - let tcx = bcx.tcx(); let lhs_t = lhs.ty; assert!(!lhs_t.is_simd()); let is_float = lhs_t.is_fp(); @@ -1656,42 +1654,7 @@ fn trans_scalar_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } hir::BiRem => { if is_float { - // LLVM currently always lowers the `frem` instructions appropriate - // library calls typically found in libm. Notably f64 gets wired up - // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for - // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's - // instead just an inline function in a header that goes up to a - // f64, uses `fmod`, and then comes back down to a f32. - // - // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will - // still unconditionally lower frem instructions over 32-bit floats - // to a call to `fmodf`. To work around this we special case MSVC - // 32-bit float rem instructions and instead do the call out to - // `fmod` ourselves. - // - // Note that this is currently duplicated with src/libcore/ops.rs - // which does the same thing, and it would be nice to perhaps unify - // these two implementations on day! Also note that we call `fmod` - // for both 32 and 64-bit floats because if we emit any FRem - // instruction at all then LLVM is capable of optimizing it into a - // 32-bit FRem (which we're trying to avoid). - let use_fmod = tcx.sess.target.target.options.is_like_msvc && - tcx.sess.target.target.arch == "x86"; - if use_fmod { - let f64t = Type::f64(bcx.ccx()); - let fty = Type::func(&[f64t, f64t], &f64t); - let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty); - if lhs_t == tcx.types.f32 { - let lhs = FPExt(bcx, lhs, f64t); - let rhs = FPExt(bcx, rhs, f64t); - let res = Call(bcx, llfn, &[lhs, rhs], binop_debug_loc); - FPTrunc(bcx, res, Type::f32(bcx.ccx())) - } else { - Call(bcx, llfn, &[lhs, rhs], binop_debug_loc) - } - } else { - FRem(bcx, lhs, rhs, binop_debug_loc) - } + FRem(bcx, lhs, rhs, binop_debug_loc) } else { // Only zero-check integers; fp %0 is NaN bcx = base::fail_if_zero_or_overflows(bcx, diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index f48409ec75573..78318aa023c3f 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -144,6 +144,7 @@ pub struct CrateTranslation { pub metadata: Vec, pub reachable: Vec, pub no_builtins: bool, + pub linker_info: back::linker::LinkerInfo } __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 9b279a397f864..64ee18fccef37 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -176,7 +176,10 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trait_closure_kind); vec![llfn].into_iter() } - traits::VtableFnPointer(bare_fn_ty) => { + traits::VtableFnPointer( + traits::VtableFnPointerData { + fn_ty: bare_fn_ty, + nested: _ }) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter() } diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index e1318396e317d..4e3386bc73677 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -24,6 +24,7 @@ use meth; use type_of; use glue; use type_::Type; +use rustc_data_structures::fnv::FnvHashMap; use super::{MirContext, TempRef, drop}; use super::constant::Const; @@ -95,17 +96,32 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { adt::trans_get_discr(bcx, &repr, discr_lvalue.llval, None, true) ); - // The else branch of the Switch can't be hit, so branch to an unreachable - // instruction so LLVM knows that - let unreachable_blk = self.unreachable_block(); - let switch = bcx.switch(discr, unreachable_blk.llbb, targets.len()); + let mut bb_hist = FnvHashMap(); + for target in targets { + *bb_hist.entry(target).or_insert(0) += 1; + } + let (default_bb, default_blk) = match bb_hist.iter().max_by_key(|&(_, c)| c) { + // If a single target basic blocks is predominant, promote that to be the + // default case for the switch instruction to reduce the size of the generated + // code. This is especially helpful in cases like an if-let on a huge enum. + // Note: This optimization is only valid for exhaustive matches. + Some((&&bb, &c)) if c > targets.len() / 2 => { + (Some(bb), self.blocks[bb.index()]) + } + // We're generating an exhaustive switch, so the else branch + // can't be hit. Branching to an unreachable instruction + // lets LLVM know this + _ => (None, self.unreachable_block()) + }; + let switch = bcx.switch(discr, default_blk.llbb, targets.len()); assert_eq!(adt_def.variants.len(), targets.len()); - for (adt_variant, target) in adt_def.variants.iter().zip(targets) { - let llval = bcx.with_block(|bcx| - adt::trans_case(bcx, &repr, Disr::from(adt_variant.disr_val)) - ); - let llbb = self.llblock(*target); - build::AddCase(switch, llval, llbb) + for (adt_variant, &target) in adt_def.variants.iter().zip(targets) { + if default_bb != Some(target) { + let llbb = self.llblock(target); + let llval = bcx.with_block(|bcx| adt::trans_case( + bcx, &repr, Disr::from(adt_variant.disr_val))); + build::AddCase(switch, llval, llbb) + } } } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 3fb22c6bd55da..bcbf3e1fa1836 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -19,10 +19,8 @@ use callee::Callee; use common::{self, C_uint, BlockAndBuilder, Result}; use datum::{Datum, Lvalue}; use debuginfo::DebugLoc; -use declare; use adt; use machine; -use type_::Type; use type_of; use tvec; use value::Value; @@ -531,43 +529,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { bcx.udiv(lhs, rhs) }, mir::BinOp::Rem => if is_float { - // LLVM currently always lowers the `frem` instructions appropriate - // library calls typically found in libm. Notably f64 gets wired up - // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for - // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's - // instead just an inline function in a header that goes up to a - // f64, uses `fmod`, and then comes back down to a f32. - // - // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will - // still unconditionally lower frem instructions over 32-bit floats - // to a call to `fmodf`. To work around this we special case MSVC - // 32-bit float rem instructions and instead do the call out to - // `fmod` ourselves. - // - // Note that this is currently duplicated with src/libcore/ops.rs - // which does the same thing, and it would be nice to perhaps unify - // these two implementations one day! Also note that we call `fmod` - // for both 32 and 64-bit floats because if we emit any FRem - // instruction at all then LLVM is capable of optimizing it into a - // 32-bit FRem (which we're trying to avoid). - let tcx = bcx.tcx(); - let use_fmod = tcx.sess.target.target.options.is_like_msvc && - tcx.sess.target.target.arch == "x86"; - if use_fmod { - let f64t = Type::f64(bcx.ccx()); - let fty = Type::func(&[f64t, f64t], &f64t); - let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty); - if input_ty == tcx.types.f32 { - let lllhs = bcx.fpext(lhs, f64t); - let llrhs = bcx.fpext(rhs, f64t); - let llres = bcx.call(llfn, &[lllhs, llrhs], None); - bcx.fptrunc(llres, Type::f32(bcx.ccx())) - } else { - bcx.call(llfn, &[lhs, rhs], None) - } - } else { - bcx.frem(lhs, rhs) - } + bcx.frem(lhs, rhs) } else if is_signed { bcx.srem(lhs, rhs) } else { diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 8b1809e40233a..6dc93c787330f 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use back::symbol_names; use llvm::ValueRef; use llvm; use rustc::hir::def_id::DefId; @@ -88,7 +87,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, monomorphizing.insert(fn_id, depth + 1); } - let symbol = symbol_names::exported_name(ccx, &instance); + let symbol = instance.symbol_name(ccx.shared()); debug!("monomorphize_fn mangled to {}", symbol); assert!(declare::get_defined_value(ccx, &symbol).is_none()); diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 2e3355968dffa..b84394e474ec3 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -14,7 +14,6 @@ //! item-path. This is used for unit testing the code that generates //! paths etc in all kinds of annoying scenarios. -use back::symbol_names; use rustc::hir; use rustc::hir::intravisit::{self, Visitor}; use syntax::ast; @@ -52,8 +51,7 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { for attr in tcx.get_attrs(def_id).iter() { if attr.check_name(SYMBOL_NAME) { // for now, can only use on monomorphic names - let instance = Instance::mono(tcx, def_id); - let name = symbol_names::exported_name(self.ccx, &instance); + let name = Instance::mono(tcx, def_id).symbol_name(self.ccx.shared()); tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); } else if attr.check_name(ITEM_PATH) { let path = tcx.item_path_str(def_id); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 725d40889ceec..c8e247fb9181c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -64,10 +64,10 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope, ElisionFailureInfo, ElidedLifetime}; use util::common::{ErrorReported, FN_OUTPUT_NAME}; -use util::nodemap::FnvHashSet; +use util::nodemap::{NodeMap, FnvHashSet}; use rustc_const_math::ConstInt; - +use std::cell::RefCell; use syntax::{abi, ast}; use syntax::codemap::{Span, Pos}; use syntax::errors::DiagnosticBuilder; @@ -81,6 +81,9 @@ use rustc_back::slice; pub trait AstConv<'gcx, 'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>; + /// A cache used for the result of `ast_ty_to_ty_cache` + fn ast_ty_to_ty_cache(&self) -> &RefCell>>; + /// Identify the type scheme for an item with a type, like a type /// alias, fn, or struct. This allows you to figure out the set of /// type parameters defined on the item. @@ -1416,13 +1419,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { rscope: &RegionScope, span: Span, param_mode: PathParamMode, - def: &Def, + def: Def, opt_self_ty: Option>, base_segments: &[hir::PathSegment]) -> Ty<'tcx> { let tcx = self.tcx(); - match *def { + debug!("base_def_to_ty(def={:?}, opt_self_ty={:?}, base_segments={:?})", + def, opt_self_ty, base_segments); + + match def { Def::Trait(trait_def_id) => { // N.B. this case overlaps somewhat with // TyObjectSum, see that fn for details @@ -1515,20 +1521,27 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { rscope: &RegionScope, span: Span, param_mode: PathParamMode, - def: &Def, + mut def: Def, opt_self_ty: Option>, base_segments: &[hir::PathSegment], assoc_segments: &[hir::PathSegment]) - -> Ty<'tcx> { + -> (Ty<'tcx>, Def) { + debug!("finish_resolving_def_to_ty(def={:?}, \ + base_segments={:?}, \ + assoc_segments={:?})", + def, + base_segments, + assoc_segments); let mut ty = self.base_def_to_ty(rscope, span, param_mode, def, opt_self_ty, base_segments); - let mut def = *def; + debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty); // If any associated type segments remain, attempt to resolve them. for segment in assoc_segments { + debug!("finish_resolving_def_to_ty: segment={:?}", segment); if ty.sty == ty::TyError { break; } @@ -1540,7 +1553,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty = a_ty; def = a_def; } - ty + (ty, def) } /// Parses the programmer's textual representation of a type into our @@ -1551,7 +1564,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let tcx = self.tcx(); - match ast_ty.node { + let cache = self.ast_ty_to_ty_cache(); + match cache.borrow().get(&ast_ty.id) { + Some(ty) => { return ty; } + None => { } + } + + let result_ty = match ast_ty.node { hir::TyVec(ref ty) => { tcx.mk_slice(self.ast_ty_to_ty(rscope, &ty)) } @@ -1599,6 +1618,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds) } hir::TyPath(ref maybe_qself, ref path) => { + debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path); let path_res = if let Some(&d) = tcx.def_map.borrow().get(&ast_ty.id) { d } else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself { @@ -1615,13 +1635,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let opt_self_ty = maybe_qself.as_ref().map(|qself| { self.ast_ty_to_ty(rscope, &qself.ty) }); - let ty = self.finish_resolving_def_to_ty(rscope, - ast_ty.span, - PathParamMode::Explicit, - &def, - opt_self_ty, - &path.segments[..base_ty_end], - &path.segments[base_ty_end..]); + let (ty, _def) = self.finish_resolving_def_to_ty(rscope, + ast_ty.span, + PathParamMode::Explicit, + def, + opt_self_ty, + &path.segments[..base_ty_end], + &path.segments[base_ty_end..]); if path_res.depth != 0 && ty.sty != ty::TyError { // Write back the new resolution. @@ -1675,7 +1695,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // handled specially and will not descend into this routine. self.ty_infer(None, None, None, ast_ty.span) } - } + }; + + cache.borrow_mut().insert(ast_ty.id, result_ty); + + result_ty } pub fn ty_of_arg(&self, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index f27ae181f77e3..00eeefa0449ce 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -84,7 +84,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, method_name: ast::Name, self_ty: ty::Ty<'tcx>, - call_expr_id: ast::NodeId) + call_expr_id: ast::NodeId, + allow_private: bool) -> bool { let mode = probe::Mode::MethodCall; @@ -93,7 +94,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Err(NoMatch(..)) => false, Err(Ambiguity(..)) => true, Err(ClosureAmbiguity(..)) => true, - Err(PrivateMatch(..)) => true, + Err(PrivateMatch(..)) => allow_private, } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f428023da9b82..ed2edc30c9d31 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -346,6 +346,8 @@ impl UnsafetyState { #[derive(Clone)] pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + ast_ty_to_ty_cache: RefCell>>, + body_id: ast::NodeId, // This flag is set to true if, during the writeback phase, we encounter @@ -1151,7 +1153,8 @@ fn check_const<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, sp: Span, e: &'tcx hir::Expr, id: ast::NodeId) { - ccx.inherited(None).enter(|inh| { + let param_env = ParameterEnvironment::for_item(ccx.tcx, id); + ccx.inherited(Some(param_env)).enter(|inh| { let rty = ccx.tcx.node_id_to_type(id); let fcx = FnCtxt::new(&inh, ty::FnConverging(rty), e.id); let declty = fcx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty; @@ -1262,6 +1265,10 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } + fn ast_ty_to_ty_cache(&self) -> &RefCell>> { + &self.ast_ty_to_ty_cache + } + fn get_item_type_scheme(&self, _: Span, id: DefId) -> Result, ErrorReported> { @@ -1434,6 +1441,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { body_id: ast::NodeId) -> FnCtxt<'a, 'gcx, 'tcx> { FnCtxt { + ast_ty_to_ty_cache: RefCell::new(NodeMap()), body_id: body_id, writeback_errors: Cell::new(false), err_count_on_creation: inh.tcx.sess.err_count(), @@ -3045,12 +3053,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some((did, field_ty)) = private_candidate { let struct_path = self.tcx().item_path_str(did); - let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); - self.tcx().sess.span_err(expr.span, &msg); self.write_ty(expr.id, field_ty); + let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path); + let mut err = self.tcx().sess.struct_span_err(expr.span, &msg); + // Also check if an accessible method exists, which is often what is meant. + if self.method_exists(field.span, field.node, expr_t, expr.id, false) { + err.note(&format!("a method `{}` also exists, perhaps you wish to call it", + field.node)); + } + err.emit(); } else if field.node == keywords::Invalid.name() { self.write_error(expr.id); - } else if self.method_exists(field.span, field.node, expr_t, expr.id) { + } else if self.method_exists(field.span, field.node, expr_t, expr.id, true) { self.type_error_struct(field.span, |actual| { format!("attempted to take value of method `{}` on type \ `{}`", field.node, actual) @@ -3299,7 +3313,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr_ty = self.instantiate_type(def.def_id(), path); self.write_ty(expr.id, expr_ty); - self.check_expr_struct_fields(expr_ty, expr.span, variant, fields, + self.check_expr_struct_fields(expr_ty, path.span, variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { self.check_expr_has_type(base_expr, expr_ty); @@ -3845,15 +3859,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if path_res.depth == 0 { Some((opt_self_ty, &path.segments, path_res.base_def)) } else { - let mut def = path_res.base_def; + let def = path_res.base_def; let ty_segments = path.segments.split_last().unwrap().1; let base_ty_end = path.segments.len() - path_res.depth; - let ty = AstConv::finish_resolving_def_to_ty(self, self, span, - PathParamMode::Optional, - &mut def, - opt_self_ty, - &ty_segments[..base_ty_end], - &ty_segments[base_ty_end..]); + let (ty, _def) = AstConv::finish_resolving_def_to_ty(self, self, span, + PathParamMode::Optional, + def, + opt_self_ty, + &ty_segments[..base_ty_end], + &ty_segments[base_ty_end..]); let item_segment = path.segments.last().unwrap(); let item_name = item_segment.identifier.name; let def = match self.resolve_ufcs(span, item_name, ty, node_id) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 797a1509ebee5..f9a22e2a577b4 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -78,11 +78,12 @@ use rscope::*; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use util::common::{ErrorReported, MemoizationMap}; -use util::nodemap::FnvHashMap; +use util::nodemap::{NodeMap, FnvHashMap}; use {CrateCtxt, write_ty_to_tcx}; use rustc_const_math::ConstInt; +use std::cell::RefCell; use std::collections::HashSet; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::rc::Rc; @@ -146,7 +147,10 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> impl<'a,'tcx> CrateCtxt<'a,'tcx> { fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,'tcx> { - ItemCtxt { ccx: self, param_bounds: param_bounds } + ItemCtxt { + ccx: self, + param_bounds: param_bounds, + } } fn cycle_check(&self, @@ -298,6 +302,10 @@ impl<'a,'tcx> ItemCtxt<'a,'tcx> { impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.ccx.tcx } + fn ast_ty_to_ty_cache(&self) -> &RefCell>> { + &self.ccx.ast_ty_to_ty_cache + } + fn get_item_type_scheme(&self, span: Span, id: DefId) -> Result, ErrorReported> { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index b88b3c9802d30..f41da95c13537 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -116,6 +116,7 @@ use syntax::ast; use syntax::abi::Abi; use std::cell::RefCell; +use util::nodemap::NodeMap; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -136,7 +137,9 @@ pub struct TypeAndSubsts<'tcx> { } pub struct CrateCtxt<'a, 'tcx: 'a> { - // A mapping from method call sites to traits that have that method. + ast_ty_to_ty_cache: RefCell>>, + + /// A mapping from method call sites to traits that have that method. pub trait_map: hir::TraitMap, /// A vector of every trait accessible in the whole crate @@ -334,6 +337,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> CompileResult { let time_passes = tcx.sess.time_passes(); let ccx = CrateCtxt { + ast_ty_to_ty_cache: RefCell::new(NodeMap()), trait_map: trait_map, all_traits: RefCell::new(None), stack: RefCell::new(Vec::new()), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a89609fad6b6e..7305b0f1fb8bc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1534,13 +1534,6 @@ impl Type { } } - pub fn trait_name(&self) -> Option { - match *self { - ResolvedPath { ref path, .. } => Some(path.last_name()), - _ => None, - } - } - pub fn is_generic(&self) -> bool { match *self { ResolvedPath { is_generic, .. } => is_generic, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 895c0bb849010..6d45980b45da9 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -21,7 +21,7 @@ use rustc::lint; use rustc_trans::back::link; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; -use rustc_metadata::creader::LocalCrateReader; +use rustc_metadata::creader::read_local_crates; use syntax::{ast, codemap, errors}; use syntax::errors::emitter::ColorConfig; @@ -153,13 +153,13 @@ pub fn run_core(search_paths: SearchPaths, let krate = driver::assign_node_ids(&sess, krate); let dep_graph = DepGraph::new(false); - let defs = &RefCell::new(hir_map::collect_definitions(&krate)); - LocalCrateReader::new(&sess, &cstore, &defs, &krate, &name).read_crates(&dep_graph); + let mut defs = hir_map::collect_definitions(&krate); + read_local_crates(&sess, &cstore, &defs, &krate, &name, &dep_graph); // Lower ast -> hir and resolve. let (analysis, resolutions, mut hir_forest) = { - let defs = &mut *defs.borrow_mut(); - driver::lower_and_resolve(&sess, &name, defs, &krate, dep_graph, resolve::MakeGlobMap::No) + driver::lower_and_resolve(&sess, &name, &mut defs, &krate, dep_graph, + resolve::MakeGlobMap::No) }; let arenas = ty::CtxtArenas::new(); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 7af5322e7bdf1..4514106cece25 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -587,7 +587,13 @@ fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::R if link_trait { write!(f, "{}", *ty)?; } else { - write!(f, "{}", ty.trait_name().unwrap())?; + match *ty { + clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => { + let last = path.segments.last().unwrap(); + write!(f, "{}{}", last.name, last.params)?; + } + _ => unreachable!(), + } } write!(f, " for ")?; } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 3e1f3a414ffc3..e4fbdba77a445 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -28,7 +28,7 @@ use rustc::hir::map as hir_map; use rustc::session::{self, config}; use rustc::session::config::{get_unstable_features_setting, OutputType}; use rustc::session::search_paths::{SearchPaths, PathKind}; -use rustc::hir::lowering::{lower_crate, LoweringContext, DummyResolver}; +use rustc::hir::lowering::{lower_crate, DummyResolver}; use rustc_back::dynamic_lib::DynamicLibrary; use rustc_back::tempdir::TempDir; use rustc_driver::{driver, Compilation}; @@ -95,11 +95,10 @@ pub fn run(input: &str, .expect("phase_2_configure_and_expand aborted in rustdoc!"); let krate = driver::assign_node_ids(&sess, krate); let dep_graph = DepGraph::new(false); - let defs = &RefCell::new(hir_map::collect_definitions(&krate)); + let defs = hir_map::collect_definitions(&krate); let mut dummy_resolver = DummyResolver; - let lcx = LoweringContext::new(&sess, Some(&krate), &mut dummy_resolver); - let krate = lower_crate(&lcx, &krate); + let krate = lower_crate(&krate, &sess, &mut dummy_resolver); let opts = scrape_test_config(&krate); diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 9dc6a26cdeed3..6956dc0d901a4 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -452,16 +452,16 @@ pub fn home_dir() -> Option { /// Returns the path of a temporary directory. /// -/// On Unix, returns the value of the 'TMPDIR' environment variable if it is -/// set, otherwise for non-Android it returns '/tmp'. If Android, since there -/// is no global temporary folder (it is usually allocated per-app), we return -/// '/data/local/tmp'. -/// -/// On Windows, returns the value of, in order, the 'TMP', 'TEMP', -/// 'USERPROFILE' environment variable if any are set and not the empty -/// string. Otherwise, tmpdir returns the path of the Windows directory. This -/// behavior is identical to that of [GetTempPath][msdn], which this function -/// uses internally. +/// On Unix, returns the value of the `TMPDIR` environment variable if it is +/// set, otherwise for non-Android it returns `/tmp`. If Android, since there +/// is no global temporary folder (it is usually allocated per-app), it returns +/// `/data/local/tmp`. +/// +/// On Windows, returns the value of, in order, the `TMP`, `TEMP`, +/// `USERPROFILE` environment variable if any are set and not the empty +/// string. Otherwise, `temp_dir` returns the path of the Windows directory. +/// This behavior is identical to that of [`GetTempPath`][msdn], which this +/// function uses internally. /// /// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx /// diff --git a/src/libstd/sync/mod.rs b/src/libstd/sync/mod.rs index c20b422d40cf5..21008ee3989a7 100644 --- a/src/libstd/sync/mod.rs +++ b/src/libstd/sync/mod.rs @@ -31,7 +31,7 @@ pub use self::mutex::MUTEX_INIT; #[stable(feature = "rust1", since = "1.0.0")] pub use self::mutex::{Mutex, MutexGuard, StaticMutex}; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::once::{Once, ONCE_INIT}; +pub use self::once::{Once, OnceState, ONCE_INIT}; #[stable(feature = "rust1", since = "1.0.0")] pub use sys_common::poison::{PoisonError, TryLockError, TryLockResult, LockResult}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index e228d236a3ca7..d8a4a69c73cd3 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -218,7 +218,6 @@ impl Once { /// The closure `f` is yielded a structure which can be used to query the /// state of this `Once` (whether initialization has previously panicked or /// not). - /// poisoned or not. #[unstable(feature = "once_poison", issue = "31688")] pub fn call_once_force(&'static self, f: F) where F: FnOnce(&OnceState) { // same as above, just with a different parameter to `call_inner`. diff --git a/src/libstd/sys/common/gnu/libbacktrace.rs b/src/libstd/sys/common/gnu/libbacktrace.rs index db719ccce61e8..b5802afc10943 100644 --- a/src/libstd/sys/common/gnu/libbacktrace.rs +++ b/src/libstd/sys/common/gnu/libbacktrace.rs @@ -15,7 +15,6 @@ use sys_common::backtrace::{output, output_fileline}; pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, symaddr: *mut libc::c_void) -> io::Result<()> { - use env; use ffi::CStr; use ptr; @@ -110,46 +109,22 @@ pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, // that is calculated the first time this is requested. Remember that // backtracing all happens serially (one global lock). // - // An additionally oddity in this function is that we initialize the - // filename via self_exe_name() to pass to libbacktrace. It turns out - // that on Linux libbacktrace seamlessly gets the filename of the - // current executable, but this fails on freebsd. by always providing - // it, we make sure that libbacktrace never has a reason to not look up - // the symbols. The libbacktrace API also states that the filename must - // be in "permanent memory", so we copy it to a static and then use the - // static as the pointer. + // Things don't work so well on not-Linux since libbacktrace can't track + // down that executable this is. We at one point used env::current_exe but + // it turns out that there are some serious security issues with that + // approach. // - // FIXME: We also call self_exe_name() on DragonFly BSD. I haven't - // tested if this is required or not. + // Specifically, on certain platforms like BSDs, a malicious actor can cause + // an arbitrary file to be placed at the path returned by current_exe. + // libbacktrace does not behave defensively in the presence of ill-formed + // DWARF information, and has been demonstrated to segfault in at least one + // case. There is no evidence at the moment to suggest that a more carefully + // constructed file can't cause arbitrary code execution. As a result of all + // of this, we don't hint libbacktrace with the path to the current process. unsafe fn init_state() -> *mut backtrace_state { static mut STATE: *mut backtrace_state = ptr::null_mut(); - static mut LAST_FILENAME: [libc::c_char; 256] = [0; 256]; if !STATE.is_null() { return STATE } - let selfname = if cfg!(target_os = "freebsd") || - cfg!(target_os = "dragonfly") || - cfg!(target_os = "bitrig") || - cfg!(target_os = "openbsd") || - cfg!(target_os = "windows") { - env::current_exe().ok() - } else { - None - }; - let filename = match selfname.as_ref().and_then(|s| s.to_str()) { - Some(path) => { - let bytes = path.as_bytes(); - if bytes.len() < LAST_FILENAME.len() { - let i = bytes.iter(); - for (slot, val) in LAST_FILENAME.iter_mut().zip(i) { - *slot = *val as libc::c_char; - } - LAST_FILENAME.as_ptr() - } else { - ptr::null() - } - } - None => ptr::null(), - }; - STATE = backtrace_create_state(filename, 0, error_cb, + STATE = backtrace_create_state(ptr::null(), 0, error_cb, ptr::null_mut()); STATE } diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index 237e6823e0f87..0699c6f4ac2a9 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -312,9 +312,15 @@ impl StyledBuffer { self.text[line][col] = chr; self.styles[line][col] = style; } else { - while self.text[line].len() < col { - self.text[line].push(' '); + let mut i = self.text[line].len(); + while i < col { + let s = match self.text[0].get(i) { + Some(&'\t') => '\t', + _ => ' ' + }; + self.text[line].push(s); self.styles[line].push(Style::NoStyle); + i += 1; } self.text[line].push(chr); self.styles[line].push(style); diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 5a888b488191b..62ce3fa9dd5e9 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -79,6 +79,30 @@ fn make_string(lines: &[RenderedLine]) -> String { .collect() } +#[test] +fn tab() { + let file_text = " +fn foo() { +\tbar; +} +"; + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + let span_bar = cm.span_substr(&foo, file_text, "bar", 0); + + let mut snippet = SnippetData::new(cm, Some(span_bar)); + snippet.push(span_bar, true, None); + + let lines = snippet.render_lines(); + let text = make_string(&lines); + assert_eq!(&text[..], &" + --> foo.rs:3:2 +3 |> \tbar; + |> \t^^^ +"[1..]); +} + #[test] fn one_line() { let file_text = r#" diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index 2c21fd2cd5ed2..30fe0f2db8a1c 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -39,6 +39,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, // Clone + Copy, and then there'd be no Clone impl at all if the user fills in something // that is Clone but not Copy. and until specialization we can't write both impls. let bounds; + let unify_fieldless_variants; let substructure; match *item { Annotatable::Item(ref annitem) => { @@ -49,6 +50,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, && attr::contains_name(&annitem.attrs, "derive_Copy") => { bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; + unify_fieldless_variants = true; substructure = combine_substructure(Box::new(|c, s, sub| { cs_clone("Clone", c, s, sub, Mode::Shallow) })); @@ -56,6 +58,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, _ => { bounds = vec![]; + unify_fieldless_variants = false; substructure = combine_substructure(Box::new(|c, s, sub| { cs_clone("Clone", c, s, sub, Mode::Deep) })); @@ -84,6 +87,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, ret_ty: Self_, attributes: attrs, is_unsafe: false, + unify_fieldless_variants: unify_fieldless_variants, combine_substructure: substructure, } ), diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 1b855c56a48bf..8bd12c393370d 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -62,6 +62,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, ret_ty: nil_ty(), attributes: attrs, is_unsafe: false, + unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|a, b, c| { cs_total_eq_assert(a, b, c) })) diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 74706c470872a..6133adb8fc5d1 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -42,6 +42,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), attributes: attrs, is_unsafe: false, + unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|a, b, c| { cs_cmp(a, b, c) })), diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index 6406ee59a5eb5..e5890d7213bed 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -73,6 +73,7 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, ret_ty: Literal(path_local!(bool)), attributes: attrs, is_unsafe: false, + unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|a, b, c| { $f(a, b, c) })) diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index e49c77285ab02..cfc6dbe5cd030 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -38,6 +38,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, ret_ty: Literal(path_local!(bool)), attributes: attrs, is_unsafe: false, + unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { cs_op($op, $equal, cx, span, substr) })) @@ -62,6 +63,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, ret_ty: ret_ty, attributes: attrs, is_unsafe: false, + unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { cs_partial_cmp(cx, span, substr) })) diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index 323c6c388fb64..d86eae820a884 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -45,6 +45,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt, ret_ty: Literal(path_std!(cx, core::fmt::Result)), attributes: Vec::new(), is_unsafe: false, + unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { show_substructure(a, b, c) })) diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 9387cf05ac7d1..04888d046ad2d 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -85,6 +85,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, )), attributes: Vec::new(), is_unsafe: false, + unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { decodable_substructure(a, b, c, krate) })), diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs index bee63a98c252f..a6a4830fab7f8 100644 --- a/src/libsyntax_ext/deriving/default.rs +++ b/src/libsyntax_ext/deriving/default.rs @@ -42,6 +42,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, ret_ty: Self_, attributes: attrs, is_unsafe: false, + unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { default_substructure(a, b, c) })) diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 5b47d8da8b642..66672305829b9 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -161,6 +161,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, )), attributes: Vec::new(), is_unsafe: false, + unify_fieldless_variants: false, combine_substructure: combine_substructure(Box::new(|a, b, c| { encodable_substructure(a, b, c, krate) })), diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 1d5fc13c72008..45029c8eb943b 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -257,6 +257,9 @@ pub struct MethodDef<'a> { // Is it an `unsafe fn`? pub is_unsafe: bool, + /// Can we combine fieldless variants for enums into a single match arm? + pub unify_fieldless_variants: bool, + pub combine_substructure: RefCell>, } @@ -1131,12 +1134,15 @@ impl<'a> MethodDef<'a> { let catch_all_substructure = EnumNonMatchingCollapsed( self_arg_idents, &variants[..], &vi_idents[..]); + let first_fieldless = variants.iter().find(|v| v.node.data.fields().is_empty()); + // These arms are of the form: // (Variant1, Variant1, ...) => Body1 // (Variant2, Variant2, ...) => Body2 // ... // where each tuple has length = self_args.len() let mut match_arms: Vec = variants.iter().enumerate() + .filter(|&(_, v)| !(self.unify_fieldless_variants && v.node.data.fields().is_empty())) .map(|(index, variant)| { let mk_self_pat = |cx: &mut ExtCtxt, self_arg_name: &str| { let (p, idents) = trait_.create_enum_variant_pattern( @@ -1219,6 +1225,28 @@ impl<'a> MethodDef<'a> { cx.arm(sp, vec![single_pat], arm_expr) }).collect(); + + let default = match first_fieldless { + Some(v) if self.unify_fieldless_variants => { + // We need a default case that handles the fieldless variants. + // The index and actual variant aren't meaningful in this case, + // so just use whatever + Some(self.call_substructure_method( + cx, trait_, type_ident, &self_args[..], nonself_args, + &EnumMatching(0, v, Vec::new()))) + } + _ if variants.len() > 1 && self_args.len() > 1 => { + // Since we know that all the arguments will match if we reach + // the match expression we add the unreachable intrinsics as the + // result of the catch all which should help llvm in optimizing it + Some(deriving::call_intrinsic(cx, sp, "unreachable", vec![])) + } + _ => None + }; + if let Some(arm) = default { + match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], arm)); + } + // We will usually need the catch-all after matching the // tuples `(VariantK, VariantK, ...)` for each VariantK of the // enum. But: @@ -1292,13 +1320,6 @@ impl<'a> MethodDef<'a> { cx, trait_, type_ident, &self_args[..], nonself_args, &catch_all_substructure); - //Since we know that all the arguments will match if we reach the match expression we - //add the unreachable intrinsics as the result of the catch all which should help llvm - //in optimizing it - match_arms.push(cx.arm(sp, - vec![cx.pat_wild(sp)], - deriving::call_intrinsic(cx, sp, "unreachable", vec![]))); - // Final wrinkle: the self_args are expressions that deref // down to desired l-values, but we cannot actually deref // them when they are fed as r-values into a tuple diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index c37ae116d379b..fd449372cb376 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -51,6 +51,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, ret_ty: nil_ty(), attributes: vec![], is_unsafe: false, + unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(|a, b, c| { hash_substructure(a, b, c) })) diff --git a/src/test/compile-fail/issue-26472.rs b/src/test/compile-fail/issue-26472.rs new file mode 100644 index 0000000000000..0d59a897ef1af --- /dev/null +++ b/src/test/compile-fail/issue-26472.rs @@ -0,0 +1,24 @@ +// Copyright 2016 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. + +mod sub { + pub struct S { len: usize } + impl S { + pub fn new() -> S { S { len: 0 } } + pub fn len(&self) -> usize { self.len } + } +} + +fn main() { + let s = sub::S::new(); + let v = s.len; + //~^ ERROR field `len` of struct `sub::S` is private + //~| NOTE a method `len` also exists, perhaps you wish to call it +} diff --git a/src/test/compile-fail/symbol-names/impl1.rs b/src/test/compile-fail/symbol-names/impl1.rs index 39bee26da20b8..93fa48b880fdf 100644 --- a/src/test/compile-fail/symbol-names/impl1.rs +++ b/src/test/compile-fail/symbol-names/impl1.rs @@ -25,7 +25,7 @@ mod bar { use foo::Foo; impl Foo { - #[rustc_symbol_name] //~ ERROR _ZN5impl13bar26_$LT$impl$u20$foo..Foo$GT$3baz + #[rustc_symbol_name] //~ ERROR _ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz #[rustc_item_path] //~ ERROR item-path(bar::::baz) fn baz() { } } diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index 98412c08df520..0ad113b8d8b38 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -20,7 +20,6 @@ extern crate rustc_metadata; extern crate rustc_resolve; #[macro_use] extern crate syntax; -use std::cell::RefCell; use std::ffi::{CStr, CString}; use std::mem::transmute; use std::path::PathBuf; @@ -35,7 +34,7 @@ use rustc::session::config::{self, basic_options, build_configuration, Input, Op use rustc::session::build_session; use rustc_driver::{driver, abort_on_err}; use rustc_resolve::MakeGlobMap; -use rustc_metadata::creader::LocalCrateReader; +use rustc_metadata::creader::read_local_crates; use rustc_metadata::cstore::CStore; use libc::c_void; @@ -240,14 +239,14 @@ fn compile_program(input: &str, sysroot: PathBuf) let dep_graph = DepGraph::new(sess.opts.build_dep_graph()); let krate = driver::assign_node_ids(&sess, krate); - let defs = RefCell::new(ast_map::collect_definitions(&krate)); - LocalCrateReader::new(&sess, &cstore, &defs, &krate, &id).read_crates(&dep_graph); + let mut defs = ast_map::collect_definitions(&krate); + read_local_crates(&sess, &cstore, &defs, &krate, &id, &dep_graph); let (analysis, resolutions, mut hir_forest) = { - let defs = &mut *defs.borrow_mut(); - driver::lower_and_resolve(&sess, &id, defs, &krate, dep_graph, MakeGlobMap::No) + driver::lower_and_resolve(&sess, &id, &mut defs, &krate, dep_graph, MakeGlobMap::No) }; + let arenas = ty::CtxtArenas::new(); - let ast_map = ast_map::map_crate(&mut hir_forest, &defs); + let ast_map = ast_map::map_crate(&mut hir_forest, defs); abort_on_err(driver::phase_3_run_analysis_passes( &sess, ast_map, analysis, resolutions, &arenas, &id, diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs index 5f0ef4de491e0..0132014de0ab5 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs @@ -58,6 +58,7 @@ fn expand(cx: &mut ExtCtxt, ret_ty: Literal(Path::new_local("isize")), attributes: vec![], is_unsafe: false, + unify_fieldless_variants: true, combine_substructure: combine_substructure(box |cx, span, substr| { let zero = cx.expr_isize(span, 0); cs_fold(false, diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index 2878674f0ea61..6fa78913839b7 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -60,6 +60,7 @@ fn expand(cx: &mut ExtCtxt, ret_ty: Literal(Path::new_local("isize")), attributes: vec![], is_unsafe: false, + unify_fieldless_variants: true, combine_substructure: combine_substructure(Box::new(totalsum_substructure)), }, ], diff --git a/src/test/run-pass/associated-const-outer-ty-refs.rs b/src/test/run-pass/associated-const-outer-ty-refs.rs new file mode 100644 index 0000000000000..a603b225132d4 --- /dev/null +++ b/src/test/run-pass/associated-const-outer-ty-refs.rs @@ -0,0 +1,21 @@ +// Copyright 2016 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. +#![feature(associated_consts)] + +trait Lattice { + const BOTTOM: Self; +} + +// FIXME(#33573): this should work without the 'static lifetime bound. +impl Lattice for Option { + const BOTTOM: Option = None; +} + +fn main(){} diff --git a/src/test/run-pass/associated-types-in-bound-type-arg.rs b/src/test/run-pass/associated-types-in-bound-type-arg.rs new file mode 100644 index 0000000000000..18803d15719e8 --- /dev/null +++ b/src/test/run-pass/associated-types-in-bound-type-arg.rs @@ -0,0 +1,26 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test the case where we resolve `C::Result` and the trait bound +// itself includes a `Self::Item` shorthand. +// +// Regression test for issue #33425. + +trait ParallelIterator { + type Item; + fn drive_unindexed(self, consumer: C) -> C::Result + where C: Consumer; +} + +pub trait Consumer { + type Result; +} + +fn main() { } diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 8b2b26948824f..f42a6ab162b70 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -32,11 +32,15 @@ macro_rules! dump_and_die { ($($pos:expr),*) => ({ // FIXME(#18285): we cannot include the current position because // the macro span takes over the last frame's file/line. - if cfg!(target_os = "macos") || - cfg!(target_os = "ios") || - cfg!(target_os = "android") || - cfg!(all(target_os = "linux", target_arch = "arm")) || - cfg!(all(windows, target_env = "gnu")) { + if cfg!(any(target_os = "macos", + target_os = "ios", + target_os = "android", + all(target_os = "linux", target_arch = "arm"), + target_os = "windows", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd")) { // skip these platforms as this support isn't implemented yet. } else { dump_filelines(&[$($pos),*]); diff --git a/src/test/run-pass/backtrace.rs b/src/test/run-pass/backtrace.rs index 5b364358a59dd..ad38dc8f45252 100644 --- a/src/test/run-pass/backtrace.rs +++ b/src/test/run-pass/backtrace.rs @@ -115,7 +115,7 @@ fn runtest(me: &str) { } fn main() { - if cfg!(windows) && cfg!(target_arch = "x86") && cfg!(target_env = "gnu") { + if cfg!(windows) && cfg!(target_env = "gnu") { return } diff --git a/src/test/run-pass/issue-33537.rs b/src/test/run-pass/issue-33537.rs new file mode 100644 index 0000000000000..24f4c9f590b11 --- /dev/null +++ b/src/test/run-pass/issue-33537.rs @@ -0,0 +1,24 @@ +// Copyright 2016 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. + +#![feature(const_fn)] + +const fn foo() -> *const i8 { + b"foo" as *const _ as *const i8 +} + +const fn bar() -> i32 { + *&{(1, 2, 3).1} +} + +fn main() { + assert_eq!(foo(), b"foo" as *const _ as *const i8); + assert_eq!(bar(), 2); +} diff --git a/src/test/rustdoc/issue-33592.rs b/src/test/rustdoc/issue-33592.rs new file mode 100644 index 0000000000000..c0de4cc38e41e --- /dev/null +++ b/src/test/rustdoc/issue-33592.rs @@ -0,0 +1,23 @@ +// Copyright 2016 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. + +#![crate_name = "foo"] + +pub trait Foo {} + +pub struct Bar; + +pub struct Baz; + +// @has foo/trait.Foo.html '//code' 'impl Foo for Bar' +impl Foo for Bar {} + +// @has foo/trait.Foo.html '//code' 'impl Foo for Baz' +impl Foo for Baz {} diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 43475f203d57c..e91b8fb0967a8 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -35,7 +35,7 @@ pub fn check(path: &Path, bad: &mut bool) { return } - let metadata = t!(fs::metadata(&file), &file); + let metadata = t!(fs::symlink_metadata(&file), &file); if metadata.mode() & 0o111 != 0 { println!("binary checked into source: {}", file.display()); *bad = true;