rustc_builtin_macros/deriving/
reborrow.rs1use rustc_ast::{self as ast, AttrArgs, Generics, ItemKind, token};
2use rustc_errors::E0802;
3use rustc_expand::base::ExtCtxt;
4use rustc_macros::Diagnostic;
5use rustc_span::{Ident, Span, Symbol, sym};
6use thin_vec::ThinVec;
7
8use crate::deriving::generic::*;
9
10pub(crate) fn expand_deriving_reborrow(
11 cx: &ExtCtxt<'_>,
12 span: Span,
13 item: &ast::Item,
14 push: &mut dyn FnMut(Box<ast::Item>),
15 _is_const: bool,
16) {
17 let Some((ident, generics)) = struct_def(cx, span, item, sym::Reborrow) else {
18 return;
19 };
20
21 push_marker_impl(cx, span, ident, generics, sym::Reborrow, Vec::new(), push);
22}
23
24pub(crate) fn expand_deriving_coerce_shared(
25 cx: &ExtCtxt<'_>,
26 span: Span,
27 item: &ast::Item,
28 push: &mut dyn FnMut(Box<ast::Item>),
29 _is_const: bool,
30) {
31 let Some((ident, generics)) = struct_def(cx, span, item, sym::CoerceShared) else {
32 return;
33 };
34 let Some(target) = coerce_shared_target(cx, span, item) else {
35 return;
36 };
37
38 push_marker_impl(
39 cx,
40 span,
41 ident,
42 generics,
43 sym::CoerceShared,
44 ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[ast::GenericArg::Type(target)]))vec![ast::GenericArg::Type(target)],
45 push,
46 );
47}
48
49fn struct_def<'a>(
50 cx: &ExtCtxt<'_>,
51 span: Span,
52 item: &'a ast::Item,
53 trait_name: Symbol,
54) -> Option<(Ident, &'a Generics)> {
55 match &item.kind {
56 ItemKind::Struct(ident, generics, _) => Some((*ident, generics)),
57 ItemKind::Enum(..) => {
58 cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "enum" });
59 None
60 }
61 ItemKind::Union(..) => {
62 cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "union" });
63 None
64 }
65 _ => {
66 cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "item" });
67 None
68 }
69 }
70}
71
72fn coerce_shared_target(cx: &ExtCtxt<'_>, span: Span, item: &ast::Item) -> Option<Box<ast::Ty>> {
73 let mut attrs = item.attrs.iter().filter(|attr| attr.has_name(sym::coerce_shared));
74 let Some(attr) = attrs.next() else {
75 cx.dcx().emit_err(MissingTarget { span });
76 return None;
77 };
78 if let Some(duplicate) = attrs.next() {
79 cx.dcx().emit_err(DuplicateTarget { first: attr.span, duplicate: duplicate.span });
80 return None;
81 }
82
83 let AttrArgs::Delimited(args) = &attr.get_normal_item().args else {
84 cx.dcx().emit_err(MalformedTarget { span: attr.span });
85 return None;
86 };
87 if args.delim != token::Delimiter::Parenthesis || args.tokens.is_empty() {
88 cx.dcx().emit_err(MalformedTarget { span: attr.span });
89 return None;
90 }
91
92 let mut parser = cx.new_parser_from_tts(args.tokens.clone());
93 let target = match parser.parse_ty() {
94 Ok(target) => target,
95 Err(err) => {
96 err.cancel();
97 cx.dcx().emit_err(MalformedTarget { span: attr.span });
98 return None;
99 }
100 };
101 if parser.token != token::Eof {
102 cx.dcx().emit_err(MalformedTarget { span: attr.span });
103 return None;
104 }
105
106 Some(target)
107}
108
109fn push_marker_impl(
110 cx: &ExtCtxt<'_>,
111 span: Span,
112 ident: Ident,
113 generics: &Generics,
114 trait_name: Symbol,
115 trait_args: Vec<ast::GenericArg>,
116 push: &mut dyn FnMut(Box<ast::Item>),
117) {
118 let trait_path = cx.std_path_all(span, &[sym::marker, trait_name], trait_args);
119 let trait_ref = cx.trait_ref(trait_path);
120
121 let self_params: Vec<_> =
122 generics.params.iter().map(|p| generic_param_to_arg(cx, p, p.span())).collect();
123 let self_ty = cx.ty_path(cx.path_all(span, &[ident], self_params));
124
125 push(cx.item_trait_impl(
126 span,
127 {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(cx.generated_attr(span,
ast::GeneratedAttr::AutomaticallyDerived));
vec
}thin_vec::thin_vec![cx.generated_attr(span, ast::GeneratedAttr::AutomaticallyDerived)],
128 generics_without_defaults(generics),
129 ast::Safety::Default,
130 false,
131 trait_ref,
132 self_ty,
133 ThinVec::new(),
134 ));
135}
136
137#[derive(const _: () =
{
impl<'_sess> rustc_errors::Diagnostic<'_sess> for UnsupportedItem {
#[track_caller]
fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
match self {
UnsupportedItem {
span: __binding_0,
trait_name: __binding_1,
kind: __binding_2 } => {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`derive({$trait_name})` is only supported for structs, not {$kind}s")));
diag.code(E0802);
;
diag.arg("trait_name", __binding_1);
diag.arg("kind", __binding_2);
diag.span(__binding_0);
diag
}
}
}
}
};Diagnostic)]
138#[diag("`derive({$trait_name})` is only supported for structs, not {$kind}s", code = E0802)]
139struct UnsupportedItem {
140 #[primary_span]
141 span: Span,
142 trait_name: Symbol,
143 kind: &'static str,
144}
145
146#[derive(const _: () =
{
impl<'_sess> rustc_errors::Diagnostic<'_sess> for MissingTarget {
#[track_caller]
fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
match self {
MissingTarget { span: __binding_0 } => {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("`derive(CoerceShared)` requires exactly one `#[coerce_shared(Target)]` attribute")));
diag.code(E0802);
;
diag.span(__binding_0);
diag
}
}
}
}
};Diagnostic)]
147#[diag("`derive(CoerceShared)` requires exactly one `#[coerce_shared(Target)]` attribute", code = E0802)]
148struct MissingTarget {
149 #[primary_span]
150 span: Span,
151}
152
153#[derive(const _: () =
{
impl<'_sess> rustc_errors::Diagnostic<'_sess> for DuplicateTarget {
#[track_caller]
fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
match self {
DuplicateTarget { duplicate: __binding_0, first: __binding_1
} => {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("duplicate `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)`")));
diag.code(E0802);
;
diag.span(__binding_0);
diag.span_note(__binding_1,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("first `#[coerce_shared(Target)]` attribute is here")));
diag
}
}
}
}
};Diagnostic)]
154#[diag("duplicate `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)`", code = E0802)]
155struct DuplicateTarget {
156 #[primary_span]
157 duplicate: Span,
158 #[note("first `#[coerce_shared(Target)]` attribute is here")]
159 first: Span,
160}
161
162#[derive(const _: () =
{
impl<'_sess> rustc_errors::Diagnostic<'_sess> for MalformedTarget {
#[track_caller]
fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
match self {
MalformedTarget { span: __binding_0 } => {
let mut diag =
rustc_errors::Diag::new(dcx, level,
rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("malformed `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)`")));
diag.code(E0802);
diag.note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("expected a single target type, for example `#[coerce_shared(Target<'a, T>)]`")));
;
diag.span(__binding_0);
diag
}
}
}
}
};Diagnostic)]
163#[diag("malformed `#[coerce_shared(Target)]` attribute for `derive(CoerceShared)`", code = E0802)]
164#[note("expected a single target type, for example `#[coerce_shared(Target<'a, T>)]`")]
165struct MalformedTarget {
166 #[primary_span]
167 span: Span,
168}