Skip to main content

rustc_builtin_macros/deriving/
coerce_pointee.rs

1use ast::HasAttrs;
2use rustc_ast::mut_visit::MutVisitor;
3use rustc_ast::visit::{BoundKind, Visitor};
4use rustc_ast::{
5    self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind,
6    TraitBoundModifiers, VariantData, WherePredicate,
7};
8use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
9use rustc_errors::E0802;
10use rustc_expand::base::ExtCtxt;
11use rustc_macros::Diagnostic;
12use rustc_span::{Ident, Span, Symbol, sym};
13use thin_vec::{ThinVec, thin_vec};
14
15use crate::diagnostics;
16
17macro_rules! path {
18    ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
19}
20
21pub(crate) fn expand_deriving_coerce_pointee(
22    cx: &ExtCtxt<'_>,
23    span: Span,
24    item: &ast::Item,
25    push: &mut dyn FnMut(Box<ast::Item>),
26    _is_const: bool,
27) {
28    DetectNonGenericPointeeAttr { cx }.visit_item(item);
29
30    let (name_ident, generics) = if let ItemKind::Struct(ident, g, struct_data) = &item.kind {
31        if !#[allow(non_exhaustive_omitted_patterns)] match struct_data {
    VariantData::Struct { fields, recovered: _ } |
        VariantData::Tuple(fields, _) if !fields.is_empty() => true,
    _ => false,
}matches!(
32            struct_data,
33            VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _)
34                if !fields.is_empty())
35        {
36            cx.dcx().emit_err(RequireOneField { span });
37            return;
38        }
39        (*ident, g)
40    } else {
41        cx.dcx().emit_err(RequireTransparent { span });
42        return;
43    };
44
45    // Convert generic parameters (from the struct) into generic args.
46    let self_params: Vec<_> = generics
47        .params
48        .iter()
49        .map(|p| match p.kind {
50            GenericParamKind::Lifetime => GenericArg::Lifetime(cx.lifetime(p.span(), p.ident)),
51            GenericParamKind::Type { .. } => GenericArg::Type(cx.ty_ident(p.span(), p.ident)),
52            GenericParamKind::Const { .. } => GenericArg::Const(cx.const_ident(p.span(), p.ident)),
53        })
54        .collect();
55    let type_params: Vec<_> = generics
56        .params
57        .iter()
58        .enumerate()
59        .filter_map(|(idx, p)| {
60            if let GenericParamKind::Type { .. } = p.kind {
61                Some((idx, p.span(), p.attrs().iter().any(|attr| attr.has_name(sym::pointee))))
62            } else {
63                None
64            }
65        })
66        .collect();
67
68    let pointee_param_idx = if type_params.is_empty() {
69        // `#[derive(CoercePointee)]` requires at least one generic type on the target `struct`
70        cx.dcx().emit_err(RequireOneGeneric { span });
71        return;
72    } else if type_params.len() == 1 {
73        // Regardless of the only type param being designed as `#[pointee]` or not, we can just use it as such
74        type_params[0].0
75    } else {
76        let mut pointees = type_params
77            .iter()
78            .filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span)));
79        match (pointees.next(), pointees.next()) {
80            (Some((idx, _span)), None) => idx,
81            (None, _) => {
82                cx.dcx().emit_err(RequireOnePointee { span });
83                return;
84            }
85            (Some((_, one)), Some((_, another))) => {
86                cx.dcx().emit_err(TooManyPointees { one, another });
87                return;
88            }
89        }
90    };
91
92    // Create the type of `self`.
93    let path = cx.path_all(span, false, ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [name_ident]))vec![name_ident], self_params.clone());
94    let self_type = cx.ty_path(path);
95
96    // Declare helper function that adds implementation blocks.
97    // FIXME(dingxiangfei2009): Investigate the set of attributes on target struct to be propagated to impls
98    let attrs = {
    let len = [()].len();
    let mut vec = ::thin_vec::ThinVec::with_capacity(len);
    vec.push(cx.attr_word(sym::automatically_derived, span));
    vec
}thin_vec![cx.attr_word(sym::automatically_derived, span),];
99    // # Validity assertion which will be checked later in `rustc_hir_analysis::coherence::builtins`.
100    {
101        let trait_path =
102            cx.path_all(span, true, ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [Ident::new(sym::core, span), Ident::new(sym::marker, span),
                Ident::new(sym::CoercePointeeValidated, span)]))path!(span, core::marker::CoercePointeeValidated), ::alloc::vec::Vec::new()vec![]);
103        let trait_ref = cx.trait_ref(trait_path);
104        push(
105            cx.item(
106                span,
107                attrs.clone(),
108                ast::ItemKind::Impl(ast::Impl {
109                    generics: Generics {
110                        params: generics
111                            .params
112                            .iter()
113                            .map(|p| match &p.kind {
114                                GenericParamKind::Lifetime => {
115                                    cx.lifetime_param(p.span(), p.ident, p.bounds.clone())
116                                }
117                                GenericParamKind::Type { default: _ } => {
118                                    cx.typaram(p.span(), p.ident, p.bounds.clone(), None)
119                                }
120                                GenericParamKind::Const { ty, span: _, default: _ } => cx
121                                    .const_param(
122                                        p.span(),
123                                        p.ident,
124                                        p.bounds.clone(),
125                                        ty.clone(),
126                                        None,
127                                    ),
128                            })
129                            .collect(),
130                        where_clause: generics.where_clause.clone(),
131                        span: generics.span,
132                    },
133                    of_trait: Some(Box::new(ast::TraitImplHeader {
134                        safety: ast::Safety::Default,
135                        polarity: ast::ImplPolarity::Positive,
136                        defaultness: ast::Defaultness::Implicit,
137                        trait_ref,
138                    })),
139                    constness: ast::Const::No,
140                    self_ty: self_type.clone(),
141                    items: ThinVec::new(),
142                }),
143            ),
144        );
145    }
146    let mut add_impl_block = |generics, trait_symbol, trait_args| {
147        let mut parts = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [Ident::new(sym::core, span), Ident::new(sym::ops, span)]))path!(span, core::ops);
148        parts.push(Ident::new(trait_symbol, span));
149        let trait_path = cx.path_all(span, true, parts, trait_args);
150        let trait_ref = cx.trait_ref(trait_path);
151        let item = cx.item(
152            span,
153            attrs.clone(),
154            ast::ItemKind::Impl(ast::Impl {
155                generics,
156                of_trait: Some(Box::new(ast::TraitImplHeader {
157                    safety: ast::Safety::Default,
158                    polarity: ast::ImplPolarity::Positive,
159                    defaultness: ast::Defaultness::Implicit,
160                    trait_ref,
161                })),
162                constness: ast::Const::No,
163                self_ty: self_type.clone(),
164                items: ThinVec::new(),
165            }),
166        );
167        push(item);
168    };
169
170    // Create unsized `self`, that is, one where the `#[pointee]` type arg is replaced with `__S`. For
171    // example, instead of `MyType<'a, T>`, it will be `MyType<'a, __S>`.
172    let s_ty = cx.ty_ident(span, Ident::new(sym::__S, span));
173    let mut alt_self_params = self_params;
174    alt_self_params[pointee_param_idx] = GenericArg::Type(s_ty.clone());
175    let alt_self_type = cx.ty_path(cx.path_all(span, false, ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [name_ident]))vec![name_ident], alt_self_params));
176
177    // # Add `Unsize<__S>` bound to `#[pointee]` at the generic parameter location
178    //
179    // Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it.
180    let mut impl_generics = generics.clone();
181    let pointee_ty_ident = generics.params[pointee_param_idx].ident;
182    let mut self_bounds;
183    {
184        let pointee = &mut impl_generics.params[pointee_param_idx];
185        self_bounds = pointee.bounds.clone();
186        if !contains_maybe_sized_bound(&self_bounds)
187            && !contains_maybe_sized_bound_on_pointee(
188                &generics.where_clause.predicates,
189                pointee_ty_ident.name,
190            )
191        {
192            cx.dcx().emit_err(RequiresMaybeSized {
193                span: pointee_ty_ident.span,
194                name: pointee_ty_ident,
195            });
196            return;
197        }
198        let arg = GenericArg::Type(s_ty.clone());
199        let unsize = cx.path_all(span, true, ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [Ident::new(sym::core, span), Ident::new(sym::marker, span),
                Ident::new(sym::Unsize, span)]))path!(span, core::marker::Unsize), ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [arg]))vec![arg]);
200        pointee.bounds.push(cx.trait_bound(unsize, false));
201        // Drop `#[pointee]` attribute since it should not be recognized outside `derive(CoercePointee)`
202        pointee.attrs.retain(|attr| !attr.has_name(sym::pointee));
203    }
204
205    // # Rewrite generic parameter bounds
206    // For each bound `U: ..` in `struct<U: ..>`, make a new bound with `__S` in place of `#[pointee]`
207    // Example:
208    // ```
209    // struct<
210    //     U: Trait<T>,
211    //     #[pointee] T: Trait<T> + ?Sized,
212    //     V: Trait<T>> ...
213    // ```
214    // ... generates this `impl` generic parameters
215    // ```
216    // impl<
217    //     U: Trait<T> + Trait<__S>,
218    //     T: Trait<T> + ?Sized + Unsize<__S>, // (**)
219    //     __S: Trait<__S> + ?Sized, // (*)
220    //     V: Trait<T> + Trait<__S>> ...
221    // ```
222    // The new bound marked with (*) has to be done separately.
223    // See next section
224    for (idx, (params, orig_params)) in
225        impl_generics.params.iter_mut().zip(&generics.params).enumerate()
226    {
227        // Default type parameters are rejected for `impl` block.
228        // We should drop them now.
229        match &mut params.kind {
230            ast::GenericParamKind::Const { default, .. } => *default = None,
231            ast::GenericParamKind::Type { default } => *default = None,
232            ast::GenericParamKind::Lifetime => {}
233        }
234        // We CANNOT rewrite `#[pointee]` type parameter bounds.
235        // This has been set in stone. (**)
236        // So we skip over it.
237        // Otherwise, we push extra bounds involving `__S`.
238        if idx != pointee_param_idx {
239            for bound in &orig_params.bounds {
240                let mut bound = bound.clone();
241                let mut substitution = TypeSubstitution {
242                    from_name: pointee_ty_ident.name,
243                    to_ty: &s_ty,
244                    rewritten: false,
245                };
246                substitution.visit_param_bound(&mut bound, BoundKind::Bound);
247                if substitution.rewritten {
248                    // We found use of `#[pointee]` somewhere,
249                    // so we make a new bound using `__S` in place of `#[pointee]`
250                    params.bounds.push(bound);
251                }
252            }
253        }
254    }
255
256    // # Insert `__S` type parameter
257    //
258    // We now insert `__S` with the missing bounds marked with (*) above.
259    // We should also write the bounds from `#[pointee]` to `__S` as required by `Unsize<__S>`.
260    {
261        let mut substitution =
262            TypeSubstitution { from_name: pointee_ty_ident.name, to_ty: &s_ty, rewritten: false };
263        for bound in &mut self_bounds {
264            substitution.visit_param_bound(bound, BoundKind::Bound);
265        }
266    }
267
268    // # Rewrite `where` clauses
269    //
270    // Move on to `where` clauses.
271    // Example:
272    // ```
273    // struct MyPointer<#[pointee] T, ..>
274    // where
275    //   U: Trait<V> + Trait<T>,
276    //   Companion<T>: Trait<T>,
277    //   T: Trait<T> + ?Sized,
278    // { .. }
279    // ```
280    // ... will have a impl prelude like so
281    // ```
282    // impl<..> ..
283    // where
284    //   U: Trait<V> + Trait<T>,
285    //   U: Trait<__S>,
286    //   Companion<T>: Trait<T>,
287    //   Companion<__S>: Trait<__S>,
288    //   T: Trait<T> + ?Sized,
289    //   __S: Trait<__S> + ?Sized,
290    // ```
291    //
292    // We should also write a few new `where` bounds from `#[pointee] T` to `__S`
293    // as well as any bound that indirectly involves the `#[pointee] T` type.
294    for predicate in &generics.where_clause.predicates {
295        if let ast::WherePredicateKind::BoundPredicate(bound) = &predicate.kind {
296            let mut substitution = TypeSubstitution {
297                from_name: pointee_ty_ident.name,
298                to_ty: &s_ty,
299                rewritten: false,
300            };
301            let mut kind = ast::WherePredicateKind::BoundPredicate(bound.clone());
302            substitution.visit_where_predicate_kind(&mut kind);
303            if substitution.rewritten {
304                let predicate = ast::WherePredicate {
305                    attrs: predicate.attrs.clone(),
306                    kind,
307                    span: predicate.span,
308                    id: ast::DUMMY_NODE_ID,
309                    is_placeholder: false,
310                };
311                impl_generics.where_clause.predicates.push(predicate);
312            }
313        }
314    }
315
316    let extra_param = cx.typaram(span, Ident::new(sym::__S, span), self_bounds, None);
317    impl_generics.params.insert(pointee_param_idx + 1, extra_param);
318
319    // Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`.
320    let gen_args = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [GenericArg::Type(alt_self_type)]))vec![GenericArg::Type(alt_self_type)];
321    add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone());
322    add_impl_block(impl_generics, sym::CoerceUnsized, gen_args);
323}
324
325fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool {
326    for bound in predicates {
327        if let ast::WherePredicateKind::BoundPredicate(bound) = &bound.kind
328            && bound.bounded_ty.kind.is_simple_path().is_some_and(|name| name == pointee)
329        {
330            if contains_maybe_sized_bound(&bound.bounds) {
331                return true;
332            }
333        }
334    }
335    false
336}
337
338fn is_maybe_sized_bound(bound: &GenericBound) -> bool {
339    if let GenericBound::Trait(trait_ref) = bound
340        && let TraitBoundModifiers { polarity: ast::BoundPolarity::Maybe(_), .. } =
341            trait_ref.modifiers
342        && is_sized_marker(&trait_ref.trait_ref.path)
343    {
344        true
345    } else {
346        false
347    }
348}
349
350fn contains_maybe_sized_bound(bounds: &[GenericBound]) -> bool {
351    bounds.iter().any(is_maybe_sized_bound)
352}
353
354fn is_sized_marker(path: &ast::Path) -> bool {
355    const CORE_UNSIZE: [Symbol; 3] = [sym::core, sym::marker, sym::Sized];
356    const STD_UNSIZE: [Symbol; 3] = [sym::std, sym::marker, sym::Sized];
357    let segments = || path.segments.iter().map(|segment| segment.ident.name);
358    if path.is_global() {
359        segments().skip(1).eq(CORE_UNSIZE) || segments().skip(1).eq(STD_UNSIZE)
360    } else {
361        segments().eq(CORE_UNSIZE) || segments().eq(STD_UNSIZE) || *path == sym::Sized
362    }
363}
364
365struct TypeSubstitution<'a> {
366    from_name: Symbol,
367    to_ty: &'a ast::Ty,
368    rewritten: bool,
369}
370
371impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
372    fn visit_ty(&mut self, ty: &mut ast::Ty) {
373        if let Some(name) = ty.kind.is_simple_path()
374            && name == self.from_name
375        {
376            *ty = self.to_ty.clone();
377            self.rewritten = true;
378        } else {
379            ast::mut_visit::walk_ty(self, ty);
380        }
381    }
382
383    fn visit_where_predicate_kind(&mut self, kind: &mut ast::WherePredicateKind) {
384        match kind {
385            rustc_ast::WherePredicateKind::BoundPredicate(bound) => {
386                bound
387                    .bound_generic_params
388                    .flat_map_in_place(|param| self.flat_map_generic_param(param));
389                self.visit_ty(&mut bound.bounded_ty);
390                for bound in &mut bound.bounds {
391                    self.visit_param_bound(bound, BoundKind::Bound)
392                }
393            }
394            rustc_ast::WherePredicateKind::RegionPredicate(_) => {}
395        }
396    }
397}
398
399struct DetectNonGenericPointeeAttr<'a, 'b> {
400    cx: &'a ExtCtxt<'b>,
401}
402
403impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonGenericPointeeAttr<'a, 'b> {
404    fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
405        if attr.has_name(sym::pointee) {
406            self.cx.dcx().emit_err(diagnostics::NonGenericPointee { span: attr.span });
407        }
408    }
409
410    fn visit_generic_param(&mut self, param: &'a rustc_ast::GenericParam) -> Self::Result {
411        let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
412
413        match &param.kind {
414            GenericParamKind::Type { default } => {
415                // The `default` may end up containing a block expression.
416                // The problem is block expressions  may define structs with generics.
417                // A user may attach a #[pointee] attribute to one of these generics
418                // We want to catch that. The simple solution is to just
419                // always raise a `NonGenericPointee` error when this happens.
420                //
421                // This solution does reject valid rust programs but,
422                // such a code would have to, in order:
423                // - Define a smart pointer struct.
424                // - Somewhere in this struct definition use a type with a const generic argument.
425                // - Calculate this const generic in a expression block.
426                // - Define a new smart pointer type in this block.
427                // - Have this smart pointer type have more than 1 generic type.
428                // In this case, the inner smart pointer derive would be complaining that it
429                // needs a pointer attribute. Meanwhile, the outer macro would be complaining
430                // that we attached a #[pointee] to a generic type argument while helpfully
431                // informing the user that #[pointee] can only be attached to generic pointer arguments
432                if let Some(x) = default {
    match ::rustc_ast_ir::visit::VisitorResult::branch(error_on_pointee.visit_ty(x))
        {
        core::ops::ControlFlow::Continue(()) =>
            (),
            #[allow(unreachable_code)]
            core::ops::ControlFlow::Break(r) => {
            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
        }
    };
};rustc_ast::visit::visit_opt!(error_on_pointee, visit_ty, default);
433            }
434
435            GenericParamKind::Const { .. } | GenericParamKind::Lifetime => {
436                rustc_ast::visit::walk_generic_param(&mut error_on_pointee, param);
437            }
438        }
439    }
440
441    fn visit_ty(&mut self, t: &'a rustc_ast::Ty) -> Self::Result {
442        let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
443        error_on_pointee.visit_ty(t)
444    }
445}
446
447struct AlwaysErrorOnGenericParam<'a, 'b> {
448    cx: &'a ExtCtxt<'b>,
449}
450
451impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> {
452    fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
453        if attr.has_name(sym::pointee) {
454            self.cx.dcx().emit_err(diagnostics::NonGenericPointee { span: attr.span });
455        }
456    }
457}
458
459#[derive(const _: () =
    {
        impl<'_sess> rustc_errors::Diagnostic<'_sess> for RequireTransparent {
            #[track_caller]
            fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
                level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
                match self {
                    RequireTransparent { span: __binding_0 } => {
                        let mut diag =
                            rustc_errors::Diag::new(dcx, level,
                                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`")));
                        diag.code(E0802);
                        ;
                        diag.span(__binding_0);
                        diag
                    }
                }
            }
        }
    };Diagnostic)]
460#[diag("`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`", code = E0802)]
461struct RequireTransparent {
462    #[primary_span]
463    span: Span,
464}
465
466#[derive(const _: () =
    {
        impl<'_sess> rustc_errors::Diagnostic<'_sess> for RequireOneField {
            #[track_caller]
            fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
                level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
                match self {
                    RequireOneField { span: __binding_0 } => {
                        let mut diag =
                            rustc_errors::Diag::new(dcx, level,
                                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`CoercePointee` can only be derived on `struct`s with at least one field")));
                        diag.code(E0802);
                        ;
                        diag.span(__binding_0);
                        diag
                    }
                }
            }
        }
    };Diagnostic)]
467#[diag("`CoercePointee` can only be derived on `struct`s with at least one field", code = E0802)]
468struct RequireOneField {
469    #[primary_span]
470    span: Span,
471}
472
473#[derive(const _: () =
    {
        impl<'_sess> rustc_errors::Diagnostic<'_sess> for RequireOneGeneric {
            #[track_caller]
            fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
                level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
                match self {
                    RequireOneGeneric { span: __binding_0 } => {
                        let mut diag =
                            rustc_errors::Diag::new(dcx, level,
                                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`CoercePointee` can only be derived on `struct`s that are generic over at least one type")));
                        diag.code(E0802);
                        ;
                        diag.span(__binding_0);
                        diag
                    }
                }
            }
        }
    };Diagnostic)]
474#[diag("`CoercePointee` can only be derived on `struct`s that are generic over at least one type", code = E0802)]
475struct RequireOneGeneric {
476    #[primary_span]
477    span: Span,
478}
479
480#[derive(const _: () =
    {
        impl<'_sess> rustc_errors::Diagnostic<'_sess> for RequireOnePointee {
            #[track_caller]
            fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
                level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
                match self {
                    RequireOnePointee { span: __binding_0 } => {
                        let mut diag =
                            rustc_errors::Diag::new(dcx, level,
                                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits")));
                        diag.code(E0802);
                        ;
                        diag.span(__binding_0);
                        diag
                    }
                }
            }
        }
    };Diagnostic)]
481#[diag("exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits", code = E0802)]
482struct RequireOnePointee {
483    #[primary_span]
484    span: Span,
485}
486
487#[derive(const _: () =
    {
        impl<'_sess> rustc_errors::Diagnostic<'_sess> for TooManyPointees {
            #[track_caller]
            fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
                level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
                match self {
                    TooManyPointees { one: __binding_0, another: __binding_1 }
                        => {
                        let mut diag =
                            rustc_errors::Diag::new(dcx, level,
                                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits")));
                        diag.code(E0802);
                        ;
                        diag.span(__binding_0);
                        diag.span_label(__binding_1,
                            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("here another type parameter is marked as `#[pointee]`")));
                        diag
                    }
                }
            }
        }
    };Diagnostic)]
488#[diag("only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits", code = E0802)]
489struct TooManyPointees {
490    #[primary_span]
491    one: Span,
492    #[label("here another type parameter is marked as `#[pointee]`")]
493    another: Span,
494}
495
496#[derive(const _: () =
    {
        impl<'_sess> rustc_errors::Diagnostic<'_sess> for RequiresMaybeSized {
            #[track_caller]
            fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
                level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
                match self {
                    RequiresMaybeSized { span: __binding_0, name: __binding_1 }
                        => {
                        let mut diag =
                            rustc_errors::Diag::new(dcx, level,
                                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`derive(CoercePointee)` requires `{$name}` to be marked `?Sized`")));
                        diag.code(E0802);
                        ;
                        diag.arg("name", __binding_1);
                        diag.span(__binding_0);
                        diag
                    }
                }
            }
        }
    };Diagnostic)]
497#[diag("`derive(CoercePointee)` requires `{$name}` to be marked `?Sized`", code = E0802)]
498struct RequiresMaybeSized {
499    #[primary_span]
500    span: Span,
501    name: Ident,
502}