Skip to content

Commit

Permalink
Auto merge of #109557 - fee1-dead-contrib:mv-const-traits, r=oli-obk
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
bors committed Mar 28, 2023
2 parents f418859 + 054009d commit 6066037
Show file tree
Hide file tree
Showing 27 changed files with 428 additions and 311 deletions.
51 changes: 26 additions & 25 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,32 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
};

// Check that all trait bounds that are marked as `~const` can be satisfied.
//
// Typeck only does a "non-const" check since it operates on HIR and cannot distinguish
// which path expressions are getting called on and which path expressions are only used
// as function pointers. This is required for correctness.
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);

let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
let cause = ObligationCause::new(
terminator.source_info.span,
self.body.source.def_id().expect_local(),
ObligationCauseCode::ItemObligation(callee),
);
let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
ocx.register_obligations(traits::predicates_for_generics(
|_, _| cause.clone(),
self.param_env,
normalized_predicates,
));

let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
}

// Attempting to call a trait method?
if let Some(trait_id) = tcx.trait_of_item(callee) {
trace!("attempting to call a trait method");
Expand Down Expand Up @@ -749,31 +775,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
selcx.select(&obligation)
};

// do a well-formedness check on the trait method being called. This is because typeck only does a
// "non-const" check. This is required for correctness here.
{
let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx);

let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
let cause = ObligationCause::new(
terminator.source_info.span,
self.body.source.def_id().expect_local(),
ObligationCauseCode::ItemObligation(callee),
);
let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
ocx.register_obligations(traits::predicates_for_generics(
|_, _| cause.clone(),
self.param_env,
normalized_predicates,
));

let errors = ocx.select_all_or_error();
if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors);
}
}

match implsrc {
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
debug!(
Expand Down
32 changes: 5 additions & 27 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1416,41 +1416,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let param_env = self.param_env;

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

for mut obligation in traits::predicates_for_generics(
for obligation in traits::predicates_for_generics(
|idx, predicate_span| {
traits::ObligationCause::new(span, self.body_id, code(idx, predicate_span))
},
param_env,
bounds,
) {
if remap {
obligation = obligation.without_const(self.tcx);
}
self.register_predicate(obligation);
// N.B. We are remapping all predicates to non-const since we don't know if we just
// want them as function pointers or we are calling them from a const-context. The
// actual checking will occur in `rustc_const_eval::transform::check_consts`.
self.register_predicate(obligation.without_const(self.tcx));
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/ui/const-generics/issue-93647.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
struct X<const N: usize = {
(||1usize)()
//~^ ERROR cannot call non-const closure
//~| ERROR the trait bound
}>;

fn main() {}
19 changes: 17 additions & 2 deletions tests/ui/const-generics/issue-93647.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
error[E0277]: the trait bound `[closure@$DIR/issue-93647.rs:2:6: 2:8]: Fn<()>` is not satisfied
--> $DIR/issue-93647.rs:2:5
|
LL | (||1usize)()
| ^^^^^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-93647.rs:2:6: 2:8]`
|
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-93647.rs:2:6: 2:8]`
note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-93647.rs:2:6: 2:8]`, but that implementation is not `const`
--> $DIR/issue-93647.rs:2:5
|
LL | (||1usize)()
| ^^^^^^^^^^^^
= note: wrap the `[closure@$DIR/issue-93647.rs:2:6: 2:8]` in a closure with no arguments: `|| { /* code */ }`

error[E0015]: cannot call non-const closure in constants
--> $DIR/issue-93647.rs:2:5
|
Expand All @@ -8,6 +22,7 @@ LL | (||1usize)()
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
Some errors have detailed explanations: E0015, E0277.
For more information about an error, try `rustc --explain E0015`.
38 changes: 12 additions & 26 deletions tests/ui/consts/const-block-const-bound.stderr
Original file line number Diff line number Diff line change
@@ -1,44 +1,30 @@
error[E0277]: can't drop `UnconstDrop` in const contexts
--> $DIR/const-block-const-bound.rs:20:11
--> $DIR/const-block-const-bound.rs:20:9
|
LL | f(UnconstDrop);
| - ^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `UnconstDrop`
| |
| required by a bound introduced by this call
| ^^^^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `UnconstDrop`
|
= note: the trait bound `UnconstDrop: ~const Destruct` is not satisfied
note: required by a bound in `f`
--> $DIR/const-block-const-bound.rs:6:15
|
LL | const fn f<T: ~const Destruct>(x: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `f`
help: consider borrowing here
|
LL | f(&UnconstDrop);
| +
LL | f(&mut UnconstDrop);
| ++++
LL | &f(UnconstDrop);
| +
LL | &mut f(UnconstDrop);
| ++++

error[E0277]: can't drop `NonDrop` in const contexts
--> $DIR/const-block-const-bound.rs:22:11
--> $DIR/const-block-const-bound.rs:22:9
|
LL | f(NonDrop);
| - ^^^^^^^ the trait `~const Destruct` is not implemented for `NonDrop`
| |
| required by a bound introduced by this call
| ^^^^^^^^^^ the trait `~const Destruct` is not implemented for `NonDrop`
|
= note: the trait bound `NonDrop: ~const Destruct` is not satisfied
note: required by a bound in `f`
--> $DIR/const-block-const-bound.rs:6:15
|
LL | const fn f<T: ~const Destruct>(x: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `f`
help: consider borrowing here
|
LL | f(&NonDrop);
| +
LL | f(&mut NonDrop);
| ++++
LL | &f(NonDrop);
| +
LL | &mut f(NonDrop);
| ++++

error: aborting due to 2 previous errors

Expand Down
1 change: 1 addition & 0 deletions tests/ui/consts/invalid-inline-const-in-match-arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ fn main() {
match () {
const { (|| {})() } => {}
//~^ ERROR cannot call non-const closure in constants
//~| ERROR the trait bound
}
}
19 changes: 17 additions & 2 deletions tests/ui/consts/invalid-inline-const-in-match-arm.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
error[E0277]: the trait bound `[closure@$DIR/invalid-inline-const-in-match-arm.rs:6:18: 6:20]: Fn<()>` is not satisfied
--> $DIR/invalid-inline-const-in-match-arm.rs:6:17
|
LL | const { (|| {})() } => {}
| ^^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/invalid-inline-const-in-match-arm.rs:6:18: 6:20]`
|
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/invalid-inline-const-in-match-arm.rs:6:18: 6:20]`
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`
--> $DIR/invalid-inline-const-in-match-arm.rs:6:17
|
LL | const { (|| {})() } => {}
| ^^^^^^^^^
= note: wrap the `[closure@$DIR/invalid-inline-const-in-match-arm.rs:6:18: 6:20]` in a closure with no arguments: `|| { /* code */ }`

error[E0015]: cannot call non-const closure in constants
--> $DIR/invalid-inline-const-in-match-arm.rs:6:17
|
Expand All @@ -8,6 +22,7 @@ LL | const { (|| {})() } => {}
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
Some errors have detailed explanations: E0015, E0277.
For more information about an error, try `rustc --explain E0015`.
1 change: 1 addition & 0 deletions tests/ui/consts/issue-28113.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const X: u8 =
|| -> u8 { 5 }()
//~^ ERROR cannot call non-const closure
//~| ERROR the trait bound
;

fn main() {}
19 changes: 17 additions & 2 deletions tests/ui/consts/issue-28113.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
error[E0277]: the trait bound `[closure@$DIR/issue-28113.rs:4:5: 4:13]: Fn<()>` is not satisfied
--> $DIR/issue-28113.rs:4:5
|
LL | || -> u8 { 5 }()
| ^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-28113.rs:4:5: 4:13]`
|
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-28113.rs:4:5: 4:13]`
note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-28113.rs:4:5: 4:13]`, but that implementation is not `const`
--> $DIR/issue-28113.rs:4:5
|
LL | || -> u8 { 5 }()
| ^^^^^^^^^^^^^^^^
= note: wrap the `[closure@$DIR/issue-28113.rs:4:5: 4:13]` in a closure with no arguments: `|| { /* code */ }`

error[E0015]: cannot call non-const closure in constants
--> $DIR/issue-28113.rs:4:5
|
Expand All @@ -8,6 +22,7 @@ LL | || -> u8 { 5 }()
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
Some errors have detailed explanations: E0015, E0277.
For more information about an error, try `rustc --explain E0015`.
1 change: 1 addition & 0 deletions tests/ui/consts/issue-56164.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const fn foo() { (||{})() }
//~^ ERROR cannot call non-const closure
//~| ERROR the trait bound

const fn bad(input: fn()) {
input()
Expand Down
21 changes: 18 additions & 3 deletions tests/ui/consts/issue-56164.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
error[E0277]: the trait bound `[closure@$DIR/issue-56164.rs:1:19: 1:21]: Fn<()>` is not satisfied
--> $DIR/issue-56164.rs:1:18
|
LL | const fn foo() { (||{})() }
| ^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-56164.rs:1:19: 1:21]`
|
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-56164.rs:1:19: 1:21]`
note: the trait `Fn<()>` is implemented for `[closure@$DIR/issue-56164.rs:1:19: 1:21]`, but that implementation is not `const`
--> $DIR/issue-56164.rs:1:18
|
LL | const fn foo() { (||{})() }
| ^^^^^^^^
= note: wrap the `[closure@$DIR/issue-56164.rs:1:19: 1:21]` in a closure with no arguments: `|| { /* code */ }`

error[E0015]: cannot call non-const closure in constant functions
--> $DIR/issue-56164.rs:1:18
|
Expand All @@ -9,7 +23,7 @@ LL | const fn foo() { (||{})() }
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable

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

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0015`.
Some errors have detailed explanations: E0015, E0277.
For more information about an error, try `rustc --explain E0015`.
1 change: 1 addition & 0 deletions tests/ui/consts/issue-68542-closure-in-array-len.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

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

fn main() {}
19 changes: 17 additions & 2 deletions tests/ui/consts/issue-68542-closure-in-array-len.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
error[E0277]: the trait bound `[closure@$DIR/issue-68542-closure-in-array-len.rs:6:14: 6:16]: Fn<()>` is not satisfied
--> $DIR/issue-68542-closure-in-array-len.rs:6:13
|
LL | a: [(); (|| { 0 })()]
| ^^^^^^^^^^^^ expected an `Fn<()>` closure, found `[closure@$DIR/issue-68542-closure-in-array-len.rs:6:14: 6:16]`
|
= help: the trait `~const Fn<()>` is not implemented for closure `[closure@$DIR/issue-68542-closure-in-array-len.rs:6:14: 6:16]`
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`
--> $DIR/issue-68542-closure-in-array-len.rs:6:13
|
LL | a: [(); (|| { 0 })()]
| ^^^^^^^^^^^^
= note: wrap the `[closure@$DIR/issue-68542-closure-in-array-len.rs:6:14: 6:16]` in a closure with no arguments: `|| { /* code */ }`

error[E0015]: cannot call non-const closure in constants
--> $DIR/issue-68542-closure-in-array-len.rs:6:13
|
Expand All @@ -8,6 +22,7 @@ LL | a: [(); (|| { 0 })()]
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
Some errors have detailed explanations: E0015, E0277.
For more information about an error, try `rustc --explain E0015`.
1 change: 1 addition & 0 deletions tests/ui/never_type/issue-52443.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ fn main() {
//~| ERROR cannot convert
//~| ERROR mutable references
//~| ERROR cannot call
//~| ERROR the trait bound
}
17 changes: 15 additions & 2 deletions tests/ui/never_type/issue-52443.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ LL | [(); { for _ in 0usize.. {}; 0}];
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error[E0277]: the trait bound `RangeFrom<usize>: Iterator` is not satisfied
--> $DIR/issue-52443.rs:9:21
|
LL | [(); { for _ in 0usize.. {}; 0}];
| ^^^^^^^^ `RangeFrom<usize>` is not an iterator
|
= help: the trait `~const Iterator` is not implemented for `RangeFrom<usize>`
note: the trait `Iterator` is implemented for `RangeFrom<usize>`, but that implementation is not `const`
--> $DIR/issue-52443.rs:9:21
|
LL | [(); { for _ in 0usize.. {}; 0}];
| ^^^^^^^^

error[E0015]: cannot call non-const fn `<RangeFrom<usize> as Iterator>::next` in constants
--> $DIR/issue-52443.rs:9:21
|
Expand All @@ -67,7 +80,7 @@ LL | [(); { for _ in 0usize.. {}; 0}];
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable

error: aborting due to 6 previous errors; 1 warning emitted
error: aborting due to 7 previous errors; 1 warning emitted

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

0 comments on commit 6066037

Please sign in to comment.