@@ -80,7 +80,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
80
80
use rustc_span:: Span ;
81
81
use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
82
82
use rustc_trait_selection:: traits:: outlives_bounds:: InferCtxtExt as _;
83
- use rustc_trait_selection:: traits:: { self , translate_substs , wf, ObligationCtxt } ;
83
+ use rustc_trait_selection:: traits:: { self , translate_substs_with_cause , wf, ObligationCtxt } ;
84
84
85
85
pub ( super ) fn check_min_specialization ( tcx : TyCtxt < ' _ > , impl_def_id : LocalDefId ) {
86
86
if let Some ( node) = parent_specialization_node ( tcx, impl_def_id) {
@@ -100,12 +100,19 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
100
100
// Implementing a normal trait isn't a specialization.
101
101
return None ;
102
102
}
103
+ if trait_def. is_marker {
104
+ // Overlapping marker implementations are not really specializations.
105
+ return None ;
106
+ }
103
107
Some ( impl2_node)
104
108
}
105
109
106
110
/// Check that `impl1` is a sound specialization
107
111
#[ instrument( level = "debug" , skip( tcx) ) ]
108
112
fn check_always_applicable ( tcx : TyCtxt < ' _ > , impl1_def_id : LocalDefId , impl2_node : Node ) {
113
+ let span = tcx. def_span ( impl1_def_id) ;
114
+ check_has_items ( tcx, impl1_def_id, impl2_node, span) ;
115
+
109
116
if let Some ( ( impl1_substs, impl2_substs) ) = get_impl_substs ( tcx, impl1_def_id, impl2_node) {
110
117
let impl2_def_id = impl2_node. def_id ( ) ;
111
118
debug ! ( ?impl2_def_id, ?impl2_substs) ;
@@ -116,14 +123,20 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
116
123
unconstrained_parent_impl_substs ( tcx, impl2_def_id, impl2_substs)
117
124
} ;
118
125
119
- let span = tcx. def_span ( impl1_def_id) ;
120
126
check_constness ( tcx, impl1_def_id, impl2_node, span) ;
121
127
check_static_lifetimes ( tcx, & parent_substs, span) ;
122
128
check_duplicate_params ( tcx, impl1_substs, & parent_substs, span) ;
123
129
check_predicates ( tcx, impl1_def_id, impl1_substs, impl2_node, impl2_substs, span) ;
124
130
}
125
131
}
126
132
133
+ fn check_has_items ( tcx : TyCtxt < ' _ > , impl1_def_id : LocalDefId , impl2_node : Node , span : Span ) {
134
+ if let Node :: Impl ( impl2_id) = impl2_node && tcx. associated_item_def_ids ( impl1_def_id) . is_empty ( ) {
135
+ let base_impl_span = tcx. def_span ( impl2_id) ;
136
+ tcx. sess . emit_err ( errors:: EmptySpecialization { span, base_impl_span } ) ;
137
+ }
138
+ }
139
+
127
140
/// Check that the specializing impl `impl1` is at least as const as the base
128
141
/// impl `impl2`
129
142
fn check_constness ( tcx : TyCtxt < ' _ > , impl1_def_id : LocalDefId , impl2_node : Node , span : Span ) {
@@ -167,8 +180,21 @@ fn get_impl_substs(
167
180
ocx. assumed_wf_types ( param_env, tcx. def_span ( impl1_def_id) , impl1_def_id) ;
168
181
169
182
let impl1_substs = InternalSubsts :: identity_for_item ( tcx, impl1_def_id) ;
170
- let impl2_substs =
171
- translate_substs ( infcx, param_env, impl1_def_id. to_def_id ( ) , impl1_substs, impl2_node) ;
183
+ let impl1_span = tcx. def_span ( impl1_def_id) ;
184
+ let impl2_substs = translate_substs_with_cause (
185
+ infcx,
186
+ param_env,
187
+ impl1_def_id. to_def_id ( ) ,
188
+ impl1_substs,
189
+ impl2_node,
190
+ |_, span| {
191
+ traits:: ObligationCause :: new (
192
+ impl1_span,
193
+ impl1_def_id,
194
+ traits:: ObligationCauseCode :: BindingObligation ( impl2_node. def_id ( ) , span) ,
195
+ )
196
+ } ,
197
+ ) ;
172
198
173
199
let errors = ocx. select_all_or_error ( ) ;
174
200
if !errors. is_empty ( ) {
0 commit comments