1 use crate::deriving
::generic
::ty
::*;
2 use crate::deriving
::generic
::*;
3 use crate::deriving
::path_std
;
5 use rustc_expand
::base
::{Annotatable, ExtCtxt}
;
6 use rustc_span
::symbol
::sym
;
7 use rustc_span
::{Span, DUMMY_SP}
;
8 use syntax
::ast
::{self, Ident}
;
9 use syntax
::ast
::{Expr, MetaItem}
;
12 pub fn expand_deriving_debug(
17 push
: &mut dyn FnMut(Annotatable
),
19 // &mut ::std::fmt::Formatter
21 Ptr(Box
::new(Literal(path_std
!(cx
, fmt
::Formatter
))), Borrowed(None
, ast
::Mutability
::Mut
));
23 let trait_def
= TraitDef
{
25 attributes
: Vec
::new(),
26 path
: path_std
!(cx
, fmt
::Debug
),
27 additional_bounds
: Vec
::new(),
28 generics
: LifetimeBounds
::empty(),
30 supports_unions
: false,
31 methods
: vec
![MethodDef
{
33 generics
: LifetimeBounds
::empty(),
34 explicit_self
: borrowed_explicit_self(),
35 args
: vec
![(fmtr
, "f")],
36 ret_ty
: Literal(path_std
!(cx
, fmt
::Result
)),
37 attributes
: Vec
::new(),
39 unify_fieldless_variants
: false,
40 combine_substructure
: combine_substructure(Box
::new(|a
, b
, c
| {
41 show_substructure(a
, b
, c
)
44 associated_types
: Vec
::new(),
46 trait_def
.expand(cx
, mitem
, item
, push
)
49 /// We use the debug builders to do the heavy lifting here
50 fn show_substructure(cx
: &mut ExtCtxt
<'_
>, span
: Span
, substr
: &Substructure
<'_
>) -> P
<Expr
> {
51 // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
52 // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
53 // based on the "shape".
54 let (ident
, vdata
, fields
) = match substr
.fields
{
55 Struct(vdata
, fields
) => (substr
.type_ident
, *vdata
, fields
),
56 EnumMatching(_
, _
, v
, fields
) => (v
.ident
, &v
.data
, fields
),
57 EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
58 cx
.span_bug(span
, "nonsensical .fields in `#[derive(Debug)]`")
62 // We want to make sure we have the ctxt set so that we can use unstable methods
63 let span
= cx
.with_def_site_ctxt(span
);
64 let name
= cx
.expr_lit(span
, ast
::LitKind
::Str(ident
.name
, ast
::StrStyle
::Cooked
));
65 let builder
= cx
.ident_of("debug_trait_builder", span
);
66 let builder_expr
= cx
.expr_ident(span
, builder
.clone());
68 let fmt
= substr
.nonself_args
[0].clone();
70 let mut stmts
= vec
![];
72 ast
::VariantData
::Tuple(..) | ast
::VariantData
::Unit(..) => {
73 // tuple struct/"normal" variant
74 let expr
= cx
.expr_method_call(span
, fmt
, cx
.ident_of("debug_tuple", span
), vec
![name
]);
75 stmts
.push(cx
.stmt_let(span
, true, builder
, expr
));
78 // Use double indirection to make sure this works for unsized types
79 let field
= cx
.expr_addr_of(field
.span
, field
.self_
.clone());
80 let field
= cx
.expr_addr_of(field
.span
, field
);
82 let expr
= cx
.expr_method_call(
85 Ident
::new(sym
::field
, span
),
89 // Use `let _ = expr;` to avoid triggering the
90 // unused_results lint.
91 stmts
.push(stmt_let_undescore(cx
, span
, expr
));
94 ast
::VariantData
::Struct(..) => {
95 // normal struct/struct variant
97 cx
.expr_method_call(span
, fmt
, cx
.ident_of("debug_struct", span
), vec
![name
]);
98 stmts
.push(cx
.stmt_let(DUMMY_SP
, true, builder
, expr
));
100 for field
in fields
{
101 let name
= cx
.expr_lit(
103 ast
::LitKind
::Str(field
.name
.unwrap().name
, ast
::StrStyle
::Cooked
),
106 // Use double indirection to make sure this works for unsized types
107 let field
= cx
.expr_addr_of(field
.span
, field
.self_
.clone());
108 let field
= cx
.expr_addr_of(field
.span
, field
);
109 let expr
= cx
.expr_method_call(
111 builder_expr
.clone(),
112 Ident
::new(sym
::field
, span
),
115 stmts
.push(stmt_let_undescore(cx
, span
, expr
));
120 let expr
= cx
.expr_method_call(span
, builder_expr
, cx
.ident_of("finish", span
), vec
![]);
122 stmts
.push(cx
.stmt_expr(expr
));
123 let block
= cx
.block(span
, stmts
);
127 fn stmt_let_undescore(cx
: &mut ExtCtxt
<'_
>, sp
: Span
, expr
: P
<ast
::Expr
>) -> ast
::Stmt
{
128 let local
= P(ast
::Local
{
129 pat
: cx
.pat_wild(sp
),
132 id
: ast
::DUMMY_NODE_ID
,
134 attrs
: ast
::AttrVec
::new(),
136 ast
::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }