From 439171e094e00e7d3ac0b2d8f65c23cac87836f2 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 7 Nov 2020 12:37:28 +0100 Subject: [PATCH] look at assoc ct, check the type of nodes --- .../src/traits/const_evaluatable.rs | 17 ++++++++++ .../associated-consts.rs | 31 +++++++++++++++++++ .../const_evaluatable_checked/different-fn.rs | 16 ++++++++++ .../different-fn.stderr | 14 +++++++++ 4 files changed, 78 insertions(+) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/associated-consts.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 638a8253e7eb9..e1721a5a88a76 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -512,6 +512,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { block = &self.body.basic_blocks()[next]; } else { assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap()); + // `AbstractConst`s should not contain any promoteds as they require references which + // are not allowed. + assert!(!self.nodes.iter().any(|n| matches!( + n.node, + Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(_, _, Some(_)), ty: _ }) + ))); + self.nodes[self.locals[mir::RETURN_PLACE]].used = true; if let Some(&unused) = self.nodes.iter().find(|n| !n.used) { self.error(Some(unused.span), "dead code")?; @@ -609,6 +616,10 @@ pub(super) fn try_unify<'tcx>( (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { let a_ct = a_ct.subst(tcx, a.substs); let b_ct = b_ct.subst(tcx, b.substs); + if a_ct.ty != b_ct.ty { + return false; + } + match (a_ct.val, b_ct.val) { // We can just unify errors with everything to reduce the amount of // emitted errors here. @@ -621,6 +632,12 @@ pub(super) fn try_unify<'tcx>( // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This // means that we only allow inference variables if they are equal. (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val, + // We may want to instead recurse into unevaluated constants here. That may require some + // care to prevent infinite recursion, so let's just ignore this for now. + ( + ty::ConstKind::Unevaluated(a_def, a_substs, None), + ty::ConstKind::Unevaluated(b_def, b_substs, None), + ) => a_def == b_def && a_substs == b_substs, // FIXME(const_evaluatable_checked): We may want to either actually try // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like // this, for now we just return false here. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/associated-consts.rs b/src/test/ui/const-generics/const_evaluatable_checked/associated-consts.rs new file mode 100644 index 0000000000000..533fe55b45bee --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/associated-consts.rs @@ -0,0 +1,31 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +pub trait BlockCipher { + const BLOCK_SIZE: usize; +} + +struct FooCipher; +impl BlockCipher for FooCipher { + const BLOCK_SIZE: usize = 64; +} + +struct BarCipher; +impl BlockCipher for BarCipher { + const BLOCK_SIZE: usize = 32; +} + +pub struct Block(C); + +pub fn test() +where + [u8; M - C::BLOCK_SIZE]: Sized, +{ + let _ = [0; M - C::BLOCK_SIZE]; +} + +fn main() { + test::(); + test::(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs new file mode 100644 index 0000000000000..05049d9c2a6ef --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs @@ -0,0 +1,16 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +use std::mem::size_of; +use std::marker::PhantomData; + +struct Foo(PhantomData); + +fn test() -> [u8; size_of::()] { + [0; size_of::>()] + //~^ ERROR unconstrained generic constant +} + +fn main() { + test::(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr new file mode 100644 index 0000000000000..1f6dddb04e56c --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr @@ -0,0 +1,14 @@ +error: unconstrained generic constant + --> $DIR/different-fn.rs:10:9 + | +LL | [0; size_of::>()] + | ^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a `where` bound for this expression + --> $DIR/different-fn.rs:10:9 + | +LL | [0; size_of::>()] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error +