about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/mir/abstract_const.rs5
-rw-r--r--compiler/rustc_privacy/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs18
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs20
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr26
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs47
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr139
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs29
10 files changed, 313 insertions, 3 deletions
diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs
index 776a777b1bd..1ef10241143 100644
--- a/compiler/rustc_middle/src/mir/abstract_const.rs
+++ b/compiler/rustc_middle/src/mir/abstract_const.rs
@@ -1,6 +1,6 @@
 //! A subset of a mir body used for const evaluatability checking.
-use crate::mir;
-use crate::ty;
+use crate::mir::{self, CastKind};
+use crate::ty::{self, Ty};
 
 rustc_index::newtype_index! {
     /// An index into an `AbstractConst`.
@@ -17,6 +17,7 @@ pub enum Node<'tcx> {
     Binop(mir::BinOp, NodeId, NodeId),
     UnaryOp(mir::UnOp, NodeId),
     FunctionCall(NodeId, &'tcx [NodeId]),
+    Cast(CastKind, NodeId, Ty<'tcx>),
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index e64f12ef48f..5a79a9cc6ec 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -156,6 +156,7 @@ where
                 let leaf = leaf.subst(tcx, ct.substs);
                 self.visit_const(leaf)
             }
+            ACNode::Cast(_, _, ty) => self.visit_ty(ty),
             ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
                 ControlFlow::CONTINUE
             }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 8961cdaebf3..b1a938836b7 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -97,6 +97,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
 
                         ControlFlow::CONTINUE
                     }
+                    Node::Cast(_, _, ty) => {
+                        let ty = ty.subst(tcx, ct.substs);
+                        if ty.has_infer_types_or_consts() {
+                            failure_kind = FailureKind::MentionsInfer;
+                        } else if ty.has_param_types_or_consts() {
+                            failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
+                        }
+
+                        ControlFlow::CONTINUE
+                    }
                     Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
                         ControlFlow::CONTINUE
                     }
@@ -304,6 +314,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 self.nodes[func].used = true;
                 nodes.iter().for_each(|&n| self.nodes[n].used = true);
             }
+            Node::Cast(_, operand, _) => {
+                self.nodes[operand].used = true;
+            }
         }
 
         // Nodes start as unused.
@@ -408,11 +421,19 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                         self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
                         Ok(())
                     }
+                    Rvalue::Cast(cast_kind, ref operand, ty) => {
+                        let operand = self.operand_to_node(span, operand)?;
+                        self.locals[local] =
+                            self.add_node(Node::Cast(cast_kind, operand, ty), span);
+                        Ok(())
+                    }
                     _ => self.error(Some(span), "unsupported rvalue")?,
                 }
             }
             // These are not actually relevant for us here, so we can ignore them.
-            StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Ok(()),
+            StatementKind::AscribeUserType(..)
+            | StatementKind::StorageLive(_)
+            | StatementKind::StorageDead(_) => Ok(()),
             _ => self.error(Some(stmt.source_info.span), "unsupported statement")?,
         }
     }
@@ -594,6 +615,7 @@ where
                 recurse(tcx, ct.subtree(func), f)?;
                 args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
             }
+            Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
         }
     }
 
@@ -676,6 +698,11 @@ pub(super) fn try_unify<'tcx>(
                 && iter::zip(a_args, b_args)
                     .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
         }
+        (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty))
+            if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) =>
+        {
+            try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
+        }
         _ => false,
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index d5e1bd3f9ea..7ebef7f8883 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -838,6 +838,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
                         let leaf = leaf.subst(self.tcx, ct.substs);
                         self.visit_const(leaf)
                     }
+                    Node::Cast(_, _, ty) => self.visit_ty(ty),
                     Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
                         ControlFlow::CONTINUE
                     }
@@ -859,6 +860,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
                             let leaf = leaf.subst(self.tcx, ct.substs);
                             self.visit_const(leaf)
                         }
+                        Node::Cast(_, _, ty) => self.visit_ty(ty),
                         Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
                             ControlFlow::CONTINUE
                         }
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs
new file mode 100644
index 00000000000..744a1c4de48
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-1.rs
@@ -0,0 +1,18 @@
+// check-pass
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+struct Foo<const N: u8>([u8; N as usize])
+where
+    [(); N as usize]:;
+
+struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 2) as usize]:;
+
+// unifying with subtrees
+struct Evaluatable<const N: u16>;
+fn foo<const N: u8>() where Evaluatable<{N as usize as u16 }>: {
+    let _ = Foo::<N>([1; N as usize]);
+}
+
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs
new file mode 100644
index 00000000000..543774649ed
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.rs
@@ -0,0 +1,20 @@
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+struct Evaluatable<const N: u128> {}
+
+struct Foo<const N: u8>([u8; N as usize])
+//~^ Error: unconstrained generic constant
+//~| help: try adding a `where` bound using this expression: `where [(); N as usize]:`
+where
+    Evaluatable<{N as u128}>:;
+
+struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
+//~^ Error: unconstrained generic constant
+//~| help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
+
+struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
+//~^ Error: unconstrained generic constant
+//~| help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr
new file mode 100644
index 00000000000..5ca04d25e55
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-2.stderr
@@ -0,0 +1,26 @@
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-2.rs:6:25
+   |
+LL | struct Foo<const N: u8>([u8; N as usize])
+   |                         ^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); N as usize]:`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-2.rs:12:26
+   |
+LL | struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-2.rs:16:25
+   |
+LL | struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs
new file mode 100644
index 00000000000..2ca06bd1cb7
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.rs
@@ -0,0 +1,47 @@
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+pub struct EvaluatableU128<const N: u128>;
+
+struct HasCastInTraitImpl<const N: usize, const M: u128>;
+impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+
+pub fn use_trait_impl<const N: usize>()
+where
+    [(); { N + 1}]:,
+    EvaluatableU128<{N as u128}>:, {
+    fn assert_impl<T: Trait>() {}
+
+    // errors are bad but seems to be pre-existing issue #86198
+    assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+    //~^ Error: mismatched types
+    //~^^ Error: unconstrained generic constant
+    assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+    //~^ Error: mismatched types
+    //~^^ Error: unconstrained generic constant
+    assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+    //~^ Error: mismatched types
+    assert_impl::<HasCastInTraitImpl<14, 13>>();
+    //~^ Error: mismatched types
+}
+pub fn use_trait_impl_2<const N: usize>()
+where
+    [(); { N + 1}]:,
+    EvaluatableU128<{N as _}>:, {
+    fn assert_impl<T: Trait>() {}
+
+    // errors are bad but seems to be pre-existing issue #86198
+    assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+    //~^ Error: mismatched types
+    //~^^ Error: unconstrained generic constant
+    assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+    //~^ Error: mismatched types
+    //~^^ Error: unconstrained generic constant
+    assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+    //~^ Error: mismatched types
+    assert_impl::<HasCastInTraitImpl<14, 13>>();
+    //~^ Error: mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr
new file mode 100644
index 00000000000..c5237fc6f2b
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-3.stderr
@@ -0,0 +1,139 @@
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-3.rs:17:5
+   |
+LL |     fn assert_impl<T: Trait>() {}
+   |                       ----- required by this bound in `use_trait_impl::assert_impl`
+...
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
+  --> $DIR/abstract-const-as-cast-3.rs:8:22
+   |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+   |                      ^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:17:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
+   |
+   = note: expected type `{ N as u128 }`
+              found type `{ O as u128 }`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-3.rs:20:5
+   |
+LL |     fn assert_impl<T: Trait>() {}
+   |                       ----- required by this bound in `use_trait_impl::assert_impl`
+...
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
+  --> $DIR/abstract-const-as-cast-3.rs:8:22
+   |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+   |                      ^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:20:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
+   |
+   = note: expected type `{ N as _ }`
+              found type `{ O as u128 }`
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:23:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
+   |
+   = note: expected type `12_u128`
+              found type `13_u128`
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:25:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<14, 13>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
+   |
+   = note: expected type `13_u128`
+              found type `14_u128`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-3.rs:35:5
+   |
+LL |     fn assert_impl<T: Trait>() {}
+   |                       ----- required by this bound in `use_trait_impl_2::assert_impl`
+...
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
+  --> $DIR/abstract-const-as-cast-3.rs:8:22
+   |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+   |                      ^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:35:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
+   |
+   = note: expected type `{ N as u128 }`
+              found type `{ O as u128 }`
+
+error: unconstrained generic constant
+  --> $DIR/abstract-const-as-cast-3.rs:38:5
+   |
+LL |     fn assert_impl<T: Trait>() {}
+   |                       ----- required by this bound in `use_trait_impl_2::assert_impl`
+...
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
+note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
+  --> $DIR/abstract-const-as-cast-3.rs:8:22
+   |
+LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+   |                      ^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:38:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
+   |
+   = note: expected type `{ N as _ }`
+              found type `{ O as u128 }`
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:41:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
+   |
+   = note: expected type `12_u128`
+              found type `13_u128`
+
+error[E0308]: mismatched types
+  --> $DIR/abstract-const-as-cast-3.rs:43:5
+   |
+LL |     assert_impl::<HasCastInTraitImpl<14, 13>>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
+   |
+   = note: expected type `13_u128`
+              found type `14_u128`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs
new file mode 100644
index 00000000000..0bb4fcff4d0
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/abstract-const-as-cast-4.rs
@@ -0,0 +1,29 @@
+// check-pass
+#![feature(const_evaluatable_checked, const_generics)]
+#![allow(incomplete_features)]
+
+trait Trait {}
+pub struct EvaluatableU128<const N: u128>;
+
+struct HasCastInTraitImpl<const N: usize, const M: u128>;
+impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
+
+pub fn use_trait_impl<const N: usize>() where EvaluatableU128<{N as u128}>:, {
+    fn assert_impl<T: Trait>() {}
+
+    assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
+    assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
+    assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
+    assert_impl::<HasCastInTraitImpl<13, 13>>();
+}
+pub fn use_trait_impl_2<const N: usize>() where EvaluatableU128<{N as _}>:, {
+    fn assert_impl<T: Trait>() {}
+
+    assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
+    assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
+    assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
+    assert_impl::<HasCastInTraitImpl<13, 13>>();
+}
+
+
+fn main() {}