Skip to content

Commit 6066037

Browse files
committed
Auto merge of #109557 - fee1-dead-contrib:mv-const-traits, r=oli-obk
Move const trait bounds checks to MIR constck Fixes #109543. When checking paths in HIR typeck, we don't want to check for const predicates since all we want might just be a function pointer. Therefore we move this to MIR constck and check that bounds are met during MIR constck. r? `@oli-obk`
2 parents f418859 + 054009d commit 6066037

27 files changed

+428
-311
lines changed

compiler/rustc_const_eval/src/transform/check_consts/check.rs

+26-25
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,32 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
722722
}
723723
};
724724

725+
// Check that all trait bounds that are marked as `~const` can be satisfied.
726+
//
727+
// Typeck only does a "non-const" check since it operates on HIR and cannot distinguish
728+
// which path expressions are getting called on and which path expressions are only used
729+
// as function pointers. This is required for correctness.
730+
let infcx = tcx.infer_ctxt().build();
731+
let ocx = ObligationCtxt::new(&infcx);
732+
733+
let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
734+
let cause = ObligationCause::new(
735+
terminator.source_info.span,
736+
self.body.source.def_id().expect_local(),
737+
ObligationCauseCode::ItemObligation(callee),
738+
);
739+
let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
740+
ocx.register_obligations(traits::predicates_for_generics(
741+
|_, _| cause.clone(),
742+
self.param_env,
743+
normalized_predicates,
744+
));
745+
746+
let errors = ocx.select_all_or_error();
747+
if !errors.is_empty() {
748+
infcx.err_ctxt().report_fulfillment_errors(&errors);
749+
}
750+
725751
// Attempting to call a trait method?
726752
if let Some(trait_id) = tcx.trait_of_item(callee) {
727753
trace!("attempting to call a trait method");
@@ -749,31 +775,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
749775
selcx.select(&obligation)
750776
};
751777

752-
// do a well-formedness check on the trait method being called. This is because typeck only does a
753-
// "non-const" check. This is required for correctness here.
754-
{
755-
let infcx = tcx.infer_ctxt().build();
756-
let ocx = ObligationCtxt::new(&infcx);
757-
758-
let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
759-
let cause = ObligationCause::new(
760-
terminator.source_info.span,
761-
self.body.source.def_id().expect_local(),
762-
ObligationCauseCode::ItemObligation(callee),
763-
);
764-
let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
765-
ocx.register_obligations(traits::predicates_for_generics(
766-
|_, _| cause.clone(),
767-
self.param_env,
768-
normalized_predicates,
769-
));
770-
771-
let errors = ocx.select_all_or_error();
772-
if !errors.is_empty() {
773-
infcx.err_ctxt().report_fulfillment_errors(&errors);
774-
}
775-
}
776-
777778
match implsrc {
778779
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
779780
debug!(

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+5-27
Original file line numberDiff line numberDiff line change
@@ -1416,41 +1416,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14161416
) {
14171417
let param_env = self.param_env;
14181418

1419-
let remap = match self.tcx.def_kind(def_id) {
1420-
// Associated consts have `Self: ~const Trait` bounds that should be satisfiable when
1421-
// `Self: Trait` is satisfied because it does not matter whether the impl is `const`.
1422-
// Therefore we have to remap the param env here to be non-const.
1423-
hir::def::DefKind::AssocConst => true,
1424-
hir::def::DefKind::AssocFn
1425-
if self.tcx.def_kind(self.tcx.parent(def_id)) == hir::def::DefKind::Trait =>
1426-
{
1427-
// N.B.: All callsites to this function involve checking a path expression.
1428-
//
1429-
// When instantiating a trait method as a function item, it does not actually matter whether
1430-
// the trait is `const` or not, or whether `where T: ~const Tr` needs to be satisfied as
1431-
// `const`. If we were to introduce instantiating trait methods as `const fn`s, we would
1432-
// check that after this, either via a bound `where F: ~const FnOnce` or when coercing to a
1433-
// `const fn` pointer.
1434-
//
1435-
// FIXME(fee1-dead) FIXME(const_trait_impl): update this doc when trait methods can satisfy
1436-
// `~const FnOnce` or can be coerced to `const fn` pointer.
1437-
true
1438-
}
1439-
_ => false,
1440-
};
14411419
let bounds = self.instantiate_bounds(span, def_id, &substs);
14421420

1443-
for mut obligation in traits::predicates_for_generics(
1421+
for obligation in traits::predicates_for_generics(
14441422
|idx, predicate_span| {
14451423
traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span))
14461424
},
14471425
param_env,
14481426
bounds,
14491427
) {
1450-
if remap {
1451-
obligation = obligation.without_const(self.tcx);
1452-
}
1453-
self.register_predicate(obligation);
1428+
// N.B. We are remapping all predicates to non-const since we don't know if we just
1429+
// want them as function pointers or we are calling them from a const-context. The
1430+
// actual checking will occur in `rustc_const_eval::transform::check_consts`.
1431+
self.register_predicate(obligation.without_const(self.tcx));
14541432
}
14551433
}
14561434

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
struct X<const N: usize = {
22
(||1usize)()
33
//~^ ERROR cannot call non-const closure
4+
//~| ERROR the trait bound
45
}>;
56

67
fn main() {}

tests/ui/const-generics/issue-93647.stderr

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
error[E0277]: the trait bound `[closure@$DIR/issue-93647.rs:2:6: 2:8]: Fn<()>` is not satisfied
2+
--> $DIR/issue-93647.rs:2:5
3+
|
4+
LL | (||1usize)()
5+
| ^^^^^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-93647.rs:2:6: 2:8]`
6+
|
7+
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-93647.rs:2:6: 2:8]`
8+
note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-93647.rs:2:6: 2:8]`, but that implementation is not `const`
9+
--> $DIR/issue-93647.rs:2:5
10+
|
11+
LL | (||1usize)()
12+
| ^^^^^^^^^^^^
13+
= note: wrap the `[closure@$DIR/issue-93647.rs:2:6: 2:8]` in a closure with no arguments: `|| { /* code */ }`
14+
115
error[E0015]: cannot call non-const closure in constants
216
--> $DIR/issue-93647.rs:2:5
317
|
@@ -8,6 +22,7 @@ LL | (||1usize)()
822
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
923
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
1024

11-
error: aborting due to previous error
25+
error: aborting due to 2 previous errors
1226

13-
For more information about this error, try `rustc --explain E0015`.
27+
Some errors have detailed explanations: E0015, E0277.
28+
For more information about an error, try `rustc --explain E0015`.

tests/ui/consts/const-block-const-bound.stderr

+12-26
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,30 @@
11
error[E0277]: can't drop `UnconstDrop` in const contexts
2-
--> $DIR/const-block-const-bound.rs:20:11
2+
--> $DIR/const-block-const-bound.rs:20:9
33
|
44
LL | f(UnconstDrop);
5-
| - ^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `UnconstDrop`
6-
| |
7-
| required by a bound introduced by this call
5+
| ^^^^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `UnconstDrop`
86
|
97
= note: the trait bound `UnconstDrop: ~const Destruct` is not satisfied
10-
note: required by a bound in `f`
11-
--> $DIR/const-block-const-bound.rs:6:15
12-
|
13-
LL | const fn f<T: ~const Destruct>(x: T) {}
14-
| ^^^^^^^^^^^^^^^ required by this bound in `f`
158
help: consider borrowing here
169
|
17-
LL | f(&UnconstDrop);
18-
| +
19-
LL | f(&mut UnconstDrop);
20-
| ++++
10+
LL | &f(UnconstDrop);
11+
| +
12+
LL | &mut f(UnconstDrop);
13+
| ++++
2114

2215
error[E0277]: can't drop `NonDrop` in const contexts
23-
--> $DIR/const-block-const-bound.rs:22:11
16+
--> $DIR/const-block-const-bound.rs:22:9
2417
|
2518
LL | f(NonDrop);
26-
| - ^^^^^^^ the trait `~const Destruct` is not implemented for `NonDrop`
27-
| |
28-
| required by a bound introduced by this call
19+
| ^^^^^^^^^^ the trait `~const Destruct` is not implemented for `NonDrop`
2920
|
3021
= note: the trait bound `NonDrop: ~const Destruct` is not satisfied
31-
note: required by a bound in `f`
32-
--> $DIR/const-block-const-bound.rs:6:15
33-
|
34-
LL | const fn f<T: ~const Destruct>(x: T) {}
35-
| ^^^^^^^^^^^^^^^ required by this bound in `f`
3622
help: consider borrowing here
3723
|
38-
LL | f(&NonDrop);
39-
| +
40-
LL | f(&mut NonDrop);
41-
| ++++
24+
LL | &f(NonDrop);
25+
| +
26+
LL | &mut f(NonDrop);
27+
| ++++
4228

4329
error: aborting due to 2 previous errors
4430

tests/ui/consts/invalid-inline-const-in-match-arm.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ fn main() {
55
match () {
66
const { (|| {})() } => {}
77
//~^ ERROR cannot call non-const closure in constants
8+
//~| ERROR the trait bound
89
}
910
}

tests/ui/consts/invalid-inline-const-in-match-arm.stderr

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
error[E0277]: the trait bound `[closure@$DIR/invalid-inline-const-in-match-arm.rs:6:18: 6:20]: Fn<()>` is not satisfied
2+
--> $DIR/invalid-inline-const-in-match-arm.rs:6:17
3+
|
4+
LL | const { (|| {})() } => {}
5+
| ^^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/invalid-inline-const-in-match-arm.rs:6:18: 6:20]`
6+
|
7+
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/invalid-inline-const-in-match-arm.rs:6:18: 6:20]`
8+
note: the trait `Fn<()>` is implemented for `[closure@$DIR/invalid-inline-const-in-match-arm.rs:6:18: 6:20]`, but that implementation is not `const`
9+
--> $DIR/invalid-inline-const-in-match-arm.rs:6:17
10+
|
11+
LL | const { (|| {})() } => {}
12+
| ^^^^^^^^^
13+
= note: wrap the `[closure@$DIR/invalid-inline-const-in-match-arm.rs:6:18: 6:20]` in a closure with no arguments: `|| { /* code */ }`
14+
115
error[E0015]: cannot call non-const closure in constants
216
--> $DIR/invalid-inline-const-in-match-arm.rs:6:17
317
|
@@ -8,6 +22,7 @@ LL | const { (|| {})() } => {}
822
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
923
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
1024

11-
error: aborting due to previous error
25+
error: aborting due to 2 previous errors
1226

13-
For more information about this error, try `rustc --explain E0015`.
27+
Some errors have detailed explanations: E0015, E0277.
28+
For more information about an error, try `rustc --explain E0015`.

tests/ui/consts/issue-28113.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const X: u8 =
44
|| -> u8 { 5 }()
55
//~^ ERROR cannot call non-const closure
6+
//~| ERROR the trait bound
67
;
78

89
fn main() {}

tests/ui/consts/issue-28113.stderr

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
error[E0277]: the trait bound `[closure@$DIR/issue-28113.rs:4:5: 4:13]: Fn<()>` is not satisfied
2+
--> $DIR/issue-28113.rs:4:5
3+
|
4+
LL | || -> u8 { 5 }()
5+
| ^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-28113.rs:4:5: 4:13]`
6+
|
7+
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-28113.rs:4:5: 4:13]`
8+
note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-28113.rs:4:5: 4:13]`, but that implementation is not `const`
9+
--> $DIR/issue-28113.rs:4:5
10+
|
11+
LL | || -> u8 { 5 }()
12+
| ^^^^^^^^^^^^^^^^
13+
= note: wrap the `[closure@$DIR/issue-28113.rs:4:5: 4:13]` in a closure with no arguments: `|| { /* code */ }`
14+
115
error[E0015]: cannot call non-const closure in constants
216
--> $DIR/issue-28113.rs:4:5
317
|
@@ -8,6 +22,7 @@ LL | || -> u8 { 5 }()
822
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
923
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
1024

11-
error: aborting due to previous error
25+
error: aborting due to 2 previous errors
1226

13-
For more information about this error, try `rustc --explain E0015`.
27+
Some errors have detailed explanations: E0015, E0277.
28+
For more information about an error, try `rustc --explain E0015`.

tests/ui/consts/issue-56164.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const fn foo() { (||{})() }
22
//~^ ERROR cannot call non-const closure
3+
//~| ERROR the trait bound
34

45
const fn bad(input: fn()) {
56
input()

tests/ui/consts/issue-56164.stderr

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
error[E0277]: the trait bound `[closure@$DIR/issue-56164.rs:1:19: 1:21]: Fn<()>` is not satisfied
2+
--> $DIR/issue-56164.rs:1:18
3+
|
4+
LL | const fn foo() { (||{})() }
5+
| ^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-56164.rs:1:19: 1:21]`
6+
|
7+
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-56164.rs:1:19: 1:21]`
8+
note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-56164.rs:1:19: 1:21]`, but that implementation is not `const`
9+
--> $DIR/issue-56164.rs:1:18
10+
|
11+
LL | const fn foo() { (||{})() }
12+
| ^^^^^^^^
13+
= note: wrap the `[closure@$DIR/issue-56164.rs:1:19: 1:21]` in a closure with no arguments: `|| { /* code */ }`
14+
115
error[E0015]: cannot call non-const closure in constant functions
216
--> $DIR/issue-56164.rs:1:18
317
|
@@ -9,7 +23,7 @@ LL | const fn foo() { (||{})() }
923
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
1024

1125
error: function pointer calls are not allowed in constant functions
12-
--> $DIR/issue-56164.rs:5:5
26+
--> $DIR/issue-56164.rs:6:5
1327
|
1428
LL | input()
1529
| ^^^^^^^
@@ -26,6 +40,7 @@ note: erroneous constant used
2640
LL | const fn foo() { (||{})() }
2741
| ^^^^^^
2842

29-
error: aborting due to 2 previous errors
43+
error: aborting due to 3 previous errors
3044

31-
For more information about this error, try `rustc --explain E0015`.
45+
Some errors have detailed explanations: E0015, E0277.
46+
For more information about an error, try `rustc --explain E0015`.

tests/ui/consts/issue-68542-closure-in-array-len.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
struct Bug {
66
a: [(); (|| { 0 })()] //~ ERROR cannot call non-const closure
7+
//~^ ERROR the trait bound
78
}
89

910
fn main() {}

tests/ui/consts/issue-68542-closure-in-array-len.stderr

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
error[E0277]: the trait bound `[closure@$DIR/issue-68542-closure-in-array-len.rs:6:14: 6:16]: Fn<()>` is not satisfied
2+
--> $DIR/issue-68542-closure-in-array-len.rs:6:13
3+
|
4+
LL | a: [(); (|| { 0 })()]
5+
| ^^^^^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-68542-closure-in-array-len.rs:6:14: 6:16]`
6+
|
7+
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-68542-closure-in-array-len.rs:6:14: 6:16]`
8+
note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-68542-closure-in-array-len.rs:6:14: 6:16]`, but that implementation is not `const`
9+
--> $DIR/issue-68542-closure-in-array-len.rs:6:13
10+
|
11+
LL | a: [(); (|| { 0 })()]
12+
| ^^^^^^^^^^^^
13+
= note: wrap the `[closure@$DIR/issue-68542-closure-in-array-len.rs:6:14: 6:16]` in a closure with no arguments: `|| { /* code */ }`
14+
115
error[E0015]: cannot call non-const closure in constants
216
--> $DIR/issue-68542-closure-in-array-len.rs:6:13
317
|
@@ -8,6 +22,7 @@ LL | a: [(); (|| { 0 })()]
822
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
923
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
1024

11-
error: aborting due to previous error
25+
error: aborting due to 2 previous errors
1226

13-
For more information about this error, try `rustc --explain E0015`.
27+
Some errors have detailed explanations: E0015, E0277.
28+
For more information about an error, try `rustc --explain E0015`.

tests/ui/never_type/issue-52443.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ fn main() {
1111
//~| ERROR cannot convert
1212
//~| ERROR mutable references
1313
//~| ERROR cannot call
14+
//~| ERROR the trait bound
1415
}

tests/ui/never_type/issue-52443.stderr

+15-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ LL | [(); { for _ in 0usize.. {}; 0}];
5858
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
5959
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
6060

61+
error[E0277]: the trait bound `RangeFrom<usize>: Iterator` is not satisfied
62+
--> $DIR/issue-52443.rs:9:21
63+
|
64+
LL | [(); { for _ in 0usize.. {}; 0}];
65+
| ^^^^^^^^ `RangeFrom<usize>` is not an iterator
66+
|
67+
= help: the trait `~const Iterator` is not implemented for `RangeFrom<usize>`
68+
note: the trait `Iterator` is implemented for `RangeFrom<usize>`, but that implementation is not `const`
69+
--> $DIR/issue-52443.rs:9:21
70+
|
71+
LL | [(); { for _ in 0usize.. {}; 0}];
72+
| ^^^^^^^^
73+
6174
error[E0015]: cannot call non-const fn `<RangeFrom<usize> as Iterator>::next` in constants
6275
--> $DIR/issue-52443.rs:9:21
6376
|
@@ -67,7 +80,7 @@ LL | [(); { for _ in 0usize.. {}; 0}];
6780
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
6881
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
6982

70-
error: aborting due to 6 previous errors; 1 warning emitted
83+
error: aborting due to 7 previous errors; 1 warning emitted
7184

72-
Some errors have detailed explanations: E0015, E0308, E0658.
85+
Some errors have detailed explanations: E0015, E0277, E0308, E0658.
7386
For more information about an error, try `rustc --explain E0015`.

0 commit comments

Comments
 (0)