mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-29 03:27:44 +00:00
Fix #88155
This commit is contained in:
parent
703c557aaa
commit
c75aeaac0b
@ -805,6 +805,8 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut nonconst_call_permission = false;
|
||||||
|
|
||||||
// Attempting to call a trait method?
|
// Attempting to call a trait method?
|
||||||
if let Some(trait_id) = tcx.trait_of_item(callee) {
|
if let Some(trait_id) = tcx.trait_of_item(callee) {
|
||||||
trace!("attempting to call a trait method");
|
trace!("attempting to call a trait method");
|
||||||
@ -824,18 +826,44 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
|
||||||
selcx.select(&obligation).unwrap()
|
selcx.select(&obligation)
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the method is provided via a where-clause that does not use the `?const`
|
match implsrc {
|
||||||
// opt-out, the call is allowed.
|
Ok(Some(ImplSource::Param(_, hir::Constness::Const))) => {
|
||||||
if let Some(ImplSource::Param(_, hir::Constness::Const)) = implsrc {
|
debug!(
|
||||||
debug!(
|
"const_trait_impl: provided {:?} via where-clause in {:?}",
|
||||||
"const_trait_impl: provided {:?} via where-clause in {:?}",
|
trait_ref, param_env
|
||||||
trait_ref, param_env
|
);
|
||||||
);
|
return;
|
||||||
return;
|
}
|
||||||
|
Ok(Some(ImplSource::UserDefined(data))) => {
|
||||||
|
let callee_name = tcx.item_name(callee);
|
||||||
|
if let Some(&did) = tcx.associated_item_def_ids(data.impl_def_id).iter().find(|did| tcx.item_name(**did) == callee_name) {
|
||||||
|
callee = did;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if !tcx.is_const_fn_raw(callee) {
|
||||||
|
// At this point, it is only legal when the caller is marked with
|
||||||
|
// #[default_method_body_is_const], and the callee is in the same
|
||||||
|
// trait.
|
||||||
|
let callee_trait = tcx.trait_of_item(callee);
|
||||||
|
if callee_trait.is_some() {
|
||||||
|
if tcx.has_attr(caller, sym::default_method_body_is_const) {
|
||||||
|
if tcx.trait_of_item(caller) == callee_trait {
|
||||||
|
nonconst_call_permission = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !nonconst_call_permission {
|
||||||
|
self.check_op(ops::FnCallNonConst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve a trait method call to its concrete implementation, which may be in a
|
// 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> {
|
|||||||
let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
|
let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
|
||||||
|
|
||||||
if !tcx.is_const_fn_raw(callee) {
|
if !tcx.is_const_fn_raw(callee) {
|
||||||
let mut permitted = false;
|
if tcx.trait_of_item(callee).is_some() {
|
||||||
|
if tcx.has_attr(callee, sym::default_method_body_is_const) {
|
||||||
let callee_trait = tcx.trait_of_item(callee);
|
// To get to here we must have already found a const impl for the
|
||||||
if let Some(trait_id) = callee_trait {
|
// trait, but for it to still be non-const can be that the impl is
|
||||||
if tcx.has_attr(caller, sym::default_method_body_is_const) {
|
// using default method bodies.
|
||||||
// permit call to non-const fn when caller has default_method_body_is_const..
|
nonconst_call_permission = true;
|
||||||
if tcx.trait_of_item(caller) == callee_trait {
|
|
||||||
// ..and caller and callee are in the same trait.
|
|
||||||
permitted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !permitted {
|
|
||||||
// if trait's impls are all const, permit the call.
|
|
||||||
let mut const_impls = true;
|
|
||||||
tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| {
|
|
||||||
if const_impls {
|
|
||||||
if let hir::Constness::NotConst = tcx.impl_constness(imp) {
|
|
||||||
const_impls = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if const_impls {
|
|
||||||
permitted = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !permitted {
|
if !nonconst_call_permission {
|
||||||
self.check_op(ops::FnCallNonConst);
|
self.check_op(ops::FnCallNonConst);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
13
src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
Normal file
13
src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#![feature(const_fn_trait_bound)]
|
||||||
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
|
pub trait A {
|
||||||
|
fn assoc() -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn foo<T: A>() -> bool {
|
||||||
|
T::assoc()
|
||||||
|
//~^ ERROR calls in constant functions are limited
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
9
src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
Normal file
9
src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
||||||
|
--> $DIR/issue-88155.rs:9:5
|
||||||
|
|
|
||||||
|
LL | T::assoc()
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0015`.
|
Loading…
Reference in New Issue
Block a user