@@ -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 }
0 commit comments