@@ -6,6 +6,7 @@ use std::iter;
66use rustc_data_structures:: fx:: FxIndexMap ;
77use rustc_hir:: attrs:: { EiiDecl , EiiImpl } ;
88use rustc_hir:: def_id:: { CrateNum , DefId , LOCAL_CRATE } ;
9+ use rustc_middle:: middle:: dependency_format:: Linkage ;
910use rustc_middle:: ty:: TyCtxt ;
1011use rustc_session:: config:: CrateType ;
1112
@@ -26,6 +27,23 @@ fn get_checking_mode(tcx: TyCtxt<'_>) -> CheckingMode {
2627 }
2728}
2829
30+ fn linked_in_dylib ( tcx : TyCtxt < ' _ > , cnum : CrateNum ) -> bool {
31+ if cnum == LOCAL_CRATE {
32+ return false ;
33+ }
34+
35+ let source = tcx. used_crate_source ( cnum) ;
36+ // If the only code artifact available is a dylib, any default impl inside it
37+ // has already been materialized and cannot be overridden downstream.
38+ let only_available_as_dylib =
39+ source. rlib . is_none ( ) && ( source. dylib . is_some ( ) || source. sdylib_interface . is_some ( ) ) ;
40+
41+ only_available_as_dylib
42+ || tcx. dependency_formats ( ( ) ) . iter ( ) . any ( |( _, formats) | {
43+ matches ! ( formats. get( cnum) , Some ( Linkage :: Dynamic | Linkage :: IncludedFromDylib ) )
44+ } )
45+ }
46+
2947/// Checks for a given crate, what EIIs need to be generated in it.
3048/// This is usually a small subset of all EIIs.
3149///
@@ -93,21 +111,31 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, ():
93111 }
94112 }
95113
96- // more than one explicit implementation (across all crates)
97- // is instantly an error.
98- if explicit_impls. len ( ) > 1 {
114+ let mut duplicate_impls = explicit_impls. clone ( ) ;
115+ if !duplicate_impls. is_empty ( ) {
116+ duplicate_impls. extend (
117+ default_impls
118+ . iter ( )
119+ . copied ( )
120+ . filter ( |( _, impl_crate) | linked_in_dylib ( tcx, * impl_crate) ) ,
121+ ) ;
122+ }
123+
124+ // more than one explicit implementation (across all crates), or an explicit
125+ // implementation overriding a default implementation from a dylib, is instantly an error.
126+ if duplicate_impls. len ( ) > 1 {
99127 tcx. dcx ( ) . emit_err ( DuplicateEiiImpls {
100128 name : decl. name . name ,
101- first_span : tcx. def_span ( explicit_impls [ 0 ] . 0 ) ,
102- first_crate : tcx. crate_name ( explicit_impls [ 0 ] . 1 ) ,
103- second_span : tcx. def_span ( explicit_impls [ 1 ] . 0 ) ,
104- second_crate : tcx. crate_name ( explicit_impls [ 1 ] . 1 ) ,
129+ first_span : tcx. def_span ( duplicate_impls [ 0 ] . 0 ) ,
130+ first_crate : tcx. crate_name ( duplicate_impls [ 0 ] . 1 ) ,
131+ second_span : tcx. def_span ( duplicate_impls [ 1 ] . 0 ) ,
132+ second_crate : tcx. crate_name ( duplicate_impls [ 1 ] . 1 ) ,
105133
106134 help : ( ) ,
107135
108- additional_crates : ( explicit_impls . len ( ) > 2 ) . then_some ( ( ) ) ,
109- num_additional_crates : explicit_impls . len ( ) - 2 ,
110- additional_crate_names : explicit_impls [ 2 ..]
136+ additional_crates : ( duplicate_impls . len ( ) > 2 ) . then_some ( ( ) ) ,
137+ num_additional_crates : duplicate_impls . len ( ) - 2 ,
138+ additional_crate_names : duplicate_impls [ 2 ..]
111139 . iter ( )
112140 . map ( |i| format ! ( "`{}`" , tcx. crate_name( i. 1 ) ) )
113141 . collect :: < Vec < _ > > ( )
0 commit comments