about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs19
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs11
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs1
-rw-r--r--compiler/rustc_middle/src/mir/abstract_const.rs2
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs20
-rw-r--r--compiler/rustc_middle/src/ty/query/on_disk_cache.rs6
-rw-r--r--compiler/rustc_privacy/src/lib.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs9
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs15
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs13
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr36
14 files changed, 157 insertions, 2 deletions
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 43d76e9fdb4..a2e2cf1ca02 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -562,6 +562,12 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
     }
 }
 
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+        ty::codec::RefDecodable::decode(d)
+    }
+}
+
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
     fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
         ty::codec::RefDecodable::decode(d)
@@ -1191,6 +1197,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .decode((self, tcx))
     }
 
+    fn get_mir_abstract_const(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        id: DefIndex,
+    ) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
+        self.root
+            .tables
+            .mir_abstract_consts
+            .get(self, id)
+            .filter(|_| !self.is_proc_macro(id))
+            .map_or(None, |v| Some(v.decode((self, tcx))))
+    }
+
     fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
         self.root
             .tables
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 94abfac19c6..d4f577a7d1b 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -112,6 +112,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     }
     optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
     promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
+    mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
     unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
     mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
     fn_sig => { cdata.fn_sig(def_id.index, tcx) }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 1e313b7edfc..eb091d86b82 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -321,6 +321,12 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> {
     }
 }
 
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
+        (**self).encode(s)
+    }
+}
+
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
     fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
         (**self).encode(s)
@@ -1109,6 +1115,11 @@ impl EncodeContext<'a, 'tcx> {
             if !unused.is_empty() {
                 record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
             }
+
+            let abstract_const = self.tcx.mir_abstract_const(def_id);
+            if let Some(abstract_const) = abstract_const {
+                record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
+            }
         }
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 1ba5962d119..ba540c94411 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -284,6 +284,7 @@ define_tables! {
     super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
     mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
+    mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
     unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
     // `def_keys` and `def_path_hashes` represent a lazy version of a
     // `DefPathTable`. This allows us to avoid deserializing an entire
diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs
index 8d215c5a521..b85f1e6e5de 100644
--- a/compiler/rustc_middle/src/mir/abstract_const.rs
+++ b/compiler/rustc_middle/src/mir/abstract_const.rs
@@ -11,7 +11,7 @@ rustc_index::newtype_index! {
 }
 
 /// A node of an `AbstractConst`.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 pub enum Node<'tcx> {
     Leaf(&'tcx ty::Const<'tcx>),
     Binop(mir::BinOp, NodeId, NodeId),
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index e2e5f08462f..8ea34f9161a 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -357,6 +357,26 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>,
     }
 }
 
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] {
+    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+        Ok(decoder.tcx().arena.alloc_from_iter(
+            (0..decoder.read_usize()?)
+                .map(|_| Decodable::decode(decoder))
+                .collect::<Result<Vec<_>, _>>()?,
+        ))
+    }
+}
+
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] {
+    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+        Ok(decoder.tcx().arena.alloc_from_iter(
+            (0..decoder.read_usize()?)
+                .map(|_| Decodable::decode(decoder))
+                .collect::<Result<Vec<_>, _>>()?,
+        ))
+    }
+}
+
 impl_decodable_via_ref! {
     &'tcx ty::TypeckResults<'tcx>,
     &'tcx ty::List<Ty<'tcx>>,
diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
index dcfb8d31430..b0c48a860eb 100644
--- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
@@ -760,6 +760,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
     }
 }
 
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+        RefDecodable::decode(d)
+    }
+}
+
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
         RefDecodable::decode(d)
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 03cc718b899..1a95992ed83 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -97,6 +97,15 @@ where
                 ty.visit_with(self)
             }
             ty::PredicateAtom::RegionOutlives(..) => false,
+            ty::PredicateAtom::ConstEvaluatable(..)
+                if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
+            {
+                // FIXME(const_evaluatable_checked): If the constant used here depends on a
+                // private function we may have to do something here...
+                //
+                // For now, let's just pretend that everything is fine.
+                false
+            }
             _ => bug!("unexpected predicate: {:?}", predicate),
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 50cc2afb89c..1a5139d34d3 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -142,6 +142,12 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
             return None;
         }
 
+        // We don't have to look at concrete constants, as we
+        // can just evaluate them.
+        if !body.is_polymorphic {
+            return None;
+        }
+
         Some(AbstractConstBuilder {
             tcx,
             body,
@@ -304,6 +310,15 @@ pub(super) fn mir_abstract_const<'tcx>(
     def: ty::WithOptConstParam<LocalDefId>,
 ) -> Option<&'tcx [Node<'tcx>]> {
     if tcx.features().const_evaluatable_checked {
+        match tcx.def_kind(def.did) {
+            // FIXME(const_evaluatable_checked): We currently only do this for anonymous constants,
+            // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether
+            // we want to look into them or treat them as opaque projections.
+            //
+            // Right now we do neither of that and simply always fail to unify them.
+            DefKind::AnonConst => (),
+            _ => return None,
+        }
         let body = tcx.mir_const(def).borrow();
         AbstractConstBuilder::new(tcx, &body)?.build()
     } else {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 098336453bc..79495ba7f9b 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -553,7 +553,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
         type_implements_trait,
         subst_and_check_impossible_predicates,
         mir_abstract_const: |tcx, def_id| {
-            let def_id = def_id.as_local()?; // We do not store failed AbstractConst's.
+            let def_id = def_id.expect_local();
             if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
                 tcx.mir_abstract_const_of_const_arg(def)
             } else {
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs b/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs
new file mode 100644
index 00000000000..9745dfed460
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs
@@ -0,0 +1,9 @@
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+pub fn test1<T>() -> [u8; std::mem::size_of::<T>() - 1]
+where
+    [u8; std::mem::size_of::<T>() - 1]: Sized,
+{
+    [0; std::mem::size_of::<T>() - 1]
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs
new file mode 100644
index 00000000000..53b23784387
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs
@@ -0,0 +1,15 @@
+// aux-build:const_evaluatable_lib.rs
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+extern crate const_evaluatable_lib;
+
+fn user<T>() where [u8; std::mem::size_of::<T>() - 1]: Sized {
+    assert_eq!(const_evaluatable_lib::test1::<T>(), [0; std::mem::size_of::<T>() - 1]);
+}
+
+fn main() {
+    assert_eq!(const_evaluatable_lib::test1::<u32>(), [0; 3]);
+    user::<u32>();
+    user::<u64>();
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs
new file mode 100644
index 00000000000..22369923329
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs
@@ -0,0 +1,13 @@
+// aux-build:const_evaluatable_lib.rs
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+extern crate const_evaluatable_lib;
+
+fn user<T>() {
+    let _ = const_evaluatable_lib::test1::<T>();
+    //~^ ERROR constant expression depends
+    //~| ERROR constant expression depends
+    //~| ERROR constant expression depends
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr
new file mode 100644
index 00000000000..63abb782b93
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr
@@ -0,0 +1,36 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/cross_crate_predicate.rs:7:13
+   |
+LL |     let _ = const_evaluatable_lib::test1::<T>();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
+   |
+LL |     [u8; std::mem::size_of::<T>() - 1]: Sized,
+   |                                         ----- required by this bound in `test1`
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/cross_crate_predicate.rs:7:13
+   |
+LL |     let _ = const_evaluatable_lib::test1::<T>();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | 
+  ::: $DIR/auxiliary/const_evaluatable_lib.rs:6:41
+   |
+LL |     [u8; std::mem::size_of::<T>() - 1]: Sized,
+   |                                         ----- required by this bound in `test1::{{constant}}#1`
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+  --> $DIR/cross_crate_predicate.rs:7:13
+   |
+LL |     let _ = const_evaluatable_lib::test1::<T>();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 3 previous errors
+