1 use crate::deriving
::generic
::ty
::*;
2 use crate::deriving
::generic
::*;
3 use crate::deriving
::path_std
;
6 use rustc_ast
::{self as ast, Expr, MetaItem}
;
7 use rustc_expand
::base
::{Annotatable, ExtCtxt}
;
8 use rustc_span
::symbol
::{sym, Ident}
;
9 use rustc_span
::{Span, DUMMY_SP}
;
11 fn make_mut_borrow(cx
: &mut ExtCtxt
<'_
>, sp
: Span
, expr
: P
<Expr
>) -> P
<Expr
> {
12 cx
.expr(sp
, ast
::ExprKind
::AddrOf(ast
::BorrowKind
::Ref
, ast
::Mutability
::Mut
, expr
))
15 pub fn expand_deriving_debug(
20 push
: &mut dyn FnMut(Annotatable
),
22 // &mut ::std::fmt::Formatter
24 Ptr(Box
::new(Literal(path_std
!(fmt
::Formatter
))), Borrowed(None
, ast
::Mutability
::Mut
));
26 let trait_def
= TraitDef
{
28 attributes
: Vec
::new(),
29 path
: path_std
!(fmt
::Debug
),
30 additional_bounds
: Vec
::new(),
31 generics
: Bounds
::empty(),
33 supports_unions
: false,
34 methods
: vec
![MethodDef
{
36 generics
: Bounds
::empty(),
37 explicit_self
: borrowed_explicit_self(),
38 args
: vec
![(fmtr
, sym
::f
)],
39 ret_ty
: Literal(path_std
!(fmt
::Result
)),
40 attributes
: Vec
::new(),
42 unify_fieldless_variants
: false,
43 combine_substructure
: combine_substructure(Box
::new(|a
, b
, c
| {
44 show_substructure(a
, b
, c
)
47 associated_types
: Vec
::new(),
49 trait_def
.expand(cx
, mitem
, item
, push
)
52 /// We use the debug builders to do the heavy lifting here
53 fn show_substructure(cx
: &mut ExtCtxt
<'_
>, span
: Span
, substr
: &Substructure
<'_
>) -> P
<Expr
> {
54 // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
55 // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
56 // based on the "shape".
57 let (ident
, vdata
, fields
) = match substr
.fields
{
58 Struct(vdata
, fields
) => (substr
.type_ident
, *vdata
, fields
),
59 EnumMatching(_
, _
, v
, fields
) => (v
.ident
, &v
.data
, fields
),
60 EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
61 cx
.span_bug(span
, "nonsensical .fields in `#[derive(Debug)]`")
65 // We want to make sure we have the ctxt set so that we can use unstable methods
66 let span
= cx
.with_def_site_ctxt(span
);
67 let name
= cx
.expr_lit(span
, ast
::LitKind
::Str(ident
.name
, ast
::StrStyle
::Cooked
));
68 let builder
= Ident
::new(sym
::debug_trait_builder
, span
);
69 let builder_expr
= cx
.expr_ident(span
, builder
);
71 let fmt
= substr
.nonself_args
[0].clone();
73 let mut stmts
= Vec
::with_capacity(fields
.len() + 2);
76 ast
::VariantData
::Tuple(..) | ast
::VariantData
::Unit(..) => {
77 // tuple struct/"normal" variant
78 let fn_path_debug_tuple
= cx
.std_path(&[sym
::fmt
, sym
::Formatter
, sym
::debug_tuple
]);
79 let expr
= cx
.expr_call_global(span
, fn_path_debug_tuple
, vec
![fmt
, name
]);
80 stmts
.push(cx
.stmt_let(span
, true, builder
, expr
));
83 // Use double indirection to make sure this works for unsized types
84 let field
= cx
.expr_addr_of(field
.span
, field
.self_
.clone());
85 let field
= cx
.expr_addr_of(field
.span
, field
);
87 let fn_path_field
= cx
.std_path(&[sym
::fmt
, sym
::DebugTuple
, sym
::field
]);
88 let builder_recv
= make_mut_borrow(cx
, span
, builder_expr
.clone());
89 let expr
= cx
.expr_call_global(span
, fn_path_field
, vec
![builder_recv
, field
]);
91 // Use `let _ = expr;` to avoid triggering the
92 // unused_results lint.
93 stmts
.push(stmt_let_underscore(cx
, span
, expr
));
96 fn_path_finish
= cx
.std_path(&[sym
::fmt
, sym
::DebugTuple
, sym
::finish
]);
98 ast
::VariantData
::Struct(..) => {
99 // normal struct/struct variant
100 let fn_path_debug_struct
= cx
.std_path(&[sym
::fmt
, sym
::Formatter
, sym
::debug_struct
]);
101 let expr
= cx
.expr_call_global(span
, fn_path_debug_struct
, vec
![fmt
, name
]);
102 stmts
.push(cx
.stmt_let(DUMMY_SP
, true, builder
, expr
));
104 for field
in fields
{
105 let name
= cx
.expr_lit(
107 ast
::LitKind
::Str(field
.name
.unwrap().name
, ast
::StrStyle
::Cooked
),
110 // Use double indirection to make sure this works for unsized types
111 let fn_path_field
= cx
.std_path(&[sym
::fmt
, sym
::DebugStruct
, sym
::field
]);
112 let field
= cx
.expr_addr_of(field
.span
, field
.self_
.clone());
113 let field
= cx
.expr_addr_of(field
.span
, field
);
114 let builder_recv
= make_mut_borrow(cx
, span
, builder_expr
.clone());
116 cx
.expr_call_global(span
, fn_path_field
, vec
![builder_recv
, name
, field
]);
117 stmts
.push(stmt_let_underscore(cx
, span
, expr
));
119 fn_path_finish
= cx
.std_path(&[sym
::fmt
, sym
::DebugStruct
, sym
::finish
]);
123 let builder_recv
= make_mut_borrow(cx
, span
, builder_expr
);
124 let expr
= cx
.expr_call_global(span
, fn_path_finish
, vec
![builder_recv
]);
126 stmts
.push(cx
.stmt_expr(expr
));
127 let block
= cx
.block(span
, stmts
);
131 fn stmt_let_underscore(cx
: &mut ExtCtxt
<'_
>, sp
: Span
, expr
: P
<ast
::Expr
>) -> ast
::Stmt
{
132 let local
= P(ast
::Local
{
133 pat
: cx
.pat_wild(sp
),
136 id
: ast
::DUMMY_NODE_ID
,
138 attrs
: ast
::AttrVec
::new(),
141 ast
::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }