]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_builtin_macros/src/deriving/debug.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / compiler / rustc_builtin_macros / src / deriving / debug.rs
1 use crate::deriving::generic::ty::*;
2 use crate::deriving::generic::*;
3 use crate::deriving::path_std;
4
5 use rustc_ast::{self as ast, MetaItem};
6 use rustc_expand::base::{Annotatable, ExtCtxt};
7 use rustc_span::symbol::{sym, Ident, Symbol};
8 use rustc_span::Span;
9
10 pub fn expand_deriving_debug(
11 cx: &mut ExtCtxt<'_>,
12 span: Span,
13 mitem: &MetaItem,
14 item: &Annotatable,
15 push: &mut dyn FnMut(Annotatable),
16 is_const: bool,
17 ) {
18 // &mut ::std::fmt::Formatter
19 let fmtr = Ref(Box::new(Path(path_std!(fmt::Formatter))), ast::Mutability::Mut);
20
21 let trait_def = TraitDef {
22 span,
23 path: path_std!(fmt::Debug),
24 skip_path_as_bound: false,
25 additional_bounds: Vec::new(),
26 supports_unions: false,
27 methods: vec![MethodDef {
28 name: sym::fmt,
29 generics: Bounds::empty(),
30 explicit_self: true,
31 nonself_args: vec![(fmtr, sym::f)],
32 ret_ty: Path(path_std!(fmt::Result)),
33 attributes: ast::AttrVec::new(),
34 unify_fieldless_variants: false,
35 combine_substructure: combine_substructure(Box::new(|a, b, c| {
36 show_substructure(a, b, c)
37 })),
38 }],
39 associated_types: Vec::new(),
40 is_const,
41 };
42 trait_def.expand(cx, mitem, item, push)
43 }
44
45 fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
46 let (ident, vdata, fields) = match substr.fields {
47 Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
48 EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
49 EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
50 cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
51 }
52 };
53
54 // We want to make sure we have the ctxt set so that we can use unstable methods
55 let span = cx.with_def_site_ctxt(span);
56 let name = cx.expr_str(span, ident.name);
57 let fmt = substr.nonselflike_args[0].clone();
58
59 // Struct and tuples are similar enough that we use the same code for both,
60 // with some extra pieces for structs due to the field names.
61 let (is_struct, args_per_field) = match vdata {
62 ast::VariantData::Unit(..) => {
63 // Special fast path for unit variants.
64 assert!(fields.is_empty());
65 (false, 0)
66 }
67 ast::VariantData::Tuple(..) => (false, 1),
68 ast::VariantData::Struct(..) => (true, 2),
69 };
70
71 // The number of fields that can be handled without an array.
72 const CUTOFF: usize = 5;
73
74 if fields.is_empty() {
75 // Special case for no fields.
76 let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
77 let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
78 BlockOrExpr::new_expr(expr)
79 } else if fields.len() <= CUTOFF {
80 // Few enough fields that we can use a specific-length method.
81 let debug = if is_struct {
82 format!("debug_struct_field{}_finish", fields.len())
83 } else {
84 format!("debug_tuple_field{}_finish", fields.len())
85 };
86 let fn_path_debug = cx.std_path(&[sym::fmt, sym::Formatter, Symbol::intern(&debug)]);
87
88 let mut args = Vec::with_capacity(2 + fields.len() * args_per_field);
89 args.extend([fmt, name]);
90 for i in 0..fields.len() {
91 let field = &fields[i];
92 if is_struct {
93 let name = cx.expr_str(field.span, field.name.unwrap().name);
94 args.push(name);
95 }
96 // Use an extra indirection to make sure this works for unsized types.
97 let field = cx.expr_addr_of(field.span, field.self_expr.clone());
98 args.push(field);
99 }
100 let expr = cx.expr_call_global(span, fn_path_debug, args);
101 BlockOrExpr::new_expr(expr)
102 } else {
103 // Enough fields that we must use the any-length method.
104 let mut name_exprs = Vec::with_capacity(fields.len());
105 let mut value_exprs = Vec::with_capacity(fields.len());
106
107 for field in fields {
108 if is_struct {
109 name_exprs.push(cx.expr_str(field.span, field.name.unwrap().name));
110 }
111
112 // Use an extra indirection to make sure this works for unsized types.
113 let field = cx.expr_addr_of(field.span, field.self_expr.clone());
114 value_exprs.push(field);
115 }
116
117 // `let names: &'static _ = &["field1", "field2"];`
118 let names_let = if is_struct {
119 let lt_static = Some(cx.lifetime_static(span));
120 let ty_static_ref =
121 cx.ty_rptr(span, cx.ty_infer(span), lt_static, ast::Mutability::Not);
122 Some(cx.stmt_let_ty(
123 span,
124 false,
125 Ident::new(sym::names, span),
126 Some(ty_static_ref),
127 cx.expr_array_ref(span, name_exprs),
128 ))
129 } else {
130 None
131 };
132
133 // `let values: &[&dyn Debug] = &[&&self.field1, &&self.field2];`
134 let path_debug = cx.path_global(span, cx.std_path(&[sym::fmt, sym::Debug]));
135 let ty_dyn_debug = cx.ty(
136 span,
137 ast::TyKind::TraitObject(vec![cx.trait_bound(path_debug)], ast::TraitObjectSyntax::Dyn),
138 );
139 let ty_slice = cx.ty(
140 span,
141 ast::TyKind::Slice(cx.ty_rptr(span, ty_dyn_debug, None, ast::Mutability::Not)),
142 );
143 let values_let = cx.stmt_let_ty(
144 span,
145 false,
146 Ident::new(sym::values, span),
147 Some(cx.ty_rptr(span, ty_slice, None, ast::Mutability::Not)),
148 cx.expr_array_ref(span, value_exprs),
149 );
150
151 // `fmt::Formatter::debug_struct_fields_finish(fmt, name, names, values)` or
152 // `fmt::Formatter::debug_tuple_fields_finish(fmt, name, values)`
153 let sym_debug = if is_struct {
154 sym::debug_struct_fields_finish
155 } else {
156 sym::debug_tuple_fields_finish
157 };
158 let fn_path_debug_internal = cx.std_path(&[sym::fmt, sym::Formatter, sym_debug]);
159
160 let mut args = Vec::with_capacity(4);
161 args.push(fmt);
162 args.push(name);
163 if is_struct {
164 args.push(cx.expr_ident(span, Ident::new(sym::names, span)));
165 }
166 args.push(cx.expr_ident(span, Ident::new(sym::values, span)));
167 let expr = cx.expr_call_global(span, fn_path_debug_internal, args);
168
169 let mut stmts = Vec::with_capacity(3);
170 if is_struct {
171 stmts.push(names_let.unwrap());
172 }
173 stmts.push(values_let);
174 BlockOrExpr::new_mixed(stmts, Some(expr))
175 }
176 }