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