about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-06-12 14:33:50 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-06-26 10:59:40 -0400
commit1acffada44df88112d23941cd96ea120ea4b8daf (patch)
tree3360a580e1ba51e594cd057d092c32f0f358fe59 /src
parent265552258048b2008975d98de75c7e536bc4f894 (diff)
downloadrust-1acffada44df88112d23941cd96ea120ea4b8daf.tar.gz
rust-1acffada44df88112d23941cd96ea120ea4b8daf.zip
introduce `canonicalize_hr_query_hack`
As the comment explains, this is needed to prevent subtype from going
awry in higher-ranked cases, due to #33684. The proper fix here is
introducing universes (#48536).
Diffstat (limited to 'src')
-rw-r--r--src/librustc/infer/canonical/canonicalizer.rs79
-rw-r--r--src/librustc/traits/query/type_op/mod.rs6
2 files changed, 74 insertions, 11 deletions
diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs
index aaa5a01e501..8b67f04e020 100644
--- a/src/librustc/infer/canonical/canonicalizer.rs
+++ b/src/librustc/infer/canonical/canonicalizer.rs
@@ -61,7 +61,10 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
             value,
             Some(self),
             self.tcx,
-            CanonicalizeAllFreeRegions(true),
+            CanonicalizeRegionMode {
+                static_region: true,
+                other_free_regions: true,
+            },
         )
     }
 
@@ -101,7 +104,43 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
             value,
             Some(self),
             self.tcx,
-            CanonicalizeAllFreeRegions(false),
+            CanonicalizeRegionMode {
+                static_region: false,
+                other_free_regions: false,
+            },
+        )
+    }
+
+    /// A hacky variant of `canonicalize_query` that does not
+    /// canonicalize `'static`.  Unfortunately, the existing leak
+    /// check treaks `'static` differently in some cases (see also
+    /// #33684), so if we are performing an operation that may need to
+    /// prove "leak-check" related things, we leave `'static`
+    /// alone.
+    ///
+    /// FIXME(#48536) -- once we have universes, we can remove this and just use
+    /// `canonicalize_query`.
+    pub fn canonicalize_hr_query_hack<V>(
+        &self,
+        value: &V,
+    ) -> (Canonicalized<'gcx, V>, CanonicalVarValues<'tcx>)
+    where
+        V: TypeFoldable<'tcx> + Lift<'gcx>,
+    {
+        self.tcx
+            .sess
+            .perf_stats
+            .queries_canonicalized
+            .fetch_add(1, Ordering::Relaxed);
+
+        Canonicalizer::canonicalize(
+            value,
+            Some(self),
+            self.tcx,
+            CanonicalizeRegionMode {
+                static_region: false,
+                other_free_regions: true,
+            },
         )
     }
 }
@@ -110,7 +149,16 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
 /// a canonical var. This is used to make queries as generic as
 /// possible. For example, the query `F: Foo<'static>` would be
 /// canonicalized to `F: Foo<'0>`.
-struct CanonicalizeAllFreeRegions(pub bool);
+struct CanonicalizeRegionMode {
+    static_region: bool,
+    other_free_regions: bool,
+}
+
+impl CanonicalizeRegionMode {
+    fn any(&self) -> bool {
+        self.static_region || self.other_free_regions
+    }
+}
 
 struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>,
@@ -118,7 +166,7 @@ struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     variables: IndexVec<CanonicalVar, CanonicalVarInfo>,
     indices: FxHashMap<Kind<'tcx>, CanonicalVar>,
     var_values: IndexVec<CanonicalVar, Kind<'tcx>>,
-    canonicalize_all_free_regions: CanonicalizeAllFreeRegions,
+    canonicalize_region_mode: CanonicalizeRegionMode,
     needs_canonical_flags: TypeFlags,
 }
 
@@ -152,14 +200,25 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx>
                 self.tcx().mk_region(ty::ReCanonical(cvar))
             }
 
-            ty::ReStatic
-            | ty::ReEarlyBound(..)
+            ty::ReStatic => {
+                if self.canonicalize_region_mode.static_region {
+                    let info = CanonicalVarInfo {
+                        kind: CanonicalVarKind::Region,
+                    };
+                    let cvar = self.canonical_var(info, r.into());
+                    self.tcx().mk_region(ty::ReCanonical(cvar))
+                } else {
+                    r
+                }
+            }
+
+            ty::ReEarlyBound(..)
             | ty::ReFree(_)
             | ty::ReScope(_)
             | ty::ReSkolemized(..)
             | ty::ReEmpty
             | ty::ReErased => {
-                if self.canonicalize_all_free_regions.0 {
+                if self.canonicalize_region_mode.other_free_regions {
                     let info = CanonicalVarInfo {
                         kind: CanonicalVarKind::Region,
                     };
@@ -235,7 +294,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
         value: &V,
         infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>,
         tcx: TyCtxt<'cx, 'gcx, 'tcx>,
-        canonicalize_all_free_regions: CanonicalizeAllFreeRegions,
+        canonicalize_region_mode: CanonicalizeRegionMode,
     ) -> (Canonicalized<'gcx, V>, CanonicalVarValues<'tcx>)
     where
         V: TypeFoldable<'tcx> + Lift<'gcx>,
@@ -246,7 +305,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
             value,
         );
 
-        let needs_canonical_flags = if canonicalize_all_free_regions.0 {
+        let needs_canonical_flags = if canonicalize_region_mode.any() {
             TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX
         } else {
             TypeFlags::KEEP_IN_LOCAL_TCX
@@ -270,7 +329,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
         let mut canonicalizer = Canonicalizer {
             infcx,
             tcx,
-            canonicalize_all_free_regions,
+            canonicalize_region_mode,
             needs_canonical_flags,
             variables: IndexVec::default(),
             indices: FxHashMap::default(),
diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs
index 0028aaa4044..6436e75158e 100644
--- a/src/librustc/traits/query/type_op/mod.rs
+++ b/src/librustc/traits/query/type_op/mod.rs
@@ -132,7 +132,11 @@ where
     fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
         let param_env = self.param_env();
 
-        let (canonical_self, canonical_var_values) = infcx.canonicalize_query(&self);
+        // FIXME(#33684) -- We need to use
+        // `canonicalize_hr_query_hack` here because of things like
+        // the subtype query, which go awry around `'static`
+        // otherwise.
+        let (canonical_self, canonical_var_values) = infcx.canonicalize_hr_query_hack(&self);
         let canonical_result = Q::perform_query(infcx.tcx, canonical_self);
 
         // FIXME: This is not the most efficient setup. The