Skip to content

Commit c75aeaa

Browse files
committed
Fix #88155
1 parent 703c557 commit c75aeaa

File tree

3 files changed

+68
-36
lines changed

3 files changed

+68
-36
lines changed

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

+46-36
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,8 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
805805
}
806806
};
807807

808+
let mut nonconst_call_permission = false;
809+
808810
// Attempting to call a trait method?
809811
if let Some(trait_id) = tcx.trait_of_item(callee) {
810812
trace!("attempting to call a trait method");
@@ -824,18 +826,44 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
824826
);
825827

826828
let implsrc = tcx.infer_ctxt().enter(|infcx| {
827-
let mut selcx = SelectionContext::new(&infcx);
828-
selcx.select(&obligation).unwrap()
829+
let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
830+
selcx.select(&obligation)
829831
});
830832

831-
// If the method is provided via a where-clause that does not use the `?const`
832-
// opt-out, the call is allowed.
833-
if let Some(ImplSource::Param(_, hir::Constness::Const)) = implsrc {
834-
debug!(
835-
"const_trait_impl: provided {:?} via where-clause in {:?}",
836-
trait_ref, param_env
837-
);
838-
return;
833+
match implsrc {
834+
Ok(Some(ImplSource::Param(_, hir::Constness::Const))) => {
835+
debug!(
836+
"const_trait_impl: provided {:?} via where-clause in {:?}",
837+
trait_ref, param_env
838+
);
839+
return;
840+
}
841+
Ok(Some(ImplSource::UserDefined(data))) => {
842+
let callee_name = tcx.item_name(callee);
843+
if let Some(&did) = tcx.associated_item_def_ids(data.impl_def_id).iter().find(|did| tcx.item_name(**did) == callee_name) {
844+
callee = did;
845+
}
846+
}
847+
_ => {
848+
if !tcx.is_const_fn_raw(callee) {
849+
// At this point, it is only legal when the caller is marked with
850+
// #[default_method_body_is_const], and the callee is in the same
851+
// trait.
852+
let callee_trait = tcx.trait_of_item(callee);
853+
if callee_trait.is_some() {
854+
if tcx.has_attr(caller, sym::default_method_body_is_const) {
855+
if tcx.trait_of_item(caller) == callee_trait {
856+
nonconst_call_permission = true;
857+
}
858+
}
859+
}
860+
861+
if !nonconst_call_permission {
862+
self.check_op(ops::FnCallNonConst);
863+
return;
864+
}
865+
}
866+
}
839867
}
840868

841869
// Resolve a trait method call to its concrete implementation, which may be in a
@@ -875,34 +903,16 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
875903
let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
876904

877905
if !tcx.is_const_fn_raw(callee) {
878-
let mut permitted = false;
879-
880-
let callee_trait = tcx.trait_of_item(callee);
881-
if let Some(trait_id) = callee_trait {
882-
if tcx.has_attr(caller, sym::default_method_body_is_const) {
883-
// permit call to non-const fn when caller has default_method_body_is_const..
884-
if tcx.trait_of_item(caller) == callee_trait {
885-
// ..and caller and callee are in the same trait.
886-
permitted = true;
887-
}
888-
}
889-
if !permitted {
890-
// if trait's impls are all const, permit the call.
891-
let mut const_impls = true;
892-
tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| {
893-
if const_impls {
894-
if let hir::Constness::NotConst = tcx.impl_constness(imp) {
895-
const_impls = false;
896-
}
897-
}
898-
});
899-
if const_impls {
900-
permitted = true;
901-
}
902-
}
906+
if tcx.trait_of_item(callee).is_some() {
907+
if tcx.has_attr(callee, sym::default_method_body_is_const) {
908+
// To get to here we must have already found a const impl for the
909+
// trait, but for it to still be non-const can be that the impl is
910+
// using default method bodies.
911+
nonconst_call_permission = true;
912+
}
903913
}
904914

905-
if !permitted {
915+
if !nonconst_call_permission {
906916
self.check_op(ops::FnCallNonConst);
907917
return;
908918
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![feature(const_fn_trait_bound)]
2+
#![feature(const_trait_impl)]
3+
4+
pub trait A {
5+
fn assoc() -> bool;
6+
}
7+
8+
pub const fn foo<T: A>() -> bool {
9+
T::assoc()
10+
//~^ ERROR calls in constant functions are limited
11+
}
12+
13+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
2+
--> $DIR/issue-88155.rs:9:5
3+
|
4+
LL | T::assoc()
5+
| ^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0015`.

0 commit comments

Comments
 (0)