]> git.lizzy.rs Git - rust.git/commitdiff
Implement inferring outlives requirements for references, structs, enum, union, and...
authortoidiu <toidiu@protonmail.com>
Sun, 15 Oct 2017 05:13:56 +0000 (01:13 -0400)
committertoidiu <toidiu@protonmail.com>
Thu, 12 Apr 2018 17:52:06 +0000 (13:52 -0400)
44 files changed:
.gitignore
src/librustc/dep_graph/dep_node.rs
src/librustc/ich/impls_ty.rs
src/librustc/ty/maps/config.rs
src/librustc/ty/maps/mod.rs
src/librustc/ty/maps/plumbing.rs
src/librustc/ty/mod.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/diagnostics.rs
src/librustc_typeck/lib.rs
src/librustc_typeck/outlives/explicit.rs [new file with mode: 0644]
src/librustc_typeck/outlives/implicit_empty.rs [new file with mode: 0644]
src/librustc_typeck/outlives/implicit_infer.rs [new file with mode: 0644]
src/librustc_typeck/outlives/mod.rs
src/librustc_typeck/outlives/test.rs
src/libsyntax/feature_gate.rs
src/test/compile-fail/outlives-associated-types.rs
src/test/ui/feature-gate-infer_outlives_requirements.rs [new file with mode: 0644]
src/test/ui/feature-gate-infer_outlives_requirements.stderr [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/enum-pass.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/enum.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/enum.stderr [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/explicit-where.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/nested-structs.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/projections-pass.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/projections.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/projections.stderr [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/reference-pass.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/reference.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/reference.stderr [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/union-pass.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/union.rs [new file with mode: 0644]
src/test/ui/rfc-2093-infer-outlives/union.stderr [new file with mode: 0644]

index 57407a2399a2f249f85ecf5ad69d05b3888ef481..efbbf22ffe57bbe85e36595fee797dd20509218e 100644 (file)
@@ -83,6 +83,7 @@ __pycache__/
 /src/libstd_unicode/UnicodeData.txt
 /stage[0-9]+/
 /target
+target/
 /test/
 /tmp/
 TAGS
index 7c5318a96f5ac5773422972984e7afd37179579b..f3f31e5740fb9601c02634e6b94c05590fe66ecf 100644 (file)
@@ -500,6 +500,7 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool {
     [] GenericsOfItem(DefId),
     [] PredicatesOfItem(DefId),
     [] InferredOutlivesOf(DefId),
+    [] InferredOutlivesCrate(CrateNum),
     [] SuperPredicatesOfItem(DefId),
     [] TraitDefOfItem(DefId),
     [] AdtDefOfItem(DefId),
index af4d3429bb1d57699210dd13645a0f07598a0e5c..41cfac2674be66b4dc358a30515923f777923758 100644 (file)
@@ -1100,6 +1100,20 @@ fn hash_stable<W: StableHasherResult>(&self,
     }
 }
 
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::CratePredicatesMap<'gcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::CratePredicatesMap {
+            ref predicates,
+            // This is just an irrelevant helper value.
+            empty_predicate: _,
+        } = *self;
+
+        predicates.hash_stable(hcx, hasher);
+    }
+}
+
 impl_stable_hash_for!(struct ty::AssociatedItem {
     def_id,
     name,
index 16866636cd90aacae94f00970462b272dabc0409..a4571c161c477471daa9be4d4fa7a3c9373ab88d 100644 (file)
@@ -155,6 +155,12 @@ fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::inferred_outlives_crate<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("computing the inferred outlives predicates for items in this crate")
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::mir_shims<'tcx> {
     fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String {
         format!("generating MIR shim for `{}`",
index 5a23a3b952a423c392f4aa8ce274d965b966285a..6dd43554a983263c2129cfc535fa3e39bd0063b6 100644 (file)
     /// associated generics and predicates.
     [] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics,
     [] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
+    [] fn explicit_predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>,
 
     /// Maps from the def-id of a trait to the list of
     /// super-predicates. This is a subset of the full list of
     [] fn variances_of: ItemVariances(DefId) -> Lrc<Vec<ty::Variance>>,
 
     /// Maps from def-id of a type to its (inferred) outlives.
-    [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Vec<ty::Predicate<'tcx>>,
+    [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>,
+
+    /// Maps from def-id of a type to its (inferred) outlives.
+    [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum)
+        -> Lrc<ty::CratePredicatesMap<'tcx>>,
 
     /// Maps from an impl/trait def-id to a list of the def-ids of its items
     [] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Lrc<Vec<DefId>>,
index c04e580a33dedaa1c6f840b3c2cc5f33df9bfd7d..2a1d87421aacb300058e2ce8fd382539e65048c9 100644 (file)
@@ -1007,6 +1007,7 @@ macro_rules! force {
         DepKind::GenericsOfItem => { force!(generics_of, def_id!()); }
         DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); }
         DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); }
+        DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); }
         DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); }
         DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); }
         DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); }
index 33b59eda7ce2ccb6ba54b27a3a3016f4e0afc7c0..fccba1e6aa76f470e70f777435c37734d7e9e902 100644 (file)
@@ -956,6 +956,22 @@ pub enum Predicate<'tcx> {
     ConstEvaluatable(DefId, &'tcx Substs<'tcx>),
 }
 
+/// The crate outlives map is computed during typeck and contains the
+/// outlives of every item in the local crate. You should not use it
+/// directly, because to do so will make your pass dependent on the
+/// HIR of every item in the local crate. Instead, use
+/// `tcx.inferred_outlives_of()` to get the outlives for a *particular*
+/// item.
+pub struct CratePredicatesMap<'tcx> {
+    /// For each struct with outlive bounds, maps to a vector of the
+    /// predicate of its outlive bounds. If an item has no outlives
+    /// bounds, it will have no entry.
+    pub predicates: FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+
+    /// An empty vector, useful for cloning.
+    pub empty_predicate: Lrc<Vec<ty::Predicate<'tcx>>>,
+}
+
 impl<'tcx> AsRef<Predicate<'tcx>> for Predicate<'tcx> {
     fn as_ref(&self) -> &Predicate<'tcx> {
         self
index a4f820d1fdcf9553488b85b9da013929f9307f47..e2e6a2d7aac9235a1f676060a01a07d955e302ec 100644 (file)
@@ -64,6 +64,7 @@ pub fn provide(providers: &mut Providers) {
         type_of,
         generics_of,
         predicates_of,
+        explicit_predicates_of,
         super_predicates_of,
         type_param_predicates,
         trait_def,
@@ -1296,13 +1297,17 @@ fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            def_id: DefId)
                            -> ty::GenericPredicates<'tcx> {
     let explicit = explicit_predicates_of(tcx, def_id);
+    let predicates = if tcx.sess.features_untracked().infer_outlives_requirements {
+        [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
+    } else { explicit.predicates };
+
     ty::GenericPredicates {
         parent: explicit.parent,
-        predicates: [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
+        predicates: predicates,
     }
 }
 
-fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            def_id: DefId)
                            -> ty::GenericPredicates<'tcx> {
     use rustc::hir::map::*;
index 5a53c008f6c317d9f518ea3b77c004e2e40ad438..063d83780d8b908dc0ecdbbcc0396d74fe247727 100644 (file)
@@ -4840,11 +4840,11 @@ fn is_null(self: *const Self) -> bool {
     E0588, // packed type cannot transitively contain a `[repr(align)]` type
     E0592, // duplicate definitions with name `{}`
 //  E0613, // Removed (merged with E0609)
-    E0640, // infer outlives
     E0627, // yield statement outside of generator literal
     E0632, // cannot provide explicit type parameters when `impl Trait` is used in
            // argument position.
     E0634, // type has conflicting packed representaton hints
+    E0640, // infer outlives requirements
     E0641, // cannot cast to/from a pointer with an unknown kind
     E0645, // trait aliases not finished
     E0907, // type inside generator must be known in this context
index 3a48e1806af2cad25b83d5037b35b192576b4673..1f5aa45e79a4513798b79e043724a858248d8f00 100644 (file)
@@ -82,6 +82,7 @@
 #![feature(slice_patterns)]
 #![feature(slice_sort_by_cached_key)]
 #![feature(dyn_trait)]
+#![feature(underscore_lifetimes)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs
new file mode 100644 (file)
index 0000000..9a8fd46
--- /dev/null
@@ -0,0 +1,82 @@
+// Copyright 2013 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.
+
+use hir::map as hir_map;
+use rustc::hir;
+use rustc::hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::ty::maps::Providers;
+use rustc::ty::{self, CratePredicatesMap, TyCtxt};
+use rustc_data_structures::sync::Lrc;
+use util::nodemap::FxHashMap;
+
+pub fn explicit_predicates<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    crate_num: CrateNum,
+) -> FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> {
+    assert_eq!(crate_num, LOCAL_CRATE);
+    let mut predicates: FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> = FxHashMap();
+
+    // iterate over the entire crate
+    tcx.hir.krate().visit_all_item_likes(&mut ExplicitVisitor {
+        tcx: tcx,
+        explicit_predicates: &mut predicates,
+        crate_num: crate_num,
+    });
+
+    predicates
+}
+
+pub struct ExplicitVisitor<'cx, 'tcx: 'cx> {
+    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
+    explicit_predicates: &'cx mut FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+    crate_num: CrateNum,
+}
+
+impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> {
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        let def_id = DefId {
+            krate: self.crate_num,
+            index: item.hir_id.owner,
+        };
+
+        let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id);
+
+        let filtered_predicates = local_explicit_predicate
+            .predicates
+            .into_iter()
+            .filter(|pred| match pred {
+                ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => true,
+
+                ty::Predicate::Trait(..)
+                | ty::Predicate::Projection(..)
+                | ty::Predicate::WellFormed(..)
+                | ty::Predicate::ObjectSafe(..)
+                | ty::Predicate::ClosureKind(..)
+                | ty::Predicate::Subtype(..)
+                | ty::Predicate::ConstEvaluatable(..) => false,
+            })
+            .collect();
+
+        match item.node {
+            hir::ItemStruct(..) | hir::ItemEnum(..) => {
+                self.tcx.adt_def(def_id);
+            }
+            _ => {}
+        }
+
+        self.explicit_predicates
+            .insert(def_id, Lrc::new(filtered_predicates));
+    }
+
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {}
+
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {}
+}
diff --git a/src/librustc_typeck/outlives/implicit_empty.rs b/src/librustc_typeck/outlives/implicit_empty.rs
new file mode 100644 (file)
index 0000000..b2259c6
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2013 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.
+
+use hir::map as hir_map;
+use rustc::hir;
+use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::ty::maps::Providers;
+use rustc::ty::{self, CratePredicatesMap, TyCtxt};
+use rustc_data_structures::sync::Lrc;
+use util::nodemap::FxHashMap;
+
+// Create the sets of inferred predicates for each type. These sets
+// are initially empty but will grow during the inference step.
+pub fn empty_predicate_map<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+) -> FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>> {
+    let mut predicates = FxHashMap();
+
+    // iterate over the entire crate
+    tcx.hir
+        .krate()
+        .visit_all_item_likes(&mut EmptyImplicitVisitor {
+            tcx,
+            predicates: &mut predicates,
+        });
+
+    predicates
+}
+
+pub struct EmptyImplicitVisitor<'cx, 'tcx: 'cx> {
+    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
+    predicates: &'cx mut FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+}
+
+impl<'a, 'p, 'v> ItemLikeVisitor<'v> for EmptyImplicitVisitor<'a, 'p> {
+    fn visit_item(&mut self, item: &hir::Item) {
+        self.predicates
+            .insert(self.tcx.hir.local_def_id(item.id), Lrc::new(Vec::new()));
+    }
+
+    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {}
+
+    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {}
+}
diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs
new file mode 100644 (file)
index 0000000..ac53a6d
--- /dev/null
@@ -0,0 +1,442 @@
+// Copyright 2013 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.
+
+#![allow(unused)]
+
+use rustc::hir;
+use rustc::hir::def::{CtorKind, Def};
+use rustc::hir::def_id::{self, CrateNum, DefId, LOCAL_CRATE};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::hir::map as hir_map;
+use rustc::ty::Slice;
+use rustc::ty::maps::Providers;
+use rustc::ty::outlives::Component;
+use rustc::ty::subst::{Kind, Subst, UnpackedKind};
+use rustc::ty::{self, AdtKind, CratePredicatesMap, Region, RegionKind, ReprOptions,
+                ToPolyTraitRef, ToPredicate, Ty, TyCtxt};
+use rustc::util::nodemap::{FxHashMap, FxHashSet};
+use rustc_data_structures::sync::Lrc;
+use syntax::{abi, ast};
+use syntax_pos::{Span, DUMMY_SP};
+
+/// Infer predicates for the items in the crate.
+///
+/// global_inferred_outlives: this is initially the empty map that
+///     was generated by walking the items in the crate. This will
+///     now be filled with inferred predicates.
+pub fn infer_predicates<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+) -> FxHashMap<DefId, RequiredPredicates<'tcx>> {
+    debug!("infer_predicates");
+
+    let mut predicates_added = true;
+
+    let mut global_inferred_outlives = FxHashMap::default();
+
+    // If new predicates were added then we need to re-calculate
+    // all crates since there could be new implied predicates.
+    while predicates_added {
+        predicates_added = false;
+
+        let mut visitor = InferVisitor {
+            tcx: tcx,
+            global_inferred_outlives: &mut global_inferred_outlives,
+            predicates_added: &mut predicates_added,
+            explicit_map: explicit_map,
+        };
+
+        // Visit all the crates and infer predicates
+        tcx.hir.krate().visit_all_item_likes(&mut visitor);
+    }
+
+    global_inferred_outlives
+}
+
+pub struct InferVisitor<'cx, 'tcx: 'cx> {
+    tcx: TyCtxt<'cx, 'tcx, 'tcx>,
+    global_inferred_outlives: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>,
+    predicates_added: &'cx mut bool,
+    explicit_map: &'cx FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+}
+
+/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
+/// must be added to the struct header.
+type RequiredPredicates<'tcx> = FxHashSet<ty::OutlivesPredicate<Kind<'tcx>, ty::Region<'tcx>>>;
+
+impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
+    fn visit_item(&mut self, item: &hir::Item) {
+        let item_did = self.tcx.hir.local_def_id(item.id);
+
+        debug!("InferVisitor::visit_item(item={:?})", item_did);
+
+        let node_id = self.tcx
+            .hir
+            .as_local_node_id(item_did)
+            .expect("expected local def-id");
+        let item = match self.tcx.hir.get(node_id) {
+            hir::map::NodeItem(item) => item,
+            _ => bug!(),
+        };
+
+        let mut item_required_predicates = RequiredPredicates::default();
+        match item.node {
+            hir::ItemUnion(..) | hir::ItemEnum(..) | hir::ItemStruct(..) => {
+                let adt_def = self.tcx.adt_def(item_did);
+
+                // Iterate over all fields in item_did
+                for field_def in adt_def.all_fields() {
+                    // Calculating the predicate requirements necessary
+                    // for item_did.
+                    //
+                    // For field of type &'a T (reference) or TyAdt
+                    // (struct/enum/union) there will be outlive
+                    // requirements for adt_def.
+                    let field_ty = self.tcx.type_of(field_def.did);
+                    insert_required_predicates_to_be_wf(
+                        self.tcx,
+                        field_ty,
+                        self.global_inferred_outlives,
+                        &mut item_required_predicates,
+                        self.explicit_map,
+                    );
+                }
+            }
+
+            _ => {}
+        };
+
+        // If new predicates were added (`local_predicate_map` has more
+        // predicates than the `global_inferred_outlives`), the new predicates
+        // might result in implied predicates for their parent types.
+        // Therefore mark `predicates_added` as true and which will ensure
+        // we walk the crates again and re-calculate predicates for all
+        // items.
+        let item_predicates_len: usize = self.global_inferred_outlives
+            .get(&item_did)
+            .map(|p| p.len())
+            .unwrap_or(0);
+        if item_required_predicates.len() > item_predicates_len {
+            *self.predicates_added = true;
+            self.global_inferred_outlives
+                .insert(item_did, item_required_predicates);
+        }
+    }
+
+    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {}
+
+    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {}
+}
+
+fn insert_required_predicates_to_be_wf<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    field_ty: Ty<'tcx>,
+    global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
+    required_predicates: &mut RequiredPredicates<'tcx>,
+    explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+) {
+    for ty in field_ty.walk() {
+        match ty.sty {
+            // The field is of type &'a T which means that we will have
+            // a predicate requirement of T: 'a (T outlives 'a).
+            //
+            // We also want to calculate potential predicates for the T
+            ty::TyRef(region, mt) => {
+                insert_outlives_predicate(tcx, mt.ty.into(), region, required_predicates);
+            }
+
+            // For each TyAdt (struct/enum/union) type `Foo<'a, T>`, we
+            // can load the current set of inferred and explicit
+            // predicates from `global_inferred_outlives` and filter the
+            // ones that are TypeOutlives.
+            //
+            ty::TyAdt(def, substs) => {
+                // First check the inferred predicates
+                //
+                // Example 1:
+                //
+                //     struct Foo<'a, T> {
+                //         field1: Bar<'a, T>
+                //     }
+                //
+                //     struct Bar<'b, U> {
+                //         field2: &'b U
+                //     }
+                //
+                // Here, when processing the type of `field1`, we would
+                // request the set of implicit predicates computed for `Bar`
+                // thus far. This will initially come back empty, but in next
+                // round we will get `U: 'b`. We then apply the substitution
+                // `['b => 'a, U => T]` and thus get the requirement that `T:
+                // 'a` holds for `Foo`.
+                if let Some(unsubstituted_predicates) = global_inferred_outlives.get(&def.did) {
+                    for unsubstituted_predicate in unsubstituted_predicates {
+                        // `unsubstituted_predicate` is `U: 'b` in the
+                        // example above.  So apply the substitution to
+                        // get `T: 'a` (or `predicate`):
+                        let predicate = unsubstituted_predicate.subst(tcx, substs);
+                        insert_outlives_predicate(
+                            tcx,
+                            predicate.0,
+                            predicate.1,
+                            required_predicates,
+                        );
+                    }
+                }
+
+                // Check if the type has any explicit predicates that need
+                // to be added to `required_predicates`
+                // let _: () = substs.region_at(0);
+                check_explicit_predicates(tcx, &def.did, substs, required_predicates, explicit_map);
+            }
+
+            ty::TyDynamic(obj, region) => {
+                // FIXME This corresponds to `dyn Trait<..>`. In this
+                // case, we should use the explicit predicates as
+                // well.
+                if let Some(p) = obj.principal() {
+                    check_explicit_predicates(
+                        tcx,
+                        &p.skip_binder().def_id,
+                        &[region.into()],
+                        required_predicates,
+                        explicit_map,
+                    );
+                }
+            }
+
+            ty::TyProjection(obj) => {
+                // FIXME This corresponds to `<T as Foo<'a>>::Bar`. In this case, we should use the
+                // explicit predicates as well.
+                check_explicit_predicates(
+                    tcx,
+                    &obj.item_def_id,
+                    obj.substs,
+                    required_predicates,
+                    explicit_map,
+                );
+            }
+
+            _ => {}
+        }
+    }
+}
+
+/// We also have to check the explicit predicates
+/// declared on the type.
+///
+///     struct Foo<'a, T> {
+///         field1: Bar<T>
+///     }
+///
+///     struct Bar<U> where U: 'static, U: Foo {
+///         ...
+///     }
+///
+/// Here, we should fetch the explicit predicates, which
+/// will give us `U: 'static` and `U: Foo`. The latter we
+/// can ignore, but we will want to process `U: 'static`,
+/// applying the substitution as above.
+fn check_explicit_predicates<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    def_id: &DefId,
+    substs: &[Kind<'tcx>],
+    required_predicates: &mut RequiredPredicates<'tcx>,
+    explicit_map: &FxHashMap<DefId, Lrc<Vec<ty::Predicate<'tcx>>>>,
+) {
+    if let Some(general_predicates) = explicit_map.get(def_id) {
+        for general_predicate in general_predicates.iter() {
+            match general_predicate {
+                // `poly` is `PolyTypeOutlivesPredicate<OutlivesPredicate<Ty>>`
+                // where OutlivesPredicate<type1, region1> is the predicate
+                // we want to add.
+                ty::Predicate::TypeOutlives(poly) => {
+                    let predicate = poly.0.subst(tcx, substs);
+                    insert_outlives_predicate(
+                        tcx,
+                        predicate.0.into(),
+                        predicate.1,
+                        required_predicates,
+                    );
+                }
+
+                // `poly` is `PolyRegionOutlivesPredicate<OutlivesPredicate<Ty>>`
+                // where OutlivesPredicate<region1, region2> is the predicate
+                // we want to add.
+                ty::Predicate::RegionOutlives(poly) => {
+                    let predicate = poly.0.subst(tcx, substs);
+                    insert_outlives_predicate(
+                        tcx,
+                        predicate.0.into(),
+                        predicate.1,
+                        required_predicates,
+                    );
+                }
+
+                ty::Predicate::Trait(..)
+                | ty::Predicate::Projection(..)
+                | ty::Predicate::WellFormed(..)
+                | ty::Predicate::ObjectSafe(..)
+                | ty::Predicate::ClosureKind(..)
+                | ty::Predicate::Subtype(..)
+                | ty::Predicate::ConstEvaluatable(..) => (),
+            }
+        }
+    }
+}
+
+/// Given a requirement `T: 'a` or `'b: 'a`, deduce the
+/// outlives_component and add it to `required_predicates`
+fn insert_outlives_predicate<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    kind: Kind<'tcx>,
+    outlived_region: Region<'tcx>,
+    required_predicates: &mut RequiredPredicates<'tcx>,
+) {
+    // If the `'a` region is bound within the field type itself, we
+    // don't want to propagate this constraint to the header.
+    if !is_free_region(outlived_region) {
+        return;
+    }
+
+    match kind.unpack() {
+        UnpackedKind::Type(ty) => {
+            // `T: 'outlived_region` for some type `T`
+            // But T could be a lot of things:
+            // e.g., if `T = &'b u32`, then `'b: 'outlived_region` is
+            // what we want to add.
+            //
+            // Or if within `struct Foo<U>` you had `T = Vec<U>`, then
+            // we would want to add `U: 'outlived_region`
+            for component in tcx.outlives_components(ty) {
+                match component {
+                    Component::Region(r) => {
+                        // This would arise from something like:
+                        //
+                        // ```
+                        // struct Foo<'a, 'b> {
+                        //    x:  &'a &'b u32
+                        // }
+                        // ```
+                        //
+                        // Here `outlived_region = 'a` and `kind = &'b
+                        // u32`.  Decomposing `&'b u32` into
+                        // components would yield `'b`, and we add the
+                        // where clause that `'b: 'a`.
+                        insert_outlives_predicate(
+                            tcx,
+                            r.into(),
+                            outlived_region,
+                            required_predicates,
+                        );
+                    }
+
+                    Component::Param(param_ty) => {
+                        // param_ty: ty::ParamTy
+                        // This would arise from something like:
+                        //
+                        // ```
+                        // struct Foo<'a, U> {
+                        //    x:  &'a Vec<U>
+                        // }
+                        // ```
+                        //
+                        // Here `outlived_region = 'a` and `kind =
+                        // Vec<U>`.  Decomposing `Vec<U>` into
+                        // components would yield `U`, and we add the
+                        // where clause that `U: 'a`.
+                        let ty: Ty<'tcx> = tcx.mk_param(param_ty.idx, param_ty.name);
+                        required_predicates
+                            .insert(ty::OutlivesPredicate(ty.into(), outlived_region));
+                    }
+
+                    Component::Projection(proj_ty) => {
+                        // This would arise from something like:
+                        //
+                        // ```
+                        // struct Foo<'a, T: Iterator> {
+                        //    x:  &'a <T as Iterator>::Item
+                        // }
+                        // ```
+                        //
+                        // Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
+                        let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs);
+                        required_predicates
+                            .insert(ty::OutlivesPredicate(ty.into(), outlived_region));
+                    }
+
+                    Component::EscapingProjection(_) => {
+                        // As above, but the projection involves
+                        // late-bound regions.  Therefore, the WF
+                        // requirement is not checked in type definition
+                        // but at fn call site, so ignore it.
+                        //
+                        // ```
+                        // struct Foo<'a, T: Iterator> {
+                        //    x: for<'b> fn(<&'b T as Iterator>::Item)
+                        //              //  ^^^^^^^^^^^^^^^^^^^^^^^^^
+                        // }
+                        // ```
+                        //
+                        // Since `'b` is not in scope on `Foo`, can't
+                        // do anything here, ignore it.
+                    }
+
+                    Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"),
+                }
+            }
+        }
+
+        UnpackedKind::Lifetime(r) => {
+            if !is_free_region(r) {
+                return;
+            }
+            required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region));
+        }
+    }
+}
+
+fn is_free_region(region: Region<'_>) -> bool {
+    // First, screen for regions that might appear in a type header.
+    match region {
+        // *These* correspond to `T: 'a` relationships where `'a` is
+        // either declared on the type or `'static`:
+        //
+        //     struct Foo<'a, T> {
+        //         field: &'a T, // this would generate a ReEarlyBound referencing `'a`
+        //         field2: &'static T, // this would generate a ReStatic
+        //     }
+        //
+        // We care about these, so fall through.
+        RegionKind::ReStatic | RegionKind::ReEarlyBound(_) => true,
+
+        // Late-bound regions can appear in `fn` types:
+        //
+        //     struct Foo<T> {
+        //         field: for<'b> fn(&'b T) // e.g., 'b here
+        //     }
+        //
+        // The type above might generate a `T: 'b` bound, but we can
+        // ignore it.  We can't put it on the struct header anyway.
+        RegionKind::ReLateBound(..) => false,
+
+        // These regions don't appear in types from type declarations:
+        RegionKind::ReEmpty
+        | RegionKind::ReErased
+        | RegionKind::ReClosureBound(..)
+        | RegionKind::ReCanonical(..)
+        | RegionKind::ReScope(..)
+        | RegionKind::ReVar(..)
+        | RegionKind::ReSkolemized(..)
+        | RegionKind::ReFree(..) => {
+            bug!("unexpected region in outlives inference: {:?}", region);
+        }
+    }
+}
index 1127028cbc8c7c052867a20667b29d3791480cb9..bad0c68a6fe8e78d5d07444b2e4d53ad7d293821 100644 (file)
 // <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.
-
-use rustc::hir::def_id::DefId;
-use rustc::ty::{self, TyCtxt};
+#![allow(unused)]
+#[allow(dead_code)]
+use hir::map as hir_map;
+use rustc::dep_graph::DepKind;
+use rustc::hir;
+use rustc::hir::Ty_::*;
+use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::ty::maps::Providers;
+use rustc::ty::subst::UnpackedKind;
+use rustc::ty::{self, CratePredicatesMap, TyCtxt};
+use rustc_data_structures::sync::Lrc;
+use util::nodemap::FxHashMap;
 
+mod explicit;
+mod implicit_empty;
+mod implicit_infer;
 /// Code to write unit test for outlives.
 pub mod test;
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         inferred_outlives_of,
+        inferred_outlives_crate,
         ..*providers
     };
 }
 
-//todo
-fn inferred_outlives_of<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, _def_id: DefId)
-                                  -> Vec<ty::Predicate<'tcx>> {
-    Vec::new()
+fn inferred_outlives_of<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    item_def_id: DefId,
+) -> Lrc<Vec<ty::Predicate<'tcx>>> {
+    let id = tcx.hir
+        .as_local_node_id(item_def_id)
+        .expect("expected local def-id");
+
+    match tcx.hir.get(id) {
+        hir_map::NodeItem(item) => match item.node {
+            hir::ItemStruct(..) | hir::ItemEnum(..) | hir::ItemUnion(..) => {
+                let crate_map = tcx.inferred_outlives_crate(LOCAL_CRATE);
+                let dep_node = item_def_id.to_dep_node(tcx, DepKind::InferredOutlivesOf);
+                tcx.dep_graph.read(dep_node);
+
+                crate_map
+                    .predicates
+                    .get(&item_def_id)
+                    .unwrap_or(&crate_map.empty_predicate)
+                    .clone()
+            }
+
+            _ => Lrc::new(Vec::new()),
+        },
+
+        _ => Lrc::new(Vec::new()),
+    }
+}
+
+fn inferred_outlives_crate<'tcx>(
+    tcx: TyCtxt<'_, 'tcx, 'tcx>,
+    crate_num: CrateNum,
+) -> Lrc<CratePredicatesMap<'tcx>> {
+    // Compute a map from each struct/enum/union S to the **explicit**
+    // outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
+    // Typically there won't be many of these, except in older code where
+    // they were mandatory. Nonetheless, we have to ensure that every such
+    // predicate is satisfied, so they form a kind of base set of requirements
+    // for the type.
+
+    // Compute the inferred predicates
+    let exp = explicit::explicit_predicates(tcx, crate_num);
+    let mut global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp);
+
+    // Convert the inferred predicates into the "collected" form the
+    // global data structure expects.
+    //
+    // FIXME -- consider correcting impedance mismatch in some way,
+    // probably by updating the global data structure.
+    let mut predicates = global_inferred_outlives
+        .iter()
+        .map(|(&def_id, set)| {
+            let vec: Vec<ty::Predicate<'tcx>> = set.iter()
+                .map(
+                    |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() {
+                        UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder(
+                            ty::OutlivesPredicate(ty1, region2),
+                        )),
+                        UnpackedKind::Lifetime(region1) => ty::Predicate::RegionOutlives(
+                            ty::Binder(ty::OutlivesPredicate(region1, region2)),
+                        ),
+                    },
+                )
+                .collect();
+            (def_id, Lrc::new(vec))
+        })
+        .collect();
+
+    let empty_predicate = Lrc::new(Vec::new());
+
+    Lrc::new(ty::CratePredicatesMap {
+        predicates,
+        empty_predicate,
+    })
 }
index 196e66054946389f672dbffeb4d60b30d3ec82aa..c3c2ae667ddd950afde58bcfee64f07a7828ca0c 100644 (file)
 use rustc::ty::TyCtxt;
 
 pub fn test_inferred_outlives<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.hir.krate().visit_all_item_likes(&mut OutlivesTest { tcx });
+    tcx.hir
+        .krate()
+        .visit_all_item_likes(&mut OutlivesTest { tcx });
 }
 
 struct OutlivesTest<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> {
@@ -28,14 +30,16 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
         // attribute and report an error with various results if found.
         if self.tcx.has_attr(item_def_id, "rustc_outlives") {
             let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id);
-            span_err!(self.tcx.sess,
-                      item.span,
-                      E0640,
-                      "{:?}",
-                      inferred_outlives_of);
+            span_err!(
+                self.tcx.sess,
+                item.span,
+                E0640,
+                "{:?}",
+                inferred_outlives_of
+            );
         }
     }
 
-    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) { }
-    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { }
+    fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {}
+    fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {}
 }
index df39757d1ebf174478164c96163641e1a98cc62c..73ebfc20876d0679814369d4abe88883207d2570 100644 (file)
@@ -426,6 +426,9 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
     // Use `?` as the Kleene "at most one" operator
     (active, macro_at_most_once_rep, "1.25.0", Some(48075), None),
 
+    // Infer outlives requirements; RFC 2093
+    (active, infer_outlives_requirements, "1.26.0", Some(44493), None),
+
     // Multiple patterns with `|` in `if let` and `while let`
     (active, if_while_or_patterns, "1.26.0", Some(48215), None),
 
@@ -1023,6 +1026,12 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                                  "never will be stable",
                                  cfg_fn!(rustc_attrs))),
 
+    // RFC #2093
+    ("infer_outlives_requirements", Normal, Gated(Stability::Unstable,
+                                   "infer_outlives_requirements",
+                                   "infer outlives requirements is an experimental feature",
+                                   cfg_fn!(infer_outlives_requirements))),
+
     ("wasm_custom_section", Whitelisted, Gated(Stability::Unstable,
                                  "wasm_custom_section",
                                  "attribute is currently unstable",
index 778394c9fc8ade7b40d11f7211ce79c5b799d5a5..5c392223f88b7dccc1a96e105fcd63dc4ac6c8da 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-tidy-linelength
+
 // Test that the outlives computation runs for now...
 
 #![feature(rustc_attrs)]
@@ -16,7 +18,7 @@
 // https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md#example-1-a-reference
 
 #[rustc_outlives]
-struct Direct<'a, T> { //~ ERROR 19:1: 21:2: [] [E0640]
+struct Direct<'a, T> { //~ ERROR 21:1: 23:2: [Binder(OutlivesPredicate(T, ReEarlyBound(0, 'a)))] [E0640]
     field: &'a T
 }
 
diff --git a/src/test/ui/feature-gate-infer_outlives_requirements.rs b/src/test/ui/feature-gate-infer_outlives_requirements.rs
new file mode 100644 (file)
index 0000000..01ccc50
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2015 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.
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+// Type T needs to outlive lifetime 'a.
+struct Foo<'a, T> {
+    bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
+}
+
+fn main() { }
diff --git a/src/test/ui/feature-gate-infer_outlives_requirements.stderr b/src/test/ui/feature-gate-infer_outlives_requirements.stderr
new file mode 100644 (file)
index 0000000..560e494
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/feature-gate-infer_outlives_requirements.rs:15:5
+   |
+LL | struct Foo<'a, T> {
+   |                - help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^
+   |
+note: ...so that the reference type `&'a [T]` does not outlive the data it points at
+  --> $DIR/feature-gate-infer_outlives_requirements.rs:15:5
+   |
+LL |     bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs b/src/test/ui/rfc-2093-infer-outlives/enum-pass.rs
new file mode 100644 (file)
index 0000000..8c7275b
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2018 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+
+// Type T needs to outlive lifetime 'a.
+enum Foo<'a, T> {
+
+    One(Bar<'a, T>)
+}
+
+// Type U needs to outlive lifetime 'b
+struct Bar<'b, U> {
+    field2: &'b U
+}
+
+
+
+// Type K needs to outlive lifetime 'c.
+enum Ying<'c, K> {
+    One(&'c Yang<K>)
+}
+
+struct Yang<V> {
+    field2: V
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/enum.rs b/src/test/ui/rfc-2093-infer-outlives/enum.rs
new file mode 100644 (file)
index 0000000..7d0427a
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2018 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.
+
+// ignore-tidy-linelength
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+// Type T needs to outlive lifetime 'a.
+enum Foo<'a, T> {
+
+    One(Bar<'a, T>)
+}
+
+// Type U needs to outlive lifetime 'b
+struct Bar<'b, U> {
+    field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+}
+
+
+
+// Type K needs to outlive lifetime 'c.
+enum Ying<'c, K> {
+    One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
+}
+
+struct Yang<V> {
+    field2: V
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/enum.stderr b/src/test/ui/rfc-2093-infer-outlives/enum.stderr
new file mode 100644 (file)
index 0000000..e6eaf9b
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0309]: the parameter type `U` may not live long enough
+  --> $DIR/enum.rs:23:5
+   |
+LL | struct Bar<'b, U> {
+   |                - help: consider adding an explicit lifetime bound `U: 'b`...
+LL |     field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^
+   |
+note: ...so that the reference type `&'b U` does not outlive the data it points at
+  --> $DIR/enum.rs:23:5
+   |
+LL |     field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^
+
+error[E0309]: the parameter type `K` may not live long enough
+  --> $DIR/enum.rs:30:9
+   |
+LL | enum Ying<'c, K> {
+   |               - help: consider adding an explicit lifetime bound `K: 'c`...
+LL |     One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
+   |         ^^^^^^^^^^^^
+   |
+note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at
+  --> $DIR/enum.rs:30:9
+   |
+LL |     One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
+   |         ^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-lifetime-pass.rs
new file mode 100644 (file)
index 0000000..da57838
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2015 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.
+
+// ignore-test
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+trait MakeRef<'a>: 'a {
+    type Type;
+}
+impl<'a, T> MakeRef<'a> for Vec<T>
+where T: 'a,
+{
+    type Type = &'a T;
+}
+// explicit-impl: T: 'a
+struct Foo<'a, T> {
+    foo: <Vec<T> as MakeRef<'a>>::Type,
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl-pass.rs
new file mode 100644 (file)
index 0000000..fd74fe3
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2015 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.
+
+// ignore-test
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+trait MakeRef<'a> {
+    type Type;
+}
+impl<'a, T> MakeRef<'a> for Vec<T>
+where T: 'a,
+{
+    type Type = &'a T;
+}
+// explicit-impl: T: 'a
+struct Foo<'a, T> {
+    foo: <Vec<T> as MakeRef<'a>>::Type,
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.rs
new file mode 100644 (file)
index 0000000..3a10087
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2015 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.
+
+// ignore-tidy-linelength
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+trait MakeRef<'a> {
+    type Type;
+}
+
+impl<'a, T> MakeRef<'a> for Vec<T>
+  where T: 'a
+{
+    type Type = &'a T;
+}
+
+// Type T needs to outlive lifetime 'a, as stated in impl.
+struct Foo<'a, T> {
+    foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309]
+}
+
+fn main() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-impl.stderr
new file mode 100644 (file)
index 0000000..498d66e
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/explicit-impl.rs:27:5
+   |
+LL | struct Foo<'a, T> {
+   |                - help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...so that the type `T` will meet its required lifetime bounds
+  --> $DIR/explicit-impl.rs:27:5
+   |
+LL |     foo: <Vec<T> as MakeRef<'a>>::Type //~ Error the parameter type `T` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-where-pass.rs
new file mode 100644 (file)
index 0000000..e51b5a1
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2015 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// explicit-where: infer U: 'b
+struct ExFoo<'b, U> {
+    bar: ExBar<'b, U>
+}
+struct ExBar<'a, T> where T: 'a {
+    x: &'a (),
+    y: T,
+}
+
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-where.rs
new file mode 100644 (file)
index 0000000..81734bf
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+// Type U needs to outlive lifetime 'b.
+struct Foo<'b, U> {
+    bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309]
+}
+
+struct Bar<'a, T> where T: 'a {
+    x: &'a (),
+    y: T,
+}
+
+fn main() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-where.stderr
new file mode 100644 (file)
index 0000000..436754c
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0309]: the parameter type `U` may not live long enough
+  --> $DIR/explicit-where.rs:15:5
+   |
+LL | struct Foo<'b, U> {
+   |                - help: consider adding an explicit lifetime bound `U: 'b`...
+LL |     bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^^^
+   |
+note: ...so that the type `U` will meet its required lifetime bounds
+  --> $DIR/explicit-where.rs:15:5
+   |
+LL |     bar: Bar<'b, U> //~ Error the parameter type `U` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs b/src/test/ui/rfc-2093-infer-outlives/multiple-regions-pass.rs
new file mode 100644 (file)
index 0000000..be686a8
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// multiple-regions: infer 'b: 'a
+struct MultiFoo<'a, 'b, T> {
+    x: &'a &'b T
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.rs
new file mode 100644 (file)
index 0000000..7ea1ce2
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2018 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.
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+// Lifetime 'b needs to outlive lifetime 'a
+struct Foo<'a,'b,T> {
+    x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491]
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr b/src/test/ui/rfc-2093-infer-outlives/multiple-regions.stderr
new file mode 100644 (file)
index 0000000..3722abd
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references
+  --> $DIR/multiple-regions.rs:15:5
+   |
+LL |     x: &'a &'b T //~ ERROR reference has a longer lifetime than the data it references [E0491]
+   |     ^^^^^^^^^^^^
+   |
+note: the pointer is valid for the lifetime 'a as defined on the struct at 14:1
+  --> $DIR/multiple-regions.rs:14:1
+   |
+LL | struct Foo<'a,'b,T> {
+   | ^^^^^^^^^^^^^^^^^^^
+note: but the referenced data is only valid for the lifetime 'b as defined on the struct at 14:1
+  --> $DIR/multiple-regions.rs:14:1
+   |
+LL | struct Foo<'a,'b,T> {
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0491`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs b/src/test/ui/rfc-2093-infer-outlives/nested-structs-pass.rs
new file mode 100644 (file)
index 0000000..0258145
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// nested-structs: infer U: 'b and therefore T: 'a
+struct NestFoo<'a, T> {
+    field1: NestBar<'a, T>
+}
+struct NestBar<'b, U> {
+    field2: &'b U
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs b/src/test/ui/rfc-2093-infer-outlives/nested-structs.rs
new file mode 100644 (file)
index 0000000..7c444db
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2018 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.
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+
+// Type T needs to outlive lifetime 'a. This is not reported due to
+// a compilation error in Bar.
+struct Foo<'a, T> {
+    field1: Bar<'a, T>
+}
+
+// Type U needs to outlive lifetime 'b
+struct Bar<'b, U> {
+    field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-structs.stderr
new file mode 100644 (file)
index 0000000..94d6cbd
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0309]: the parameter type `U` may not live long enough
+  --> $DIR/nested-structs.rs:22:5
+   |
+LL | struct Bar<'b, U> {
+   |                - help: consider adding an explicit lifetime bound `U: 'b`...
+LL |     field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^
+   |
+note: ...so that the reference type `&'b U` does not outlive the data it points at
+  --> $DIR/nested-structs.rs:22:5
+   |
+LL |     field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs b/src/test/ui/rfc-2093-infer-outlives/projections-pass.rs
new file mode 100644 (file)
index 0000000..1234e27
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// projections: infer <Iterator>::Item: 'a
+struct ProjFoo<'a, T: Iterator> {
+    bar: &'a T::Item
+}
+
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.rs b/src/test/ui/rfc-2093-infer-outlives/projections.rs
new file mode 100644 (file)
index 0000000..f6a557c
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2015 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.
+
+// ignore-tidy-linelength
+
+// Needs an explicit where clause stating outlives condition. RFC 2093
+
+// Associated type <Iterator>::Item  needs to outlives lifetime 'a.
+struct Foo<'a, T: Iterator> {
+    bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309]
+}
+
+fn main() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/projections.stderr b/src/test/ui/rfc-2093-infer-outlives/projections.stderr
new file mode 100644 (file)
index 0000000..9969cf4
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough
+  --> $DIR/projections.rs:17:5
+   |
+LL |     bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: 'a`...
+note: ...so that the reference type `&'a <T as std::iter::Iterator>::Item` does not outlive the data it points at
+  --> $DIR/projections.rs:17:5
+   |
+LL |     bar: &'a T::Item //~ Error the associated type `<T as std::iter::Iterator>::Item` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs b/src/test/ui/rfc-2093-infer-outlives/reference-pass.rs
new file mode 100644 (file)
index 0000000..f357685
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+// Outlives requirementes are inferred (RFC 2093)
+
+// reference: infer T: 'a
+struct RefFoo<'a, T> {
+    bar: &'a [T]
+}
+
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.rs b/src/test/ui/rfc-2093-infer-outlives/reference.rs
new file mode 100644 (file)
index 0000000..01ccc50
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2015 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.
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+// Type T needs to outlive lifetime 'a.
+struct Foo<'a, T> {
+    bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
+}
+
+fn main() { }
diff --git a/src/test/ui/rfc-2093-infer-outlives/reference.stderr b/src/test/ui/rfc-2093-infer-outlives/reference.stderr
new file mode 100644 (file)
index 0000000..7236bd5
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/reference.rs:15:5
+   |
+LL | struct Foo<'a, T> {
+   |                - help: consider adding an explicit lifetime bound `T: 'a`...
+LL |     bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^
+   |
+note: ...so that the reference type `&'a [T]` does not outlive the data it points at
+  --> $DIR/reference.rs:15:5
+   |
+LL |     bar: &'a [T] //~ ERROR the parameter type `T` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/rfc-2093-infer-outlives/union-pass.rs b/src/test/ui/rfc-2093-infer-outlives/union-pass.rs
new file mode 100644 (file)
index 0000000..b4a6134
--- /dev/null
@@ -0,0 +1,39 @@
+// Copyright 2018 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.
+
+// must-compile-successfully
+
+#![feature(infer_outlives_requirements)]
+#![feature(untagged_unions)]
+#![allow(unions_with_drop_fields)]
+
+// Type T needs to outlive lifetime 'a. This is not reported due to
+// a compilation error in Bar.
+union Foo<'a, T> {
+    field1: Bar<'a, T>
+}
+
+// Type U needs to outlive lifetime 'b
+union Bar<'b, U> {
+    field2: &'b U
+}
+
+
+// Type K needs to outlive lifetime 'c.
+union Ying<'c, K> {
+    field1: &'c Yang<K>
+}
+
+union Yang<V> {
+    field2: V
+}
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/union.rs b/src/test/ui/rfc-2093-infer-outlives/union.rs
new file mode 100644 (file)
index 0000000..36b1dcc
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2018 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.
+
+// ignore-tidy-linelength
+
+// Needs an explicit where clause stating outlives condition. (RFC 2093)
+
+#![feature(untagged_unions)]
+
+// Type T needs to outlive lifetime 'a. This is not reported due to
+// a compilation error in Bar.
+union Foo<'a, T> {
+    field1: Bar<'a, T>
+}
+
+// Type U needs to outlive lifetime 'b
+union Bar<'b, U> {
+    field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309]
+}
+
+
+// Type K needs to outlive lifetime 'c.
+union Ying<'c, K> {
+    field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309]
+}
+
+union Yang<V> {
+    field2: V
+}
+
+
+fn main() {}
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/union.stderr b/src/test/ui/rfc-2093-infer-outlives/union.stderr
new file mode 100644 (file)
index 0000000..cd13c42
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0309]: the parameter type `U` may not live long enough
+  --> $DIR/union.rs:25:5
+   |
+LL | union Bar<'b, U> {
+   |               - help: consider adding an explicit lifetime bound `U: 'b`...
+LL |     field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^
+   |
+note: ...so that the reference type `&'b U` does not outlive the data it points at
+  --> $DIR/union.rs:25:5
+   |
+LL |     field2: &'b U //~ ERROR 25:5: 25:18: the parameter type `U` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^
+
+error[E0309]: the parameter type `K` may not live long enough
+  --> $DIR/union.rs:31:5
+   |
+LL | union Ying<'c, K> {
+   |                - help: consider adding an explicit lifetime bound `K: 'c`...
+LL |     field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at
+  --> $DIR/union.rs:31:5
+   |
+LL |     field1: &'c Yang<K> //~ ERROR 31:5: 31:24: the parameter type `K` may not live long enough [E0309]
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.