]> git.lizzy.rs Git - rust.git/commitdiff
allow unary operations and ignore StorageLive/Dead stmts
authorBastian Kauschke <bastian_kauschke@hotmail.de>
Fri, 11 Sep 2020 08:00:06 +0000 (10:00 +0200)
committerBastian Kauschke <bastian_kauschke@hotmail.de>
Fri, 18 Sep 2020 15:11:34 +0000 (17:11 +0200)
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
src/test/ui/const-generics/const_evaluatable_checked/unop.rs [new file with mode: 0644]

index 56886aae066693540d5798052850d39ea27cda91..f0e51511732767e17410fd4e8bd90ec2048becec 100644 (file)
@@ -174,6 +174,7 @@ fn operand_to_node(&mut self, op: &mir::Operand<'tcx>) -> Option<NodeId> {
         }
     }
 
+    /// 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 @@ fn check_binop(op: mir::BinOp) -> bool {
         }
     }
 
+    /// 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 @@ fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> {
                 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 @@ fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> {
                         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 @@ fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> {
                         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 (file)
index 0000000..8e0768b
--- /dev/null
@@ -0,0 +1,14 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+struct Foo<const B: bool>;
+
+fn test<const N: usize>() -> Foo<{ !(N > 10) }> where Foo<{ !(N > 10) }>: Sized {
+    Foo
+}
+
+fn main() {
+    let _: Foo<false> = test::<12>();
+    let _: Foo<true> = test::<9>();
+}