about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-02-24 21:54:52 +0000
committerbors <bors@rust-lang.org>2021-02-24 21:54:52 +0000
commit1fdadbf13aecd190b277ea2aa1b125d2ed986d55 (patch)
treeaeafe7efa86c189ea34cda3ef8d91720d51cd24d
parenta8486b64b0c87dabd045453b6c81500015d122d6 (diff)
parent42cbfd63460a752ec5e57e88a180d7e3268521a9 (diff)
downloadrust-1fdadbf13aecd190b277ea2aa1b125d2ed986d55.tar.gz
rust-1fdadbf13aecd190b277ea2aa1b125d2ed986d55.zip
Auto merge of #82159 - BoxyUwU:uwu, r=varkor
Use correct param_env in conservative_is_privately_uninhabited

cc `@lcnr`
r? `@varkor` since this is your FIXME that was removed ^^
-rw-r--r--compiler/rustc_middle/src/query/mod.rs10
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs13
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs47
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs5
-rw-r--r--compiler/rustc_mir/src/transform/generator.rs6
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs2
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs58
-rw-r--r--src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs27
-rw-r--r--src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs20
9 files changed, 131 insertions, 57 deletions
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4207e2dea34..a1c45c0b35c 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1603,4 +1603,14 @@ rustc_queries! {
     query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
         desc { "normalizing opaque types in {:?}", key }
     }
+
+    /// Checks whether a type is definitely uninhabited. This is
+    /// conservative: for some types that are uninhabited we return `false`,
+    /// but we only return `true` for types that are definitely uninhabited.
+    /// `ty.conservative_is_privately_uninhabited` implies that any value of type `ty`
+    /// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero
+    /// size, to account for partial initialisation. See #49298 for details.)
+    query conservative_is_privately_uninhabited(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+        desc { "conservatively checking if {:?} is privately uninhabited", key }
+    }
 }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 12dcb95187c..725c144257c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -232,7 +232,7 @@ fn layout_raw<'tcx>(
             let layout = cx.layout_raw_uncached(ty);
             // Type-level uninhabitedness should always imply ABI uninhabitedness.
             if let Ok(layout) = layout {
-                if ty.conservative_is_privately_uninhabited(tcx) {
+                if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
                     assert!(layout.abi.is_uninhabited());
                 }
             }
@@ -584,11 +584,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 let size =
                     element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?;
 
-                let abi = if count != 0 && ty.conservative_is_privately_uninhabited(tcx) {
-                    Abi::Uninhabited
-                } else {
-                    Abi::Aggregate { sized: true }
-                };
+                let abi =
+                    if count != 0 && tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
+                        Abi::Uninhabited
+                    } else {
+                        Abi::Aggregate { sized: true }
+                    };
 
                 let largest_niche = if count != 0 { element.largest_niche.clone() } else { None };
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index bbf64c69d83..a7bcc198f02 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1697,53 +1697,6 @@ impl<'tcx> TyS<'tcx> {
         matches!(self.kind(), Never)
     }
 
-    /// Checks whether a type is definitely uninhabited. This is
-    /// conservative: for some types that are uninhabited we return `false`,
-    /// but we only return `true` for types that are definitely uninhabited.
-    /// `ty.conservative_is_privately_uninhabited` implies that any value of type `ty`
-    /// will be `Abi::Uninhabited`. (Note that uninhabited types may have nonzero
-    /// size, to account for partial initialisation. See #49298 for details.)
-    pub fn conservative_is_privately_uninhabited(&self, tcx: TyCtxt<'tcx>) -> bool {
-        // FIXME(varkor): we can make this less conversative by substituting concrete
-        // type arguments.
-        match self.kind() {
-            ty::Never => true,
-            ty::Adt(def, _) if def.is_union() => {
-                // For now, `union`s are never considered uninhabited.
-                false
-            }
-            ty::Adt(def, _) => {
-                // Any ADT is uninhabited if either:
-                // (a) It has no variants (i.e. an empty `enum`);
-                // (b) Each of its variants (a single one in the case of a `struct`) has at least
-                //     one uninhabited field.
-                def.variants.iter().all(|var| {
-                    var.fields.iter().any(|field| {
-                        tcx.type_of(field.did).conservative_is_privately_uninhabited(tcx)
-                    })
-                })
-            }
-            ty::Tuple(..) => {
-                self.tuple_fields().any(|ty| ty.conservative_is_privately_uninhabited(tcx))
-            }
-            ty::Array(ty, len) => {
-                match len.try_eval_usize(tcx, ParamEnv::empty()) {
-                    Some(0) | None => false,
-                    // If the array is definitely non-empty, it's uninhabited if
-                    // the type of its elements is uninhabited.
-                    Some(1..) => ty.conservative_is_privately_uninhabited(tcx),
-                }
-            }
-            ty::Ref(..) => {
-                // References to uninitialised memory is valid for any type, including
-                // uninhabited types, in unsafe code, so we treat all references as
-                // inhabited.
-                false
-            }
-            _ => false,
-        }
-    }
-
     #[inline]
     pub fn is_primitive(&self) -> bool {
         self.kind().is_primitive()
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index f64848e694c..aa946fdafa9 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -1734,7 +1734,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 }
             }
             None => {
-                if !sig.output().conservative_is_privately_uninhabited(self.tcx()) {
+                if !self
+                    .tcx()
+                    .conservative_is_privately_uninhabited(self.param_env.and(sig.output()))
+                {
                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
                 }
             }
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index dc413f8dd2d..9f996e84528 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -1007,9 +1007,9 @@ fn insert_panic_block<'tcx>(
     assert_block
 }
 
-fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
+fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
     // Returning from a function with an uninhabited return type is undefined behavior.
-    if body.return_ty().conservative_is_privately_uninhabited(tcx) {
+    if tcx.conservative_is_privately_uninhabited(param_env.and(body.return_ty())) {
         return false;
     }
 
@@ -1320,7 +1320,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
         // `storage_liveness` tells us which locals have live storage at suspension points
         let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
 
-        let can_return = can_return(tcx, body);
+        let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
 
         // Run the transformation which converts Places from Local to generator struct
         // accesses for locals in `remap`.
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 904c0062a92..aa5d3388401 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -5,6 +5,8 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 76d27c29226..29f1761b84d 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -481,6 +481,63 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
     fn_like.asyncness()
 }
 
+/// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
+#[instrument(level = "debug", skip(tcx))]
+pub fn conservative_is_privately_uninhabited_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env_and: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> bool {
+    let (param_env, ty) = param_env_and.into_parts();
+    match ty.kind() {
+        ty::Never => {
+            debug!("ty::Never =>");
+            true
+        }
+        ty::Adt(def, _) if def.is_union() => {
+            debug!("ty::Adt(def, _) if def.is_union() =>");
+            // For now, `union`s are never considered uninhabited.
+            false
+        }
+        ty::Adt(def, substs) => {
+            debug!("ty::Adt(def, _) if def.is_not_union() =>");
+            // Any ADT is uninhabited if either:
+            // (a) It has no variants (i.e. an empty `enum`);
+            // (b) Each of its variants (a single one in the case of a `struct`) has at least
+            //     one uninhabited field.
+            def.variants.iter().all(|var| {
+                var.fields.iter().any(|field| {
+                    let ty = tcx.type_of(field.did).subst(tcx, substs);
+                    tcx.conservative_is_privately_uninhabited(param_env.and(ty))
+                })
+            })
+        }
+        ty::Tuple(..) => {
+            debug!("ty::Tuple(..) =>");
+            ty.tuple_fields().any(|ty| tcx.conservative_is_privately_uninhabited(param_env.and(ty)))
+        }
+        ty::Array(ty, len) => {
+            debug!("ty::Array(ty, len) =>");
+            match len.try_eval_usize(tcx, param_env) {
+                Some(0) | None => false,
+                // If the array is definitely non-empty, it's uninhabited if
+                // the type of its elements is uninhabited.
+                Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(ty)),
+            }
+        }
+        ty::Ref(..) => {
+            debug!("ty::Ref(..) =>");
+            // References to uninitialised memory is valid for any type, including
+            // uninhabited types, in unsafe code, so we treat all references as
+            // inhabited.
+            false
+        }
+        _ => {
+            debug!("_ =>");
+            false
+        }
+    }
+}
+
 pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         asyncness,
@@ -498,6 +555,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
+        conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw,
         ..*providers
     };
 }
diff --git a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs
new file mode 100644
index 00000000000..d1bffae0d94
--- /dev/null
+++ b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs
@@ -0,0 +1,27 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+// This tests that the `conservative_is_privately_uninhabited` fn doesn't cause
+// ICEs by trying to evaluate `T::ASSOC` with an incorrect `ParamEnv`.
+
+trait Foo {
+    const ASSOC: usize = 1;
+}
+
+struct Iced<T: Foo>(T, [(); T::ASSOC])
+where
+    [(); T::ASSOC]: ;
+
+impl Foo for u32 {}
+
+fn foo<T: Foo>()
+where
+    [(); T::ASSOC]: ,
+{
+    let _iced: Iced<T> = return;
+}
+
+fn main() {
+    foo::<u32>();
+}
diff --git a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs
new file mode 100644
index 00000000000..96dbac1fbef
--- /dev/null
+++ b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs
@@ -0,0 +1,20 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+// This tests that the `conservative_is_privately_uninhabited` fn doesn't cause
+// ICEs by trying to evaluate `T::ASSOC` with an incorrect `ParamEnv`.
+
+trait Foo {
+    const ASSOC: usize = 1;
+}
+
+struct Iced<T: Foo>(T, [(); T::ASSOC])
+where
+    [(); T::ASSOC]: ;
+
+impl Foo for u32 {}
+
+fn main() {
+    let _iced: Iced<u32> = return;
+}