about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBastian Kauschke <bastian_kauschke@hotmail.de>2020-09-11 10:00:06 +0200
committerBastian Kauschke <bastian_kauschke@hotmail.de>2020-09-18 17:11:34 +0200
commitd1294e0ce2ce78e4a634fbfa68cb2bc4d50afc6e (patch)
treef32d9289e39c862d70cb15bd15b38e3e20118cd5
parent5a277822a536eff72d562e75fb6046add63d4926 (diff)
downloadrust-d1294e0ce2ce78e4a634fbfa68cb2bc4d50afc6e.tar.gz
rust-d1294e0ce2ce78e4a634fbfa68cb2bc4d50afc6e.zip
allow unary operations and ignore StorageLive/Dead stmts
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs27
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/unop.rs14
2 files changed, 37 insertions, 4 deletions
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<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>();
+}