about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan MacKenzie <ecstaticmorse@gmail.com>2020-03-16 10:45:39 -0700
committerDylan MacKenzie <ecstaticmorse@gmail.com>2020-04-28 14:58:50 -0700
commit6b54829b784bb5e16354fd0e63c1de4e6238800c (patch)
tree1045d8aeedc77d3c6d2b6b722f0059843b99d8d6
parent0850c3bbb89c08523136a57e89cd3d84f407d2bf (diff)
downloadrust-6b54829b784bb5e16354fd0e63c1de4e6238800c.tar.gz
rust-6b54829b784bb5e16354fd0e63c1de4e6238800c.zip
Add `CustomEq` qualif
-rw-r--r--src/librustc_middle/mir/query.rs1
-rw-r--r--src/librustc_mir/transform/check_consts/qualifs.rs36
-rw-r--r--src/librustc_mir/transform/check_consts/validation.rs28
3 files changed, 64 insertions, 1 deletions
diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs
index 8c81f5227d2..95a28df99aa 100644
--- a/src/librustc_middle/mir/query.rs
+++ b/src/librustc_middle/mir/query.rs
@@ -80,6 +80,7 @@ pub struct BorrowCheckResult<'tcx> {
 pub struct ConstQualifs {
     pub has_mut_interior: bool,
     pub needs_drop: bool,
+    pub custom_eq: bool,
 }
 
 /// After we borrow check a closure, we are left with various
diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs
index 04bd632553e..fc6860b40e8 100644
--- a/src/librustc_mir/transform/check_consts/qualifs.rs
+++ b/src/librustc_mir/transform/check_consts/qualifs.rs
@@ -2,9 +2,11 @@
 //!
 //! See the `Qualif` trait for more info.
 
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
 use rustc_span::DUMMY_SP;
+use rustc_trait_selection::traits;
 
 use super::ConstCx;
 
@@ -12,6 +14,7 @@ pub fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> ConstQualifs
     ConstQualifs {
         has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
         needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
+        custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
     }
 }
 
@@ -108,6 +111,39 @@ impl Qualif for NeedsDrop {
     }
 }
 
+/// A constant that cannot be used as part of a pattern in a `match` expression.
+pub struct CustomEq;
+
+impl Qualif for CustomEq {
+    const ANALYSIS_NAME: &'static str = "flow_custom_eq";
+
+    fn in_qualifs(qualifs: &ConstQualifs) -> bool {
+        qualifs.custom_eq
+    }
+
+    fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+        // If *any* component of a composite data type does not implement `Structural{Partial,}Eq`,
+        // we know that at least some values of that type are not structural-match. I say "some"
+        // because that component may be part of an enum variant (e.g.,
+        // `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
+        // structural-match (`Option::None`).
+        let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap());
+        traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some()
+    }
+
+    fn in_adt_inherently(
+        cx: &ConstCx<'_, 'tcx>,
+        adt: &'tcx AdtDef,
+        substs: SubstsRef<'tcx>,
+    ) -> bool {
+        let ty = cx.tcx.mk_ty(ty::Adt(adt, substs));
+        let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id.as_local().unwrap());
+        cx.tcx
+            .infer_ctxt()
+            .enter(|infcx| !traits::type_marked_structural(id, cx.body.span, &infcx, ty))
+    }
+}
+
 // FIXME: Use `mir::visit::Visitor` for the `in_*` functions if/when it supports early return.
 
 /// Returns `true` if this `Rvalue` contains qualif `Q`.
diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs
index b87429199ec..c5938426f61 100644
--- a/src/librustc_mir/transform/check_consts/validation.rs
+++ b/src/librustc_mir/transform/check_consts/validation.rs
@@ -17,7 +17,7 @@ use std::borrow::Cow;
 use std::ops::Deref;
 
 use super::ops::{self, NonConstOp};
-use super::qualifs::{self, HasMutInterior, NeedsDrop};
+use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop};
 use super::resolver::FlowSensitiveAnalysis;
 use super::{is_lang_panic_fn, ConstCx, ConstKind, Qualif};
 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
@@ -142,9 +142,35 @@ impl Qualifs<'mir, 'tcx> {
 
         let return_loc = ccx.body.terminator_loc(return_block);
 
+        let custom_eq = match ccx.const_kind() {
+            // We don't care whether a `const fn` returns a value that is not structurally
+            // matchable. Functions calls are opaque and always use type-based qualification, so
+            // this value should never be used.
+            ConstKind::ConstFn => true,
+
+            // If we know that all values of the return type are structurally matchable, there's no
+            // need to run dataflow.
+            ConstKind::Const | ConstKind::Static | ConstKind::StaticMut
+                if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) =>
+            {
+                false
+            }
+
+            ConstKind::Const | ConstKind::Static | ConstKind::StaticMut => {
+                let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
+                    .into_engine(ccx.tcx, &ccx.body, ccx.def_id)
+                    .iterate_to_fixpoint()
+                    .into_results_cursor(&ccx.body);
+
+                cursor.seek_after(return_loc);
+                cursor.contains(RETURN_PLACE)
+            }
+        };
+
         ConstQualifs {
             needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
             has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
+            custom_eq,
         }
     }
 }