Skip to main content

rustc_hir_analysis/check/
always_applicable.rs

1//! This module contains methods that assist in checking that impls are general
2//! enough, i.e. that they always apply to every valid instantaiton of the ADT
3//! they're implemented for.
4//!
5//! This is necessary for `Drop` and negative impls to be well-formed.
6
7use rustc_data_structures::fx::FxHashSet;
8use rustc_errors::codes::*;
9use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
10use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
11use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
12use rustc_middle::span_bug;
13use rustc_middle::ty::util::CheckRegions;
14use rustc_middle::ty::{self, GenericArgsRef, RegionExt, Ty, TyCtxt, TypeVisitableExt, TypingMode};
15use rustc_span::sym;
16use rustc_trait_selection::regions::InferCtxtRegionExt;
17use rustc_trait_selection::traits::{self, ObligationCtxt};
18
19use crate::check::missing_items_must_implement_one_of_err;
20use crate::diagnostics;
21use crate::hir::def_id::{DefId, LocalDefId};
22
23/// This function confirms that the `Drop` implementation identified by
24/// `drop_impl_did` is not any more specialized than the type it is
25/// attached to (Issue #8142).
26///
27/// This means:
28///
29/// 1. The self type must be nominal (this is already checked during
30///    coherence),
31///
32/// 2. The generic region/type parameters of the impl's self type must
33///    all be parameters of the Drop impl itself (i.e., no
34///    specialization like `impl Drop for Foo<i32>`), and,
35///
36/// 3. Any bounds on the generic parameters must be reflected in the
37///    struct/enum definition for the nominal type itself (i.e.
38///    cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
39pub(crate) fn check_drop_impl(
40    tcx: TyCtxt<'_>,
41    drop_impl_did: LocalDefId,
42) -> Result<(), ErrorGuaranteed> {
43    match tcx.impl_polarity(drop_impl_did) {
44        ty::ImplPolarity::Positive => {}
45        ty::ImplPolarity::Negative => {
46            return Err(tcx.dcx().emit_err(diagnostics::DropImplPolarity::Negative {
47                span: tcx.def_span(drop_impl_did),
48            }));
49        }
50        ty::ImplPolarity::Reservation => {
51            return Err(tcx.dcx().emit_err(diagnostics::DropImplPolarity::Reservation {
52                span: tcx.def_span(drop_impl_did),
53            }));
54        }
55    }
56
57    tcx.ensure_result().orphan_check_impl(drop_impl_did)?;
58
59    let self_ty = tcx.type_of(drop_impl_did).instantiate_identity().skip_norm_wip();
60
61    match self_ty.kind() {
62        ty::Adt(adt_def, adt_to_impl_args) => {
63            ensure_impl_params_and_item_params_correspond(
64                tcx,
65                drop_impl_did,
66                adt_def.did(),
67                adt_to_impl_args,
68            )?;
69
70            ensure_all_fields_are_const_destruct(tcx, drop_impl_did, adt_def.did())?;
71
72            ensure_impl_predicates_are_implied_by_item_defn(
73                tcx,
74                drop_impl_did,
75                adt_def.did(),
76                adt_to_impl_args,
77            )?;
78
79            check_drop_xor_pin_drop(tcx, adt_def.did(), drop_impl_did)?;
80
81            Ok(())
82        }
83        _ => {
84            ::rustc_middle::util::bug::span_bug_fmt(tcx.def_span(drop_impl_did),
    format_args!("incoherent impl of Drop"));span_bug!(tcx.def_span(drop_impl_did), "incoherent impl of Drop");
85        }
86    }
87}
88
89pub(crate) fn check_negative_auto_trait_impl<'tcx>(
90    tcx: TyCtxt<'tcx>,
91    impl_def_id: LocalDefId,
92    impl_trait_ref: ty::TraitRef<'tcx>,
93    polarity: ty::ImplPolarity,
94) -> Result<(), ErrorGuaranteed> {
95    let ty::ImplPolarity::Negative = polarity else {
96        return Ok(());
97    };
98
99    if !tcx.trait_is_auto(impl_trait_ref.def_id) {
100        return Ok(());
101    }
102
103    if tcx.defaultness(impl_def_id).is_default() {
104        tcx.dcx().span_delayed_bug(tcx.def_span(impl_def_id), "default impl cannot be negative");
105    }
106
107    tcx.ensure_result().orphan_check_impl(impl_def_id)?;
108
109    match impl_trait_ref.self_ty().kind() {
110        ty::Adt(adt_def, adt_to_impl_args) => {
111            ensure_impl_params_and_item_params_correspond(
112                tcx,
113                impl_def_id,
114                adt_def.did(),
115                adt_to_impl_args,
116            )?;
117
118            ensure_impl_predicates_are_implied_by_item_defn(
119                tcx,
120                impl_def_id,
121                adt_def.did(),
122                adt_to_impl_args,
123            )
124        }
125        _ => {
126            if tcx.features().auto_traits() {
127                // NOTE: We ignore the applicability check for negative auto impls
128                // defined in libcore. In the (almost impossible) future where we
129                // stabilize auto impls, then the proper applicability check MUST
130                // be implemented here to handle non-ADT rigid types.
131                Ok(())
132            } else {
133                Err(tcx.dcx().span_delayed_bug(
134                    tcx.def_span(impl_def_id),
135                    "incoherent impl of negative auto trait",
136                ))
137            }
138        }
139    }
140}
141
142fn ensure_impl_params_and_item_params_correspond<'tcx>(
143    tcx: TyCtxt<'tcx>,
144    impl_def_id: LocalDefId,
145    adt_def_id: DefId,
146    adt_to_impl_args: GenericArgsRef<'tcx>,
147) -> Result<(), ErrorGuaranteed> {
148    let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_args, CheckRegions::OnlyParam) else {
149        return Ok(());
150    };
151
152    let impl_span = tcx.def_span(impl_def_id);
153    let item_span = tcx.def_span(adt_def_id);
154    let self_descr = tcx.def_descr(adt_def_id);
155    let polarity = match tcx.impl_polarity(impl_def_id) {
156        ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
157        ty::ImplPolarity::Negative => "!",
158    };
159    let trait_name = tcx.item_name(tcx.impl_trait_id(impl_def_id.to_def_id()));
160    let mut err = {
    tcx.dcx().struct_span_err(impl_span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`{0}{1}` impls cannot be specialized",
                            polarity, trait_name))
                })).with_code(E0366)
}struct_span_code_err!(
161        tcx.dcx(),
162        impl_span,
163        E0366,
164        "`{polarity}{trait_name}` impls cannot be specialized",
165    );
166    match arg {
167        ty::util::NotUniqueParam::DuplicateParam(arg) => {
168            err.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` is mentioned multiple times",
                arg))
    })format!("`{arg}` is mentioned multiple times"))
169        }
170        ty::util::NotUniqueParam::NotParam(arg) => {
171            err.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}` is not a generic parameter",
                arg))
    })format!("`{arg}` is not a generic parameter"))
172        }
173    };
174    err.span_note(
175        item_span,
176        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("use the same sequence of generic lifetime, type and const parameters as the {0} definition",
                self_descr))
    })format!(
177            "use the same sequence of generic lifetime, type and const parameters \
178                     as the {self_descr} definition",
179        ),
180    );
181    Err(err.emit())
182}
183
184fn ensure_all_fields_are_const_destruct<'tcx>(
185    tcx: TyCtxt<'tcx>,
186    impl_def_id: LocalDefId,
187    adt_def_id: DefId,
188) -> Result<(), ErrorGuaranteed> {
189    if !tcx.is_conditionally_const(impl_def_id) {
190        return Ok(());
191    }
192    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
193    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
194
195    let impl_span = tcx.def_span(impl_def_id.to_def_id());
196    let env = ty::EarlyBinder::bind(tcx, tcx.param_env(impl_def_id))
197        .instantiate_identity()
198        .skip_norm_wip();
199    let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
200    let destruct_trait = tcx.lang_items().destruct_trait().unwrap();
201    for field in tcx.adt_def(adt_def_id).all_fields() {
202        let field_ty = field.ty(tcx, args).skip_norm_wip();
203        let cause = traits::ObligationCause::new(
204            tcx.def_span(field.did),
205            impl_def_id,
206            ObligationCauseCode::Misc,
207        );
208        ocx.register_obligation(traits::Obligation::new(
209            tcx,
210            cause,
211            env,
212            ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
213                trait_ref: ty::TraitRef::new(tcx, destruct_trait, [field_ty]),
214                constness: ty::BoundConstness::Maybe,
215            }),
216        ));
217    }
218    ocx.evaluate_obligations_error_on_ambiguity()
219        .into_iter()
220        .map(|error| {
221            let ty::ClauseKind::HostEffect(eff) =
222                error.root_obligation.predicate.expect_clause().kind().no_bound_vars().unwrap()
223            else {
224                ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
225            };
226            let field_ty = eff.trait_ref.self_ty();
227            let mut diag = {
    tcx.dcx().struct_span_err(error.root_obligation.cause.span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`{0}` does not implement `[const] Destruct`",
                            field_ty))
                })).with_code(E0367)
}struct_span_code_err!(
228                tcx.dcx(),
229                error.root_obligation.cause.span,
230                E0367,
231                "`{field_ty}` does not implement `[const] Destruct`",
232            )
233            .with_span_note(impl_span, "required for this `Drop` impl");
234            if field_ty.has_param()
235                && let Some(generics) = tcx.hir_node_by_def_id(impl_def_id).generics()
236            {
237                let destruct_def_id = tcx.lang_items().destruct_trait();
238                ty::suggest_constraining_type_param(
239                    tcx,
240                    generics,
241                    &mut diag,
242                    &field_ty.to_string(),
243                    "[const] Destruct",
244                    destruct_def_id,
245                    None,
246                );
247            }
248            Err(diag.emit())
249        })
250        .collect()
251}
252
253/// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be
254/// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are
255/// implied by the ADT being well formed.
256fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
257    tcx: TyCtxt<'tcx>,
258    impl_def_id: LocalDefId,
259    adt_def_id: DefId,
260    adt_to_impl_args: GenericArgsRef<'tcx>,
261) -> Result<(), ErrorGuaranteed> {
262    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
263    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
264
265    let impl_span = tcx.def_span(impl_def_id.to_def_id());
266    let trait_name = tcx.item_name(tcx.impl_trait_id(impl_def_id.to_def_id()));
267    let polarity = match tcx.impl_polarity(impl_def_id) {
268        ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
269        ty::ImplPolarity::Negative => "!",
270    };
271    // Take the param-env of the adt and instantiate the args that show up in
272    // the implementation's self type. This gives us the assumptions that the
273    // self ty of the implementation is allowed to know just from it being a
274    // well-formed adt, since that's all we're allowed to assume while proving
275    // the Drop implementation is not specialized.
276    //
277    // We don't need to normalize this param-env or anything, since we're only
278    // instantiating it with free params, so no additional param-env normalization
279    // can occur on top of what has been done in the param_env query itself.
280    //
281    // Note: Ideally instead of instantiating the `ParamEnv` with the arguments from the impl ty we
282    // could instead use identity args for the adt. Unfortunately this would cause any errors to
283    // reference the params from the ADT instead of from the impl which is bad UX. To resolve
284    // this we "rename" the ADT's params to be the impl's params which should not affect behaviour.
285    let impl_adt_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args);
286    let adt_env = ty::EarlyBinder::bind_unchecked(tcx.param_env(adt_def_id))
287        .instantiate(tcx, adt_to_impl_args)
288        .skip_norm_wip();
289
290    let fresh_impl_args = infcx.fresh_args_for_item(impl_span, impl_def_id.to_def_id());
291    let fresh_adt_ty =
292        tcx.impl_trait_ref(impl_def_id).instantiate(tcx, fresh_impl_args).skip_norm_wip().self_ty();
293
294    ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty)
295        .expect("equating fully generic trait ref should never fail");
296
297    for (clause, span) in tcx.clauses_of(impl_def_id).instantiate(tcx, fresh_impl_args) {
298        let normalize_cause = traits::ObligationCause::misc(span, impl_def_id);
299        let pred = ocx.normalize(&normalize_cause, adt_env, clause);
300        let cause = traits::ObligationCause::new(
301            span,
302            impl_def_id,
303            ObligationCauseCode::AlwaysApplicableImpl,
304        );
305        ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred));
306    }
307
308    // All of the custom error reporting logic is to preserve parity with the old
309    // error messages.
310    //
311    // They can probably get removed with better treatment of the new `DropImpl`
312    // obligation cause code, and perhaps some custom logic in `report_region_errors`.
313
314    let errors = ocx.evaluate_obligations_error_on_ambiguity();
315    if !errors.is_empty() {
316        let mut guar = None;
317        let mut root_predicates = FxHashSet::default();
318        for error in errors {
319            let root_predicate = error.root_obligation.predicate;
320            if root_predicates.insert(root_predicate) {
321                let item_span = tcx.def_span(adt_def_id);
322                let self_descr = tcx.def_descr(adt_def_id);
323                guar = Some(
324                    {
    tcx.dcx().struct_span_err(error.root_obligation.cause.span,
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`{0}{1}` impl requires `{2}` but the {3} it is implemented for does not",
                            polarity, trait_name, root_predicate, self_descr))
                })).with_code(E0367)
}struct_span_code_err!(
325                        tcx.dcx(),
326                        error.root_obligation.cause.span,
327                        E0367,
328                        "`{polarity}{trait_name}` impl requires `{root_predicate}` \
329                        but the {self_descr} it is implemented for does not",
330                    )
331                    .with_span_note(item_span, "the implementor must specify the same requirement")
332                    .emit(),
333                );
334            }
335        }
336        return Err(guar.unwrap());
337    }
338
339    let errors = ocx.infcx.resolve_regions(impl_def_id, adt_env, []);
340    if !errors.is_empty() {
341        let mut guar = None;
342        for error in errors {
343            let item_span = tcx.def_span(adt_def_id);
344            let self_descr = tcx.def_descr(adt_def_id);
345            let outlives = match error {
346                RegionResolutionError::ConcreteFailure(_, a, b) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", b, a))
    })format!("{b}: {a}"),
347                RegionResolutionError::GenericBoundFailure(_, generic, r) => {
348                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", generic, r))
    })format!("{generic}: {r}")
349                }
350                RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}: {1}", b, a))
    })format!("{b}: {a}"),
351                RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
352                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{1}: {0}",
                ty::Region::new_var(tcx, a), b))
    })format!("{b}: {a}", a = ty::Region::new_var(tcx, a))
353                }
354                RegionResolutionError::CannotNormalize(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
355            };
356            guar = Some(
357                {
    tcx.dcx().struct_span_err(error.origin().span(),
            ::alloc::__export::must_use({
                    ::alloc::fmt::format(format_args!("`{0}{1}` impl requires `{2}` but the {3} it is implemented for does not",
                            polarity, trait_name, outlives, self_descr))
                })).with_code(E0367)
}struct_span_code_err!(
358                    tcx.dcx(),
359                    error.origin().span(),
360                    E0367,
361                    "`{polarity}{trait_name}` impl requires `{outlives}` \
362                    but the {self_descr} it is implemented for does not",
363                )
364                .with_span_note(item_span, "the implementor must specify the same requirement")
365                .emit(),
366            );
367        }
368        return Err(guar.unwrap());
369    }
370
371    Ok(())
372}
373
374/// This function checks at least and at most one of `Drop::drop` and `Drop::pin_drop` is implemented.
375/// It also checks that `Drop::pin_drop` must be implemented if `#[pin_v2]` is present on the type.
376fn check_drop_xor_pin_drop<'tcx>(
377    tcx: TyCtxt<'tcx>,
378    adt_def_id: DefId,
379    drop_impl_did: LocalDefId,
380) -> Result<(), ErrorGuaranteed> {
381    let mut drop_span = None;
382    let mut pin_drop_span = None;
383    for item in tcx.associated_items(drop_impl_did).in_definition_order() {
384        match item.kind {
385            ty::AssocKind::Fn { name: sym::drop, .. } => {
386                drop_span = Some(tcx.def_span(item.def_id))
387            }
388            ty::AssocKind::Fn { name: sym::pin_drop, .. } => {
389                pin_drop_span = Some(tcx.def_span(item.def_id))
390            }
391            _ => {}
392        }
393    }
394
395    match (drop_span, pin_drop_span) {
396        (None, None) => {
397            if tcx.features().pin_ergonomics() {
398                return Err(missing_items_must_implement_one_of_err(
399                    tcx,
400                    drop_impl_did,
401                    [sym::drop, sym::pin_drop].into_iter(),
402                    None,
403                ));
404            } else {
405                return Err(tcx
406                    .dcx()
407                    .span_delayed_bug(tcx.def_span(drop_impl_did), "missing `Drop::drop`"));
408            }
409        }
410        (Some(span), None) => {
411            if tcx.adt_def(adt_def_id).is_pin_project() {
412                let pin_v2_span = {
    {
        'done:
            {
            for i in ::rustc_hir::attrs::HasAttrs::get_attrs(adt_def_id, &tcx)
                {
                #[allow(unused_imports)]
                use ::rustc_hir::attrs::AttributeKind::*;
                let i: &::rustc_hir::Attribute = i;
                match i {
                    ::rustc_hir::Attribute::Parsed(PinV2(attr)) => {
                        break 'done Some(*attr);
                    }
                    ::rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}rustc_hir::find_attr!(tcx, adt_def_id, PinV2(attr) => *attr);
413                let adt_name = tcx.item_name(adt_def_id);
414                return Err(tcx.dcx().emit_err(crate::diagnostics::PinV2WithoutPinDrop {
415                    span,
416                    pin_v2_span,
417                    adt_name,
418                }));
419            }
420        }
421        (None, Some(span)) => {
422            if !tcx.features().pin_ergonomics() {
423                return Err(tcx.dcx().span_delayed_bug(
424                    span,
425                    "`Drop::pin_drop` should be guarded by the library feature gate",
426                ));
427            }
428        }
429        (Some(drop_span), Some(pin_drop_span)) => {
430            return Err(tcx.dcx().emit_err(crate::diagnostics::ConflictImplDropAndPinDrop {
431                span: tcx.def_span(drop_impl_did),
432                drop_span,
433                pin_drop_span,
434            }));
435        }
436    }
437    Ok(())
438}