mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
support const_evaluatable_checked across crate boundaries
This commit is contained in:
parent
82ebbd7d6b
commit
30ff1ef3d0
@ -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)] {
|
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||||
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
|
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
|
||||||
ty::codec::RefDecodable::decode(d)
|
ty::codec::RefDecodable::decode(d)
|
||||||
@ -1191,6 +1197,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||||||
.decode((self, tcx))
|
.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> {
|
fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
|
||||||
self.root
|
self.root
|
||||||
.tables
|
.tables
|
||||||
|
@ -112,6 +112,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
|||||||
}
|
}
|
||||||
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
|
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)) }
|
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) }
|
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
|
||||||
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
|
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
|
||||||
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
|
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
|
||||||
|
@ -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)] {
|
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||||
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
|
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
|
||||||
(**self).encode(s)
|
(**self).encode(s)
|
||||||
@ -1109,6 +1115,11 @@ impl EncodeContext<'a, 'tcx> {
|
|||||||
if !unused.is_empty() {
|
if !unused.is_empty() {
|
||||||
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +284,7 @@ define_tables! {
|
|||||||
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
|
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
|
||||||
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
|
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
|
||||||
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, 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>>>,
|
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
|
||||||
// `def_keys` and `def_path_hashes` represent a lazy version of a
|
// `def_keys` and `def_path_hashes` represent a lazy version of a
|
||||||
// `DefPathTable`. This allows us to avoid deserializing an entire
|
// `DefPathTable`. This allows us to avoid deserializing an entire
|
||||||
|
@ -11,7 +11,7 @@ rustc_index::newtype_index! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A node of an `AbstractConst`.
|
/// 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> {
|
pub enum Node<'tcx> {
|
||||||
Leaf(&'tcx ty::Const<'tcx>),
|
Leaf(&'tcx ty::Const<'tcx>),
|
||||||
Binop(mir::BinOp, NodeId, NodeId),
|
Binop(mir::BinOp, NodeId, NodeId),
|
||||||
|
@ -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! {
|
impl_decodable_via_ref! {
|
||||||
&'tcx ty::TypeckResults<'tcx>,
|
&'tcx ty::TypeckResults<'tcx>,
|
||||||
&'tcx ty::List<Ty<'tcx>>,
|
&'tcx ty::List<Ty<'tcx>>,
|
||||||
|
@ -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)] {
|
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
|
||||||
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
|
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
|
||||||
RefDecodable::decode(d)
|
RefDecodable::decode(d)
|
||||||
|
@ -97,6 +97,15 @@ where
|
|||||||
ty.visit_with(self)
|
ty.visit_with(self)
|
||||||
}
|
}
|
||||||
ty::PredicateAtom::RegionOutlives(..) => false,
|
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),
|
_ => bug!("unexpected predicate: {:?}", predicate),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,12 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||||||
return None;
|
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 {
|
Some(AbstractConstBuilder {
|
||||||
tcx,
|
tcx,
|
||||||
body,
|
body,
|
||||||
@ -304,6 +310,15 @@ pub(super) fn mir_abstract_const<'tcx>(
|
|||||||
def: ty::WithOptConstParam<LocalDefId>,
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
) -> Option<&'tcx [Node<'tcx>]> {
|
) -> Option<&'tcx [Node<'tcx>]> {
|
||||||
if tcx.features().const_evaluatable_checked {
|
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();
|
let body = tcx.mir_const(def).borrow();
|
||||||
AbstractConstBuilder::new(tcx, &body)?.build()
|
AbstractConstBuilder::new(tcx, &body)?.build()
|
||||||
} else {
|
} else {
|
||||||
|
@ -553,7 +553,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
|||||||
type_implements_trait,
|
type_implements_trait,
|
||||||
subst_and_check_impossible_predicates,
|
subst_and_check_impossible_predicates,
|
||||||
mir_abstract_const: |tcx, def_id| {
|
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) {
|
if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
|
||||||
tcx.mir_abstract_const_of_const_arg(def)
|
tcx.mir_abstract_const_of_const_arg(def)
|
||||||
} else {
|
} else {
|
||||||
|
@ -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]
|
||||||
|
}
|
@ -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>();
|
||||||
|
}
|
@ -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() {}
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user