Skip to content

Commit d59b80d

Browse files
committed
Auto merge of rust-lang#86130 - BoxyUwU:abstract_const_as_cast, r=oli-obk
const_eval_checked: Support as casts in abstract consts
2 parents 0f6ba39 + 17cd790 commit d59b80d

File tree

10 files changed

+313
-3
lines changed

10 files changed

+313
-3
lines changed

compiler/rustc_middle/src/mir/abstract_const.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! A subset of a mir body used for const evaluatability checking.
2-
use crate::mir;
3-
use crate::ty;
2+
use crate::mir::{self, CastKind};
3+
use crate::ty::{self, Ty};
44

55
rustc_index::newtype_index! {
66
/// An index into an `AbstractConst`.
@@ -17,6 +17,7 @@ pub enum Node<'tcx> {
1717
Binop(mir::BinOp, NodeId, NodeId),
1818
UnaryOp(mir::UnOp, NodeId),
1919
FunctionCall(NodeId, &'tcx [NodeId]),
20+
Cast(CastKind, NodeId, Ty<'tcx>),
2021
}
2122

2223
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]

compiler/rustc_privacy/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ where
156156
let leaf = leaf.subst(tcx, ct.substs);
157157
self.visit_const(leaf)
158158
}
159+
ACNode::Cast(_, _, ty) => self.visit_ty(ty),
159160
ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
160161
ControlFlow::CONTINUE
161162
}

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
9797

9898
ControlFlow::CONTINUE
9999
}
100+
Node::Cast(_, _, ty) => {
101+
let ty = ty.subst(tcx, ct.substs);
102+
if ty.has_infer_types_or_consts() {
103+
failure_kind = FailureKind::MentionsInfer;
104+
} else if ty.has_param_types_or_consts() {
105+
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
106+
}
107+
108+
ControlFlow::CONTINUE
109+
}
100110
Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => {
101111
ControlFlow::CONTINUE
102112
}
@@ -304,6 +314,9 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
304314
self.nodes[func].used = true;
305315
nodes.iter().for_each(|&n| self.nodes[n].used = true);
306316
}
317+
Node::Cast(_, operand, _) => {
318+
self.nodes[operand].used = true;
319+
}
307320
}
308321

309322
// Nodes start as unused.
@@ -408,11 +421,19 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
408421
self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
409422
Ok(())
410423
}
424+
Rvalue::Cast(cast_kind, ref operand, ty) => {
425+
let operand = self.operand_to_node(span, operand)?;
426+
self.locals[local] =
427+
self.add_node(Node::Cast(cast_kind, operand, ty), span);
428+
Ok(())
429+
}
411430
_ => self.error(Some(span), "unsupported rvalue")?,
412431
}
413432
}
414433
// These are not actually relevant for us here, so we can ignore them.
415-
StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => Ok(()),
434+
StatementKind::AscribeUserType(..)
435+
| StatementKind::StorageLive(_)
436+
| StatementKind::StorageDead(_) => Ok(()),
416437
_ => self.error(Some(stmt.source_info.span), "unsupported statement")?,
417438
}
418439
}
@@ -594,6 +615,7 @@ where
594615
recurse(tcx, ct.subtree(func), f)?;
595616
args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f))
596617
}
618+
Node::Cast(_, operand, _) => recurse(tcx, ct.subtree(operand), f),
597619
}
598620
}
599621

@@ -676,6 +698,11 @@ pub(super) fn try_unify<'tcx>(
676698
&& iter::zip(a_args, b_args)
677699
.all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
678700
}
701+
(Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty))
702+
if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) =>
703+
{
704+
try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
705+
}
679706
_ => false,
680707
}
681708
}

compiler/rustc_trait_selection/src/traits/object_safety.rs

+2
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
838838
let leaf = leaf.subst(self.tcx, ct.substs);
839839
self.visit_const(leaf)
840840
}
841+
Node::Cast(_, _, ty) => self.visit_ty(ty),
841842
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
842843
ControlFlow::CONTINUE
843844
}
@@ -859,6 +860,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
859860
let leaf = leaf.subst(self.tcx, ct.substs);
860861
self.visit_const(leaf)
861862
}
863+
Node::Cast(_, _, ty) => self.visit_ty(ty),
862864
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
863865
ControlFlow::CONTINUE
864866
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// check-pass
2+
#![feature(const_evaluatable_checked, const_generics)]
3+
#![allow(incomplete_features)]
4+
5+
struct Foo<const N: u8>([u8; N as usize])
6+
where
7+
[(); N as usize]:;
8+
9+
struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 2) as usize]:;
10+
11+
// unifying with subtrees
12+
struct Evaluatable<const N: u16>;
13+
fn foo<const N: u8>() where Evaluatable<{N as usize as u16 }>: {
14+
let _ = Foo::<N>([1; N as usize]);
15+
}
16+
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![feature(const_evaluatable_checked, const_generics)]
2+
#![allow(incomplete_features)]
3+
4+
struct Evaluatable<const N: u128> {}
5+
6+
struct Foo<const N: u8>([u8; N as usize])
7+
//~^ Error: unconstrained generic constant
8+
//~| help: try adding a `where` bound using this expression: `where [(); N as usize]:`
9+
where
10+
Evaluatable<{N as u128}>:;
11+
12+
struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
13+
//~^ Error: unconstrained generic constant
14+
//~| help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
15+
16+
struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
17+
//~^ Error: unconstrained generic constant
18+
//~| help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
19+
20+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: unconstrained generic constant
2+
--> $DIR/abstract-const-as-cast-2.rs:6:25
3+
|
4+
LL | struct Foo<const N: u8>([u8; N as usize])
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
= help: try adding a `where` bound using this expression: `where [(); N as usize]:`
8+
9+
error: unconstrained generic constant
10+
--> $DIR/abstract-const-as-cast-2.rs:12:26
11+
|
12+
LL | struct Foo2<const N: u8>(Evaluatable::<{N as u128}>) where Evaluatable<{N as usize as u128 }>:;
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
|
15+
= help: try adding a `where` bound using this expression: `where [(); {N as u128}]:`
16+
17+
error: unconstrained generic constant
18+
--> $DIR/abstract-const-as-cast-2.rs:16:25
19+
|
20+
LL | struct Bar<const N: u8>([u8; (N + 2) as usize]) where [(); (N + 1) as usize]:;
21+
| ^^^^^^^^^^^^^^^^^^^^^^
22+
|
23+
= help: try adding a `where` bound using this expression: `where [(); (N + 2) as usize]:`
24+
25+
error: aborting due to 3 previous errors
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#![feature(const_generics, const_evaluatable_checked)]
2+
#![allow(incomplete_features)]
3+
4+
trait Trait {}
5+
pub struct EvaluatableU128<const N: u128>;
6+
7+
struct HasCastInTraitImpl<const N: usize, const M: u128>;
8+
impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
9+
10+
pub fn use_trait_impl<const N: usize>()
11+
where
12+
[(); { N + 1}]:,
13+
EvaluatableU128<{N as u128}>:, {
14+
fn assert_impl<T: Trait>() {}
15+
16+
// errors are bad but seems to be pre-existing issue #86198
17+
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
18+
//~^ Error: mismatched types
19+
//~^^ Error: unconstrained generic constant
20+
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
21+
//~^ Error: mismatched types
22+
//~^^ Error: unconstrained generic constant
23+
assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
24+
//~^ Error: mismatched types
25+
assert_impl::<HasCastInTraitImpl<14, 13>>();
26+
//~^ Error: mismatched types
27+
}
28+
pub fn use_trait_impl_2<const N: usize>()
29+
where
30+
[(); { N + 1}]:,
31+
EvaluatableU128<{N as _}>:, {
32+
fn assert_impl<T: Trait>() {}
33+
34+
// errors are bad but seems to be pre-existing issue #86198
35+
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
36+
//~^ Error: mismatched types
37+
//~^^ Error: unconstrained generic constant
38+
assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
39+
//~^ Error: mismatched types
40+
//~^^ Error: unconstrained generic constant
41+
assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
42+
//~^ Error: mismatched types
43+
assert_impl::<HasCastInTraitImpl<14, 13>>();
44+
//~^ Error: mismatched types
45+
}
46+
47+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
error: unconstrained generic constant
2+
--> $DIR/abstract-const-as-cast-3.rs:17:5
3+
|
4+
LL | fn assert_impl<T: Trait>() {}
5+
| ----- required by this bound in `use_trait_impl::assert_impl`
6+
...
7+
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9+
|
10+
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
11+
note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
12+
--> $DIR/abstract-const-as-cast-3.rs:8:22
13+
|
14+
LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
15+
| ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
17+
error[E0308]: mismatched types
18+
--> $DIR/abstract-const-as-cast-3.rs:17:5
19+
|
20+
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
22+
|
23+
= note: expected type `{ N as u128 }`
24+
found type `{ O as u128 }`
25+
26+
error: unconstrained generic constant
27+
--> $DIR/abstract-const-as-cast-3.rs:20:5
28+
|
29+
LL | fn assert_impl<T: Trait>() {}
30+
| ----- required by this bound in `use_trait_impl::assert_impl`
31+
...
32+
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
|
35+
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
36+
note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
37+
--> $DIR/abstract-const-as-cast-3.rs:8:22
38+
|
39+
LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
40+
| ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
41+
42+
error[E0308]: mismatched types
43+
--> $DIR/abstract-const-as-cast-3.rs:20:5
44+
|
45+
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
46+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
47+
|
48+
= note: expected type `{ N as _ }`
49+
found type `{ O as u128 }`
50+
51+
error[E0308]: mismatched types
52+
--> $DIR/abstract-const-as-cast-3.rs:23:5
53+
|
54+
LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
55+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
56+
|
57+
= note: expected type `12_u128`
58+
found type `13_u128`
59+
60+
error[E0308]: mismatched types
61+
--> $DIR/abstract-const-as-cast-3.rs:25:5
62+
|
63+
LL | assert_impl::<HasCastInTraitImpl<14, 13>>();
64+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
65+
|
66+
= note: expected type `13_u128`
67+
found type `14_u128`
68+
69+
error: unconstrained generic constant
70+
--> $DIR/abstract-const-as-cast-3.rs:35:5
71+
|
72+
LL | fn assert_impl<T: Trait>() {}
73+
| ----- required by this bound in `use_trait_impl_2::assert_impl`
74+
...
75+
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
76+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
77+
|
78+
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
79+
note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as u128 }>`
80+
--> $DIR/abstract-const-as-cast-3.rs:8:22
81+
|
82+
LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
83+
| ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
84+
85+
error[E0308]: mismatched types
86+
--> $DIR/abstract-const-as-cast-3.rs:35:5
87+
|
88+
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as u128 }>>();
89+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as u128 }`, found `{ O as u128 }`
90+
|
91+
= note: expected type `{ N as u128 }`
92+
found type `{ O as u128 }`
93+
94+
error: unconstrained generic constant
95+
--> $DIR/abstract-const-as-cast-3.rs:38:5
96+
|
97+
LL | fn assert_impl<T: Trait>() {}
98+
| ----- required by this bound in `use_trait_impl_2::assert_impl`
99+
...
100+
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
101+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
102+
|
103+
= help: try adding a `where` bound using this expression: `where [(); { O as u128 }]:`
104+
note: required because of the requirements on the impl of `Trait` for `HasCastInTraitImpl<{ N + 1 }, { N as _ }>`
105+
--> $DIR/abstract-const-as-cast-3.rs:8:22
106+
|
107+
LL | impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
108+
| ^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
109+
110+
error[E0308]: mismatched types
111+
--> $DIR/abstract-const-as-cast-3.rs:38:5
112+
|
113+
LL | assert_impl::<HasCastInTraitImpl<{ N + 1 }, { N as _ }>>();
114+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{ N as _ }`, found `{ O as u128 }`
115+
|
116+
= note: expected type `{ N as _ }`
117+
found type `{ O as u128 }`
118+
119+
error[E0308]: mismatched types
120+
--> $DIR/abstract-const-as-cast-3.rs:41:5
121+
|
122+
LL | assert_impl::<HasCastInTraitImpl<13, { 12 as u128 }>>();
123+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `12_u128`, found `13_u128`
124+
|
125+
= note: expected type `12_u128`
126+
found type `13_u128`
127+
128+
error[E0308]: mismatched types
129+
--> $DIR/abstract-const-as-cast-3.rs:43:5
130+
|
131+
LL | assert_impl::<HasCastInTraitImpl<14, 13>>();
132+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `13_u128`, found `14_u128`
133+
|
134+
= note: expected type `13_u128`
135+
found type `14_u128`
136+
137+
error: aborting due to 12 previous errors
138+
139+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// check-pass
2+
#![feature(const_evaluatable_checked, const_generics)]
3+
#![allow(incomplete_features)]
4+
5+
trait Trait {}
6+
pub struct EvaluatableU128<const N: u128>;
7+
8+
struct HasCastInTraitImpl<const N: usize, const M: u128>;
9+
impl<const O: usize> Trait for HasCastInTraitImpl<O, { O as u128 }> {}
10+
11+
pub fn use_trait_impl<const N: usize>() where EvaluatableU128<{N as u128}>:, {
12+
fn assert_impl<T: Trait>() {}
13+
14+
assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
15+
assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
16+
assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
17+
assert_impl::<HasCastInTraitImpl<13, 13>>();
18+
}
19+
pub fn use_trait_impl_2<const N: usize>() where EvaluatableU128<{N as _}>:, {
20+
fn assert_impl<T: Trait>() {}
21+
22+
assert_impl::<HasCastInTraitImpl<N, { N as u128 }>>();
23+
assert_impl::<HasCastInTraitImpl<N, { N as _ }>>();
24+
assert_impl::<HasCastInTraitImpl<12, { 12 as u128 }>>();
25+
assert_impl::<HasCastInTraitImpl<13, 13>>();
26+
}
27+
28+
29+
fn main() {}

0 commit comments

Comments
 (0)