From d1294e0ce2ce78e4a634fbfa68cb2bc4d50afc6e Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Fri, 11 Sep 2020 10:00:06 +0200 Subject: [PATCH] allow unary operations and ignore StorageLive/Dead stmts --- .../src/traits/const_evaluatable.rs | 27 ++++++++++++++++--- .../const_evaluatable_checked/unop.rs | 14 ++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/const-generics/const_evaluatable_checked/unop.rs diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 56886aae066..f0e51511732 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -174,6 +174,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } + /// We do not allow all binary operations in abstract consts, so filter disallowed ones. fn check_binop(op: mir::BinOp) -> bool { use mir::BinOp::*; match op { @@ -183,6 +184,15 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { } } + /// While we currently allow all unary operations, we still want to explicitly guard against + /// future changes here. + fn check_unop(op: mir::UnOp) -> bool { + use mir::UnOp::*; + match op { + Not | Neg => true, + } + } + fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> { debug!("AbstractConstBuilder: stmt={:?}", stmt); match stmt.kind { @@ -191,6 +201,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { match *rvalue { Rvalue::Use(ref operand) => { self.locals[local] = self.operand_to_node(operand)?; + Some(()) } Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { let lhs = self.operand_to_node(lhs)?; @@ -198,6 +209,8 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); if op.is_checkable() { bug!("unexpected unchecked checkable binary operation"); + } else { + Some(()) } } Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { @@ -205,14 +218,20 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { let rhs = self.operand_to_node(rhs)?; self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); self.checked_op_locals.insert(local); + Some(()) } - _ => return None, + Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { + let operand = self.operand_to_node(operand)?; + self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand)); + Some(()) + } + _ => None, } } - _ => return None, + // These are not actually relevant for us here, so we can ignore them. + StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Some(()), + _ => None, } - - Some(()) } fn build_terminator( diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unop.rs b/src/test/ui/const-generics/const_evaluatable_checked/unop.rs new file mode 100644 index 00000000000..8e0768b1c95 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/unop.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ !(N > 10) }> where Foo<{ !(N > 10) }>: Sized { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +}