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