]> git.lizzy.rs Git - rust.git/commitdiff
rustc_privacy: visit Ty instead of HIR types in EmbargoVisitor.
authorEduard-Mihai Burtescu <edy.burt@gmail.com>
Mon, 28 Nov 2016 03:09:28 +0000 (05:09 +0200)
committerEduard-Mihai Burtescu <edy.burt@gmail.com>
Mon, 28 Nov 2016 03:09:28 +0000 (05:09 +0200)
src/librustc/middle/reachable.rs
src/librustc/ty/fold.rs
src/librustc/ty/mod.rs
src/librustc/ty/structural_impls.rs
src/librustc_privacy/lib.rs
src/librustc_typeck/collect.rs
src/test/run-pass/impl-trait/auxiliary/xcrate.rs [new file with mode: 0644]
src/test/run-pass/impl-trait/xcrate.rs [new file with mode: 0644]

index e9b731ebaf2b66303067f079aaa5a0f491ac0546..767886a23157729a7d3e356284b5ad0aaeb5ba0a 100644 (file)
@@ -298,7 +298,8 @@ fn propagate_node(&mut self, node: &ast_map::Node,
             // Nothing to recurse on for these
             ast_map::NodeForeignItem(_) |
             ast_map::NodeVariant(_) |
-            ast_map::NodeStructCtor(_) => {}
+            ast_map::NodeStructCtor(_) |
+            ast_map::NodeTy(_) => {}
             _ => {
                 bug!("found unexpected thingy in worklist: {}",
                      self.tcx.map.node_to_string(search_item))
index 354658ec4397f3cd284e1a4a580f6db642616b87..10754825a8c1873c9b7100ea262ee5643daf09b7 100644 (file)
@@ -191,6 +191,10 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
         t.super_visit_with(self)
     }
 
+    fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
+        trait_ref.super_visit_with(self)
+    }
+
     fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
         r.super_visit_with(self)
     }
index 3719090e922d0ee6f88f77cba81e3780545a4944..844fc58cec37b9864d2d7db4594c7a90570f9b79 100644 (file)
@@ -1280,8 +1280,13 @@ pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
             }
             Some(ast_map::NodeExpr(expr)) => {
                 // This is a convenience to allow closures to work.
-                if let hir::ExprClosure(..) = expr.node {
-                    ParameterEnvironment::for_item(tcx, tcx.map.get_parent(id))
+                if let hir::ExprClosure(.., ref body, _) = expr.node {
+                    let def_id = tcx.map.local_def_id(id);
+                    let base_def_id = tcx.closure_base_def_id(def_id);
+                    tcx.construct_parameter_environment(
+                        expr.span,
+                        base_def_id,
+                        tcx.region_maps.call_site_extent(id, body.id))
                 } else {
                     tcx.empty_parameter_environment()
                 }
index 877da7ee3b51255167ab2f13db97edc2b85a8cd4..c8618cd154781b8f3a848920da8a929e8d4c2ae8 100644 (file)
@@ -599,6 +599,10 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         self.substs.visit_with(visitor)
     }
+
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        visitor.visit_trait_ref(*self)
+    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialTraitRef<'tcx> {
@@ -766,6 +770,36 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
     }
 }
 
+impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        ty::Generics {
+            parent: self.parent,
+            parent_regions: self.parent_regions,
+            parent_types: self.parent_types,
+            regions: self.regions.fold_with(folder),
+            types: self.types.fold_with(folder),
+            has_self: self.has_self,
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.regions.visit_with(visitor) || self.types.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
+    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+        ty::GenericPredicates {
+            parent: self.parent,
+            predicates: self.predicates.fold_with(folder),
+        }
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+        self.predicates.visit_with(visitor)
+    }
+}
+
 impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         match *self {
index 29bcb73602ea3dd5fdcbffecd416b07d06485eef..797371001d8d64c509c916082df6f217f2b25e6f 100644 (file)
@@ -35,7 +35,8 @@
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 use rustc::lint;
 use rustc::middle::privacy::{AccessLevel, AccessLevels};
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
+use rustc::ty::fold::TypeVisitor;
 use rustc::util::nodemap::NodeSet;
 use syntax::ast;
 use syntax_pos::Span;
@@ -62,40 +63,32 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
 }
 
 struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
+    item_def_id: DefId,
     ev: &'b mut EmbargoVisitor<'a, 'tcx>,
 }
 
 impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
-    fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
-        if let hir::TyPath(ref qpath) = ty.node {
-            let def = match *qpath {
-                hir::QPath::Resolved(_, ref path) => path.def,
-                hir::QPath::TypeRelative(..) => self.tcx.tables().type_relative_path_defs[&ty.id]
-            };
-            match def {
-                Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
-                    Some(AccessLevel::Public)
-                }
-                def => {
-                    if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
-                        self.get(node_id)
-                    } else {
-                        Some(AccessLevel::Public)
-                    }
-                }
-            }
+    fn item_ty_level(&self, item_def_id: DefId) -> Option<AccessLevel> {
+        let ty_def_id = match self.tcx.item_type(item_def_id).sty {
+            ty::TyAdt(adt, _) => adt.did,
+            ty::TyTrait(ref obj) => obj.principal.def_id(),
+            ty::TyProjection(ref proj) => proj.trait_ref.def_id,
+            _ => return Some(AccessLevel::Public)
+        };
+        if let Some(node_id) = self.tcx.map.as_local_node_id(ty_def_id) {
+            self.get(node_id)
         } else {
             Some(AccessLevel::Public)
         }
     }
 
-    fn trait_level(&self, trait_ref: &hir::TraitRef) -> Option<AccessLevel> {
-        let did = trait_ref.path.def.def_id();
-        if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
-            self.get(node_id)
-        } else {
-            Some(AccessLevel::Public)
+    fn impl_trait_level(&self, impl_def_id: DefId) -> Option<AccessLevel> {
+        if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) {
+            if let Some(node_id) = self.tcx.map.as_local_node_id(trait_ref.def_id) {
+                return self.get(node_id);
+            }
         }
+        Some(AccessLevel::Public)
     }
 
     fn get(&self, id: ast::NodeId) -> Option<AccessLevel> {
@@ -115,8 +108,12 @@ fn update(&mut self, id: ast::NodeId, level: Option<AccessLevel>) -> Option<Acce
         }
     }
 
-    fn reach<'b>(&'b mut self) -> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
-        ReachEverythingInTheInterfaceVisitor { ev: self }
+    fn reach<'b>(&'b mut self, item_id: ast::NodeId)
+                 -> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
+        ReachEverythingInTheInterfaceVisitor {
+            item_def_id: self.tcx.map.local_def_id(item_id),
+            ev: self,
+        }
     }
 }
 
@@ -130,14 +127,13 @@ fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         let inherited_item_level = match item.node {
             // Impls inherit level from their types and traits
-            hir::ItemImpl(.., None, ref ty, _) => {
-                self.ty_level(&ty)
-            }
-            hir::ItemImpl(.., Some(ref trait_ref), ref ty, _) => {
-                cmp::min(self.ty_level(&ty), self.trait_level(trait_ref))
+            hir::ItemImpl(..) => {
+                let def_id = self.tcx.map.local_def_id(item.id);
+                cmp::min(self.item_ty_level(def_id), self.impl_trait_level(def_id))
             }
-            hir::ItemDefaultImpl(_, ref trait_ref) => {
-                self.trait_level(trait_ref)
+            hir::ItemDefaultImpl(..) => {
+                let def_id = self.tcx.map.local_def_id(item.id);
+                self.impl_trait_level(def_id)
             }
             // Foreign mods inherit level from parents
             hir::ItemForeignMod(..) => {
@@ -209,22 +205,54 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
             hir::ItemMod(..) => {}
             // Reexports are handled in visit_mod
             hir::ItemUse(..) => {}
+            // The interface is empty
+            hir::ItemDefaultImpl(..) => {}
             // Visit everything
-            hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
-            hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(.., Some(..), _, _) => {
+            hir::ItemConst(..) | hir::ItemStatic(..) |
+            hir::ItemFn(..) | hir::ItemTy(..) => {
                 if item_level.is_some() {
-                    self.reach().visit_item(item);
+                    self.reach(item.id).generics().predicates().item_type();
                 }
             }
+            hir::ItemTrait(.., ref trait_items) => {
+                if item_level.is_some() {
+                    self.reach(item.id).generics().predicates();
+
+                    for trait_item in trait_items {
+                        let mut reach = self.reach(trait_item.id);
+                        reach.generics().predicates();
+
+                        if let hir::TypeTraitItem(_, None) = trait_item.node {
+                            // No type to visit.
+                        } else {
+                            reach.item_type();
+                        }
+                    }
+                }
+            }
+            // Visit everything except for private impl items
+            hir::ItemImpl(.., ref trait_ref, _, ref impl_items) => {
+                if item_level.is_some() {
+                    self.reach(item.id).generics().predicates().impl_trait_ref();
+
+                    for impl_item in impl_items {
+                        let id = impl_item.id.node_id;
+                        if trait_ref.is_some() || self.get(id).is_some() {
+                            self.reach(id).generics().predicates().item_type();
+                        }
+                    }
+                }
+            }
+
             // Visit everything, but enum variants have their own levels
-            hir::ItemEnum(ref def, ref generics) => {
+            hir::ItemEnum(ref def, _) => {
                 if item_level.is_some() {
-                    self.reach().visit_generics(generics);
+                    self.reach(item.id).generics().predicates();
                 }
                 for variant in &def.variants {
                     if self.get(variant.node.data.id()).is_some() {
                         for field in variant.node.data.fields() {
-                            self.reach().visit_struct_field(field);
+                            self.reach(field.id).item_type();
                         }
                         // Corner case: if the variant is reachable, but its
                         // enum is not, make the enum reachable as well.
@@ -236,32 +264,18 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
             hir::ItemForeignMod(ref foreign_mod) => {
                 for foreign_item in &foreign_mod.items {
                     if self.get(foreign_item.id).is_some() {
-                        self.reach().visit_foreign_item(foreign_item);
+                        self.reach(foreign_item.id).generics().predicates().item_type();
                     }
                 }
             }
             // Visit everything except for private fields
-            hir::ItemStruct(ref struct_def, ref generics) |
-            hir::ItemUnion(ref struct_def, ref generics) => {
+            hir::ItemStruct(ref struct_def, _) |
+            hir::ItemUnion(ref struct_def, _) => {
                 if item_level.is_some() {
-                    self.reach().visit_generics(generics);
+                    self.reach(item.id).generics().predicates();
                     for field in struct_def.fields() {
                         if self.get(field.id).is_some() {
-                            self.reach().visit_struct_field(field);
-                        }
-                    }
-                }
-            }
-            // The interface is empty
-            hir::ItemDefaultImpl(..) => {}
-            // Visit everything except for private impl items
-            hir::ItemImpl(.., ref generics, None, _, ref impl_item_refs) => {
-                if item_level.is_some() {
-                    self.reach().visit_generics(generics);
-                    for impl_item_ref in impl_item_refs {
-                        if self.get(impl_item_ref.id.node_id).is_some() {
-                            let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
-                            self.reach().visit_impl_item(impl_item);
+                            self.reach(field.id).item_type();
                         }
                     }
                 }
@@ -306,87 +320,69 @@ fn visit_mod(&mut self, m: &'tcx hir::Mod, _sp: Span, id: ast::NodeId) {
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
         self.update(md.id, Some(AccessLevel::Public));
     }
-}
 
-impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
-    // Make the type hidden under a type alias reachable
-    fn reach_aliased_type(&mut self, item: &'tcx hir::Item, segment: &'tcx hir::PathSegment) {
-        if let hir::ItemTy(ref ty, ref generics) = item.node {
-            // See `fn is_public_type_alias` for details
-            self.visit_ty(ty);
-            let provided_params = segment.parameters.types().len();
-            for ty_param in &generics.ty_params[provided_params..] {
-                if let Some(ref default_ty) = ty_param.default {
-                    self.visit_ty(default_ty);
-                }
+    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
+        if let hir::TyImplTrait(..) = ty.node {
+            if self.get(ty.id).is_some() {
+                // Reach the (potentially private) type and the API being exposed.
+                self.reach(ty.id).item_type().predicates();
             }
         }
+
+        intravisit::walk_ty(self, ty);
     }
 }
 
-impl<'b, 'a, 'tcx: 'a> Visitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
-    fn visit_nested_impl_item(&mut self, item_id: hir::ImplItemId) {
-        // when we visit an impl, its methods and items are part of its "interface"
-        let impl_item = self.ev.tcx.map.impl_item(item_id);
-        self.visit_impl_item(impl_item)
+impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
+    fn generics(&mut self) -> &mut Self {
+        self.ev.tcx.item_generics(self.item_def_id).visit_with(self);
+        self
     }
 
-    fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        let def_and_segment = match ty.node {
-            hir::TyPath(hir::QPath::Resolved(_, ref path)) => {
-                Some((path.def, path.segments.last().unwrap()))
-            }
-            hir::TyPath(hir::QPath::TypeRelative(_, ref segment)) => {
-                Some((self.ev.tcx.tables().type_relative_path_defs[&ty.id], &**segment))
-            }
+    fn predicates(&mut self) -> &mut Self {
+        self.ev.tcx.item_predicates(self.item_def_id).visit_with(self);
+        self
+    }
+
+    fn item_type(&mut self) -> &mut Self {
+        self.ev.tcx.item_type(self.item_def_id).visit_with(self);
+        self
+    }
+
+    fn impl_trait_ref(&mut self) -> &mut Self {
+        self.ev.tcx.impl_trait_ref(self.item_def_id).visit_with(self);
+        self
+    }
+}
+
+impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+        let ty_def_id = match ty.sty {
+            ty::TyAdt(adt, _) => Some(adt.did),
+            ty::TyTrait(ref obj) => Some(obj.principal.def_id()),
+            ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
+            ty::TyFnDef(def_id, ..) |
+            ty::TyAnon(def_id, _) => Some(def_id),
             _ => None
         };
-        if let Some((def, segment)) = def_and_segment {
-            match def {
-                Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) |
-                Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id) => {
-                    if let Some(mut node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
-                        // Check the trait for associated types.
-                        if let hir::map::NodeTraitItem(_) = self.ev.tcx.map.get(node_id) {
-                            node_id = self.ev.tcx.map.get_parent(node_id);
-                        }
-
-                        let item = self.ev.tcx.map.expect_item(node_id);
-                        if let Def::TyAlias(..) = def {
-                            // Type aliases are substituted. Associated type aliases are not
-                            // substituted yet, but ideally they should be.
-                            if self.ev.get(item.id).is_none() {
-                                self.reach_aliased_type(item, segment);
-                            }
-                        } else {
-                            self.ev.update(item.id, Some(AccessLevel::Reachable));
-                        }
-                    }
-                }
 
-                _ => {}
+        if let Some(def_id) = ty_def_id {
+            if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
+                self.ev.update(node_id, Some(AccessLevel::Reachable));
             }
         }
 
-        intravisit::walk_ty(self, ty);
+        ty.super_visit_with(self)
     }
 
-    fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
-        let def_id = trait_ref.path.def.def_id();
-        if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
+    fn visit_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
+        if let Some(node_id) = self.ev.tcx.map.as_local_node_id(trait_ref.def_id) {
             let item = self.ev.tcx.map.expect_item(node_id);
             self.ev.update(item.id, Some(AccessLevel::Reachable));
         }
 
-        intravisit::walk_trait_ref(self, trait_ref);
+        trait_ref.super_visit_with(self)
     }
-
-    // Don't recurse into function bodies
-    fn visit_block(&mut self, _: &hir::Block) {}
-    // Don't recurse into expressions in array sizes or const initializers
-    fn visit_expr(&mut self, _: &hir::Expr) {}
-    // Don't recurse into patterns in function arguments
-    fn visit_pat(&mut self, _: &hir::Pat) {}
 }
 
 ////////////////////////////////////////////////////////////////////////////////
index 493f9d96fe028dcbfb0cee1d636bfb7f07bca3e3..0dcc0bcc316ce96cab2a98079156907d07ffa046 100644 (file)
@@ -136,7 +136,9 @@ fn visit_item(&mut self, item: &hir::Item) {
 
     fn visit_expr(&mut self, expr: &hir::Expr) {
         if let hir::ExprClosure(..) = expr.node {
-            convert_closure(self.ccx, expr.id);
+            let def_id = self.ccx.tcx.map.local_def_id(expr.id);
+            generics_of_def_id(self.ccx, def_id);
+            type_of_def_id(self.ccx, def_id);
         }
         intravisit::walk_expr(self, expr);
     }
@@ -570,40 +572,6 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone());
 }
 
-fn convert_closure<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                             node_id: ast::NodeId)
-{
-    let tcx = ccx.tcx;
-    let def_id = tcx.map.local_def_id(node_id);
-    let base_def_id = tcx.closure_base_def_id(def_id);
-    let base_generics = generics_of_def_id(ccx, base_def_id);
-
-    // provide junk type parameter defs - the only place that
-    // cares about anything but the length is instantiation,
-    // and we don't do that for closures.
-    let upvar_decls : Vec<_> = tcx.with_freevars(node_id, |fv| {
-        fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
-            index: (base_generics.count() as u32) + (i as u32),
-            name: Symbol::intern("<upvar>"),
-            def_id: def_id,
-            default_def_id: base_def_id,
-            default: None,
-            object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
-            pure_wrt_drop: false,
-        }).collect()
-    });
-    tcx.generics.borrow_mut().insert(def_id, tcx.alloc_generics(ty::Generics {
-        parent: Some(base_def_id),
-        parent_regions: base_generics.parent_regions + (base_generics.regions.len() as u32),
-        parent_types: base_generics.parent_types + (base_generics.types.len() as u32),
-        regions: vec![],
-        types: upvar_decls,
-        has_self: base_generics.has_self,
-    }));
-
-    type_of_def_id(ccx, def_id);
-}
-
 fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                             container: AssociatedItemContainer,
                             id: ast::NodeId,
@@ -1320,6 +1288,9 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                 let parent_id = tcx.map.get_parent(node_id);
                 Some(tcx.map.local_def_id(parent_id))
             }
+            NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+                Some(tcx.closure_base_def_id(def_id))
+            }
             NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
                 let mut parent_id = node_id;
                 loop {
@@ -1437,7 +1408,24 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             let i = type_start + i as u32;
             get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults)
         });
-        let types: Vec<_> = opt_self.into_iter().chain(types).collect();
+        let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
+
+        // provide junk type parameter defs - the only place that
+        // cares about anything but the length is instantiation,
+        // and we don't do that for closures.
+        if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
+            tcx.with_freevars(node_id, |fv| {
+                types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
+                    index: type_start + i as u32,
+                    name: Symbol::intern("<upvar>"),
+                    def_id: def_id,
+                    default_def_id: parent_def_id.unwrap(),
+                    default: None,
+                    object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
+                    pure_wrt_drop: false,
+               }));
+            });
+        }
 
         // Debugging aid.
         if tcx.has_attr(def_id, "rustc_object_lifetime_default") {
diff --git a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs
new file mode 100644 (file)
index 0000000..be353f6
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(conservative_impl_trait)]
+
+pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 {
+    move |b| move |c| move |d| a + b + c + d
+}
diff --git a/src/test/run-pass/impl-trait/xcrate.rs b/src/test/run-pass/impl-trait/xcrate.rs
new file mode 100644 (file)
index 0000000..fe3ed7b
--- /dev/null
@@ -0,0 +1,17 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:xcrate.rs
+
+extern crate xcrate;
+
+fn main() {
+    assert_eq!(xcrate::fourway_add(1)(2)(3)(4), 10);
+}