@@ -805,6 +805,8 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
805
805
}
806
806
} ;
807
807
808
+ let mut nonconst_call_permission = false ;
809
+
808
810
// Attempting to call a trait method?
809
811
if let Some ( trait_id) = tcx. trait_of_item ( callee) {
810
812
trace ! ( "attempting to call a trait method" ) ;
@@ -824,18 +826,44 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
824
826
) ;
825
827
826
828
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)
829
831
} ) ;
830
832
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
+ }
839
867
}
840
868
841
869
// 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> {
875
903
let is_intrinsic = tcx. fn_sig ( callee) . abi ( ) == RustIntrinsic ;
876
904
877
905
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
+ }
903
913
}
904
914
905
- if !permitted {
915
+ if !nonconst_call_permission {
906
916
self . check_op ( ops:: FnCallNonConst ) ;
907
917
return ;
908
918
}
0 commit comments