1 use crate::cfg_eval
::cfg_eval
;
5 use rustc_ast
::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}
;
6 use rustc_expand
::base
::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}
;
7 use rustc_feature
::AttributeTemplate
;
8 use rustc_parse
::validate_attr
;
9 use rustc_session
::Session
;
10 use rustc_span
::symbol
::{sym, Ident}
;
11 use rustc_span
::{ErrorGuaranteed, Span}
;
13 pub(crate) struct Expander(pub bool
);
15 impl MultiItemModifier
for Expander
{
18 ecx
: &mut ExtCtxt
<'_
>,
20 meta_item
: &ast
::MetaItem
,
23 ) -> ExpandResult
<Vec
<Annotatable
>, Annotatable
> {
25 if report_bad_target(sess
, &item
, span
).is_err() {
26 // We don't want to pass inappropriate targets to derive macros to avoid
27 // follow up errors, all other errors below are recoverable.
28 return ExpandResult
::Ready(vec
![item
]);
31 let (sess
, features
) = (ecx
.sess
, ecx
.ecfg
.features
);
33 ecx
.resolver
.resolve_derives(ecx
.current_expansion
.id
, ecx
.force_mode
, &|| {
35 AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() }
;
36 validate_attr
::check_builtin_meta_item(
39 ast
::AttrStyle
::Outer
,
44 let mut resolutions
= match &meta_item
.kind
{
45 MetaItemKind
::List(list
) => {
47 .filter_map(|nested_meta
| match nested_meta
{
48 NestedMetaItem
::MetaItem(meta
) => Some(meta
),
49 NestedMetaItem
::Lit(lit
) => {
50 // Reject `#[derive("Debug")]`.
51 report_unexpected_meta_item_lit(sess
, &lit
);
56 // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the
58 report_path_args(sess
, &meta
);
61 .map(|path
| (path
, dummy_annotatable(), None
, self.0))
67 // Do not configure or clone items unless necessary.
68 match &mut resolutions
[..] {
70 [(_
, first_item
, ..), others @
..] => {
71 *first_item
= cfg_eval(
75 ecx
.current_expansion
.lint_node_id
,
77 for (_
, item
, _
, _
) in others
{
78 *item
= first_item
.clone();
87 Ok(()) => ExpandResult
::Ready(vec
![item
]),
88 Err(Indeterminate
) => ExpandResult
::Retry(item
),
93 // The cheapest `Annotatable` to construct.
94 fn dummy_annotatable() -> Annotatable
{
95 Annotatable
::GenericParam(ast
::GenericParam
{
96 id
: ast
::DUMMY_NODE_ID
,
97 ident
: Ident
::empty(),
98 attrs
: Default
::default(),
99 bounds
: Default
::default(),
100 is_placeholder
: false,
101 kind
: GenericParamKind
::Lifetime
,
106 fn report_bad_target(
110 ) -> Result
<(), ErrorGuaranteed
> {
111 let item_kind
= match item
{
112 Annotatable
::Item(item
) => Some(&item
.kind
),
113 Annotatable
::Stmt(stmt
) => match &stmt
.kind
{
114 StmtKind
::Item(item
) => Some(&item
.kind
),
121 !matches
!(item_kind
, Some(ItemKind
::Struct(..) | ItemKind
::Enum(..) | ItemKind
::Union(..)));
123 return Err(sess
.emit_err(errors
::BadDeriveTarget { span, item: item.span() }
));
128 fn report_unexpected_meta_item_lit(sess
: &Session
, lit
: &ast
::MetaItemLit
) {
129 let help
= match lit
.kind
{
130 ast
::LitKind
::Str(_
, ast
::StrStyle
::Cooked
)
131 if rustc_lexer
::is_ident(lit
.symbol
.as_str()) =>
133 errors
::BadDeriveLitHelp
::StrLit { sym: lit.symbol }
135 _
=> errors
::BadDeriveLitHelp
::Other
,
137 sess
.emit_err(errors
::BadDeriveLit { span: lit.span, help }
);
140 fn report_path_args(sess
: &Session
, meta
: &ast
::MetaItem
) {
141 let span
= meta
.span
.with_lo(meta
.path
.span
.hi());
144 MetaItemKind
::Word
=> {}
145 MetaItemKind
::List(..) => {
146 sess
.emit_err(errors
::DerivePathArgsList { span }
);
148 MetaItemKind
::NameValue(..) => {
149 sess
.emit_err(errors
::DerivePathArgsValue { span }
);