Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move const trait bounds checks to MIR constck #109557

Merged
merged 2 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the message say that we expect a const bound here too?

--> $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);
| ++++
Comment on lines -17 to +13
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a regression that has something to do with the spans and how trait selection is different in typeck and constck. I will look into this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the span of the ObligationCause is what caused this. Kind of hard to fix since we don't have access to the machinery that typeck can use.


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