Skip to content

Commit 788dded

Browse files
committedJun 26, 2022
Auto merge of #98190 - nnethercote:optimize-derive-Debug-code, r=scottmcm
Improve `derive(Debug)` r? `@ghost`
2 parents 7125846 + 20f0cda commit 788dded

File tree

10 files changed

+413
-233
lines changed

10 files changed

+413
-233
lines changed
 

‎compiler/rustc_builtin_macros/src/deriving/debug.rs

+117-88
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,10 @@ use crate::deriving::generic::*;
33
use crate::deriving::path_std;
44

55
use rustc_ast::ptr::P;
6-
use rustc_ast::{self as ast, Expr, LocalKind, MetaItem};
6+
use rustc_ast::{self as ast, Expr, MetaItem};
77
use rustc_expand::base::{Annotatable, ExtCtxt};
8-
use rustc_span::symbol::{sym, Ident};
9-
use rustc_span::{Span, DUMMY_SP};
10-
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))
13-
}
8+
use rustc_span::symbol::{sym, Ident, Symbol};
9+
use rustc_span::Span;
1410

1511
pub fn expand_deriving_debug(
1612
cx: &mut ExtCtxt<'_>,
@@ -49,11 +45,7 @@ pub fn expand_deriving_debug(
4945
trait_def.expand(cx, mitem, item, push)
5046
}
5147

52-
/// We use the debug builders to do the heavy lifting here
5348
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".
5749
let (ident, vdata, fields) = match substr.fields {
5850
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
5951
EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
@@ -67,93 +59,130 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
6759
let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
6860
let fmt = substr.nonself_args[0].clone();
6961

70-
// Special fast path for unit variants. In the common case of an enum that is entirely unit
71-
// variants (i.e. a C-like enum), this fast path allows LLVM to eliminate the entire switch in
72-
// favor of a lookup table.
73-
if let ast::VariantData::Unit(..) = vdata {
74-
let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
75-
let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
76-
let stmts = vec![cx.stmt_expr(expr)];
77-
let block = cx.block(span, stmts);
78-
return cx.expr_block(block);
79-
}
80-
81-
let builder = Ident::new(sym::debug_trait_builder, span);
82-
let builder_expr = cx.expr_ident(span, builder);
83-
84-
let mut stmts = Vec::with_capacity(fields.len() + 2);
85-
let fn_path_finish;
86-
match vdata {
62+
// Struct and tuples are similar enough that we use the same code for both,
63+
// with some extra pieces for structs due to the field names.
64+
let (is_struct, args_per_field) = match vdata {
8765
ast::VariantData::Unit(..) => {
88-
cx.span_bug(span, "unit variants should have been handled above");
66+
// Special fast path for unit variants.
67+
//let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
68+
//return cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
69+
assert!(fields.is_empty());
70+
(false, 0)
8971
}
90-
ast::VariantData::Tuple(..) => {
91-
// tuple struct/"normal" variant
92-
let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]);
93-
let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]);
94-
let expr = make_mut_borrow(cx, span, expr);
95-
stmts.push(cx.stmt_let(span, false, builder, expr));
96-
97-
for field in fields {
98-
// Use double indirection to make sure this works for unsized types
99-
let field = cx.expr_addr_of(field.span, field.self_.clone());
100-
let field = cx.expr_addr_of(field.span, field);
101-
102-
let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::field]);
103-
let expr =
104-
cx.expr_call_global(span, fn_path_field, vec![builder_expr.clone(), field]);
105-
106-
// Use `let _ = expr;` to avoid triggering the
107-
// unused_results lint.
108-
stmts.push(stmt_let_underscore(cx, span, expr));
109-
}
72+
ast::VariantData::Tuple(..) => (false, 1),
73+
ast::VariantData::Struct(..) => (true, 2),
74+
};
11075

111-
fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::finish]);
112-
}
113-
ast::VariantData::Struct(..) => {
114-
// normal struct/struct variant
115-
let fn_path_debug_struct = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_struct]);
116-
let expr = cx.expr_call_global(span, fn_path_debug_struct, vec![fmt, name]);
117-
let expr = make_mut_borrow(cx, span, expr);
118-
stmts.push(cx.stmt_let(DUMMY_SP, false, builder, expr));
119-
120-
for field in fields {
76+
// The number of fields that can be handled without an array.
77+
const CUTOFF: usize = 5;
78+
79+
if fields.is_empty() {
80+
// Special case for no fields.
81+
let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
82+
cx.expr_call_global(span, fn_path_write_str, vec![fmt, name])
83+
} else if fields.len() <= CUTOFF {
84+
// Few enough fields that we can use a specific-length method.
85+
let debug = if is_struct {
86+
format!("debug_struct_field{}_finish", fields.len())
87+
} else {
88+
format!("debug_tuple_field{}_finish", fields.len())
89+
};
90+
let fn_path_debug = cx.std_path(&[sym::fmt, sym::Formatter, Symbol::intern(&debug)]);
91+
92+
let mut args = Vec::with_capacity(2 + fields.len() * args_per_field);
93+
args.extend([fmt, name]);
94+
for i in 0..fields.len() {
95+
let field = &fields[i];
96+
if is_struct {
12197
let name = cx.expr_lit(
12298
field.span,
12399
ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
124100
);
125-
126-
// Use double indirection to make sure this works for unsized types
127-
let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::field]);
128-
let field = cx.expr_addr_of(field.span, field.self_.clone());
129-
let field = cx.expr_addr_of(field.span, field);
130-
let expr = cx.expr_call_global(
131-
span,
132-
fn_path_field,
133-
vec![builder_expr.clone(), name, field],
134-
);
135-
stmts.push(stmt_let_underscore(cx, span, expr));
101+
args.push(name);
136102
}
137-
fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::finish]);
103+
// Use double indirection to make sure this works for unsized types
104+
let field = cx.expr_addr_of(field.span, field.self_.clone());
105+
let field = cx.expr_addr_of(field.span, field);
106+
args.push(field);
138107
}
139-
}
108+
cx.expr_call_global(span, fn_path_debug, args)
109+
} else {
110+
// Enough fields that we must use the any-length method.
111+
let mut name_exprs = Vec::with_capacity(fields.len());
112+
let mut value_exprs = Vec::with_capacity(fields.len());
113+
114+
for field in fields {
115+
if is_struct {
116+
name_exprs.push(cx.expr_lit(
117+
field.span,
118+
ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
119+
));
120+
}
140121

141-
let expr = cx.expr_call_global(span, fn_path_finish, vec![builder_expr]);
122+
// Use double indirection to make sure this works for unsized types
123+
let value_ref = cx.expr_addr_of(field.span, field.self_.clone());
124+
value_exprs.push(cx.expr_addr_of(field.span, value_ref));
125+
}
142126

143-
stmts.push(cx.stmt_expr(expr));
144-
let block = cx.block(span, stmts);
145-
cx.expr_block(block)
146-
}
127+
// `let names: &'static _ = &["field1", "field2"];`
128+
let names_let = if is_struct {
129+
let lt_static = Some(cx.lifetime_static(span));
130+
let ty_static_ref =
131+
cx.ty_rptr(span, cx.ty_infer(span), lt_static, ast::Mutability::Not);
132+
Some(cx.stmt_let_ty(
133+
span,
134+
false,
135+
Ident::new(sym::names, span),
136+
Some(ty_static_ref),
137+
cx.expr_array_ref(span, name_exprs),
138+
))
139+
} else {
140+
None
141+
};
142+
143+
// `let values: &[&dyn Debug] = &[&&self.field1, &&self.field2];`
144+
let path_debug = cx.path_global(span, cx.std_path(&[sym::fmt, sym::Debug]));
145+
let ty_dyn_debug = cx.ty(
146+
span,
147+
ast::TyKind::TraitObject(vec![cx.trait_bound(path_debug)], ast::TraitObjectSyntax::Dyn),
148+
);
149+
let ty_slice = cx.ty(
150+
span,
151+
ast::TyKind::Slice(cx.ty_rptr(span, ty_dyn_debug, None, ast::Mutability::Not)),
152+
);
153+
let values_let = cx.stmt_let_ty(
154+
span,
155+
false,
156+
Ident::new(sym::values, span),
157+
Some(cx.ty_rptr(span, ty_slice, None, ast::Mutability::Not)),
158+
cx.expr_array_ref(span, value_exprs),
159+
);
160+
161+
// `fmt::Formatter::debug_struct_fields_finish(fmt, name, names, values)` or
162+
// `fmt::Formatter::debug_tuple_fields_finish(fmt, name, values)`
163+
let sym_debug = if is_struct {
164+
sym::debug_struct_fields_finish
165+
} else {
166+
sym::debug_tuple_fields_finish
167+
};
168+
let fn_path_debug_internal = cx.std_path(&[sym::fmt, sym::Formatter, sym_debug]);
169+
170+
let mut args = Vec::with_capacity(4);
171+
args.push(fmt);
172+
args.push(name);
173+
if is_struct {
174+
args.push(cx.expr_ident(span, Ident::new(sym::names, span)));
175+
}
176+
args.push(cx.expr_ident(span, Ident::new(sym::values, span)));
177+
let expr = cx.expr_call_global(span, fn_path_debug_internal, args);
147178

148-
fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast::Stmt {
149-
let local = P(ast::Local {
150-
pat: cx.pat_wild(sp),
151-
ty: None,
152-
id: ast::DUMMY_NODE_ID,
153-
kind: LocalKind::Init(expr),
154-
span: sp,
155-
attrs: ast::AttrVec::new(),
156-
tokens: None,
157-
});
158-
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
179+
let mut stmts = Vec::with_capacity(3);
180+
if is_struct {
181+
stmts.push(names_let.unwrap());
182+
}
183+
stmts.push(values_let);
184+
stmts.push(cx.stmt_expr(expr));
185+
186+
cx.expr_block(cx.block(span, stmts))
187+
}
159188
}

‎compiler/rustc_builtin_macros/src/deriving/decodable.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -162,14 +162,13 @@ fn decodable_substructure(
162162
cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms),
163163
);
164164
let lambda = cx.lambda(trait_span, vec![blkarg, variant], result);
165-
let variant_vec = cx.expr_vec(trait_span, variants);
166-
let variant_vec = cx.expr_addr_of(trait_span, variant_vec);
165+
let variant_array_ref = cx.expr_array_ref(trait_span, variants);
167166
let fn_read_enum_variant_path: Vec<_> =
168167
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]);
169168
let result = cx.expr_call_global(
170169
trait_span,
171170
fn_read_enum_variant_path,
172-
vec![blkdecoder, variant_vec, lambda],
171+
vec![blkdecoder, variant_array_ref, lambda],
173172
);
174173
let fn_read_enum_path: Vec<_> =
175174
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]);

‎compiler/rustc_builtin_macros/src/format.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ impl<'a, 'b> Context<'a, 'b> {
776776

777777
// First, build up the static array which will become our precompiled
778778
// format "string"
779-
let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces);
779+
let pieces = self.ecx.expr_array_ref(self.fmtsp, self.str_pieces);
780780

781781
// We need to construct a &[ArgumentV1] to pass into the fmt::Arguments
782782
// constructor. In general the expressions in this slice might be
@@ -849,7 +849,7 @@ impl<'a, 'b> Context<'a, 'b> {
849849
fmt_args.push(Context::format_arg(self.ecx, self.macsp, span, arg_ty, arg));
850850
}
851851

852-
let args_array = self.ecx.expr_vec(self.macsp, fmt_args);
852+
let args_array = self.ecx.expr_array(self.macsp, fmt_args);
853853
let args_slice = self.ecx.expr_addr_of(
854854
self.macsp,
855855
if no_need_for_match {
@@ -879,7 +879,7 @@ impl<'a, 'b> Context<'a, 'b> {
879879
} else {
880880
// Build up the static array which will store our precompiled
881881
// nonstandard placeholders, if there are any.
882-
let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces);
882+
let fmt = self.ecx.expr_array_ref(self.macsp, self.pieces);
883883

884884
let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]);
885885
let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new());

‎compiler/rustc_builtin_macros/src/proc_macro_harness.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
317317
proc_macro_ty_method_path(cx, custom_derive),
318318
vec![
319319
cx.expr_str(span, cd.trait_name),
320-
cx.expr_vec_slice(
320+
cx.expr_array_ref(
321321
span,
322322
cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<Vec<_>>(),
323323
),
@@ -362,7 +362,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
362362
ast::Mutability::Not,
363363
),
364364
ast::Mutability::Not,
365-
cx.expr_vec_slice(span, decls),
365+
cx.expr_array_ref(span, decls),
366366
)
367367
.map(|mut i| {
368368
let attr = cx.meta_word(span, sym::rustc_proc_macro_decls);

‎compiler/rustc_builtin_macros/src/test_harness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
352352
debug!("building test vector from {} tests", cx.test_cases.len());
353353
let ecx = &cx.ext_cx;
354354

355-
ecx.expr_vec_slice(
355+
ecx.expr_array_ref(
356356
sp,
357357
cx.test_cases
358358
.iter()

‎compiler/rustc_expand/src/build.rs

+27-4
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ impl<'a> ExtCtxt<'a> {
5757
P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind, tokens: None })
5858
}
5959

60+
pub fn ty_infer(&self, span: Span) -> P<ast::Ty> {
61+
self.ty(span, ast::TyKind::Infer)
62+
}
63+
6064
pub fn ty_path(&self, path: ast::Path) -> P<ast::Ty> {
6165
self.ty(path.span, ast::TyKind::Path(None, path))
6266
}
@@ -140,11 +144,26 @@ impl<'a> ExtCtxt<'a> {
140144
ast::Lifetime { id: ast::DUMMY_NODE_ID, ident: ident.with_span_pos(span) }
141145
}
142146

147+
pub fn lifetime_static(&self, span: Span) -> ast::Lifetime {
148+
self.lifetime(span, Ident::new(kw::StaticLifetime, span))
149+
}
150+
143151
pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
144152
ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) }
145153
}
146154

147155
pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P<ast::Expr>) -> ast::Stmt {
156+
self.stmt_let_ty(sp, mutbl, ident, None, ex)
157+
}
158+
159+
pub fn stmt_let_ty(
160+
&self,
161+
sp: Span,
162+
mutbl: bool,
163+
ident: Ident,
164+
ty: Option<P<ast::Ty>>,
165+
ex: P<ast::Expr>,
166+
) -> ast::Stmt {
148167
let pat = if mutbl {
149168
let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mut);
150169
self.pat_ident_binding_mode(sp, ident, binding_mode)
@@ -153,7 +172,7 @@ impl<'a> ExtCtxt<'a> {
153172
};
154173
let local = P(ast::Local {
155174
pat,
156-
ty: None,
175+
ty,
157176
id: ast::DUMMY_NODE_ID,
158177
kind: LocalKind::Init(ex),
159178
span: sp,
@@ -315,12 +334,16 @@ impl<'a> ExtCtxt<'a> {
315334
self.expr_lit(sp, ast::LitKind::Bool(value))
316335
}
317336

318-
pub fn expr_vec(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
337+
/// `[expr1, expr2, ...]`
338+
pub fn expr_array(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
319339
self.expr(sp, ast::ExprKind::Array(exprs))
320340
}
321-
pub fn expr_vec_slice(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
322-
self.expr_addr_of(sp, self.expr_vec(sp, exprs))
341+
342+
/// `&[expr1, expr2, ...]`
343+
pub fn expr_array_ref(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
344+
self.expr_addr_of(sp, self.expr_array(sp, exprs))
323345
}
346+
324347
pub fn expr_str(&self, sp: Span, s: Symbol) -> P<ast::Expr> {
325348
self.expr_lit(sp, ast::LitKind::Str(s, ast::StrStyle::Cooked))
326349
}

‎compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -567,8 +567,10 @@ symbols! {
567567
debug_assert_ne_macro,
568568
debug_assertions,
569569
debug_struct,
570+
debug_struct_fields_finish,
570571
debug_trait_builder,
571572
debug_tuple,
573+
debug_tuple_fields_finish,
572574
debugger_visualizer,
573575
decl_macro,
574576
declare_lint_pass,

‎compiler/rustc_type_ir/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(fmt_helpers_for_derive)]
12
#![feature(min_specialization)]
23
#![feature(rustc_attrs)]
34

‎compiler/rustc_type_ir/src/sty.rs

+31-131
Original file line numberDiff line numberDiff line change
@@ -554,137 +554,37 @@ impl<I: Interner> hash::Hash for TyKind<I> {
554554
// This is manually implemented because a derive would require `I: Debug`
555555
impl<I: Interner> fmt::Debug for TyKind<I> {
556556
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
557-
match (&*self,) {
558-
(&Bool,) => fmt::Formatter::write_str(f, "Bool"),
559-
(&Char,) => fmt::Formatter::write_str(f, "Char"),
560-
(&Int(ref __self_0),) => {
561-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Int");
562-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
563-
fmt::DebugTuple::finish(debug_trait_builder)
564-
}
565-
(&Uint(ref __self_0),) => {
566-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Uint");
567-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
568-
fmt::DebugTuple::finish(debug_trait_builder)
569-
}
570-
(&Float(ref __self_0),) => {
571-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Float");
572-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
573-
fmt::DebugTuple::finish(debug_trait_builder)
574-
}
575-
(&Adt(ref __self_0, ref __self_1),) => {
576-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Adt");
577-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
578-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
579-
fmt::DebugTuple::finish(debug_trait_builder)
580-
}
581-
(&Foreign(ref __self_0),) => {
582-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Foreign");
583-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
584-
fmt::DebugTuple::finish(debug_trait_builder)
585-
}
586-
(&Str,) => fmt::Formatter::write_str(f, "Str"),
587-
(&Array(ref __self_0, ref __self_1),) => {
588-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Array");
589-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
590-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
591-
fmt::DebugTuple::finish(debug_trait_builder)
592-
}
593-
(&Slice(ref __self_0),) => {
594-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Slice");
595-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
596-
fmt::DebugTuple::finish(debug_trait_builder)
597-
}
598-
(&RawPtr(ref __self_0),) => {
599-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "RawPtr");
600-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
601-
fmt::DebugTuple::finish(debug_trait_builder)
602-
}
603-
(&Ref(ref __self_0, ref __self_1, ref __self_2),) => {
604-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Ref");
605-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
606-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
607-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2);
608-
fmt::DebugTuple::finish(debug_trait_builder)
609-
}
610-
(&FnDef(ref __self_0, ref __self_1),) => {
611-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnDef");
612-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
613-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
614-
fmt::DebugTuple::finish(debug_trait_builder)
615-
}
616-
(&FnPtr(ref __self_0),) => {
617-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnPtr");
618-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
619-
fmt::DebugTuple::finish(debug_trait_builder)
620-
}
621-
(&Dynamic(ref __self_0, ref __self_1),) => {
622-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Dynamic");
623-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
624-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
625-
fmt::DebugTuple::finish(debug_trait_builder)
626-
}
627-
(&Closure(ref __self_0, ref __self_1),) => {
628-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Closure");
629-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
630-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
631-
fmt::DebugTuple::finish(debug_trait_builder)
632-
}
633-
(&Generator(ref __self_0, ref __self_1, ref __self_2),) => {
634-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Generator");
635-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
636-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
637-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2);
638-
fmt::DebugTuple::finish(debug_trait_builder)
639-
}
640-
(&GeneratorWitness(ref __self_0),) => {
641-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "GeneratorWitness");
642-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
643-
fmt::DebugTuple::finish(debug_trait_builder)
644-
}
645-
(&Never,) => fmt::Formatter::write_str(f, "Never"),
646-
(&Tuple(ref __self_0),) => {
647-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Tuple");
648-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
649-
fmt::DebugTuple::finish(debug_trait_builder)
650-
}
651-
(&Projection(ref __self_0),) => {
652-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Projection");
653-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
654-
fmt::DebugTuple::finish(debug_trait_builder)
655-
}
656-
(&Opaque(ref __self_0, ref __self_1),) => {
657-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Opaque");
658-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
659-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
660-
fmt::DebugTuple::finish(debug_trait_builder)
661-
}
662-
(&Param(ref __self_0),) => {
663-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Param");
664-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
665-
fmt::DebugTuple::finish(debug_trait_builder)
666-
}
667-
(&Bound(ref __self_0, ref __self_1),) => {
668-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Bound");
669-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
670-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
671-
fmt::DebugTuple::finish(debug_trait_builder)
672-
}
673-
(&Placeholder(ref __self_0),) => {
674-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Placeholder");
675-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
676-
fmt::DebugTuple::finish(debug_trait_builder)
677-
}
678-
(&Infer(ref __self_0),) => {
679-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Infer");
680-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
681-
fmt::DebugTuple::finish(debug_trait_builder)
682-
}
683-
(&Error(ref __self_0),) => {
684-
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Error");
685-
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
686-
fmt::DebugTuple::finish(debug_trait_builder)
687-
}
557+
use std::fmt::*;
558+
match self {
559+
Bool => Formatter::write_str(f, "Bool"),
560+
Char => Formatter::write_str(f, "Char"),
561+
Int(f0) => Formatter::debug_tuple_field1_finish(f, "Int", f0),
562+
Uint(f0) => Formatter::debug_tuple_field1_finish(f, "Uint", f0),
563+
Float(f0) => Formatter::debug_tuple_field1_finish(f, "Float", f0),
564+
Adt(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Adt", f0, f1),
565+
Foreign(f0) => Formatter::debug_tuple_field1_finish(f, "Foreign", f0),
566+
Str => Formatter::write_str(f, "Str"),
567+
Array(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Array", f0, f1),
568+
Slice(f0) => Formatter::debug_tuple_field1_finish(f, "Slice", f0),
569+
RawPtr(f0) => Formatter::debug_tuple_field1_finish(f, "RawPtr", f0),
570+
Ref(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Ref", f0, f1, f2),
571+
FnDef(f0, f1) => Formatter::debug_tuple_field2_finish(f, "FnDef", f0, f1),
572+
FnPtr(f0) => Formatter::debug_tuple_field1_finish(f, "FnPtr", f0),
573+
Dynamic(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Dynamic", f0, f1),
574+
Closure(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Closure", f0, f1),
575+
Generator(f0, f1, f2) => {
576+
Formatter::debug_tuple_field3_finish(f, "Generator", f0, f1, f2)
577+
}
578+
GeneratorWitness(f0) => Formatter::debug_tuple_field1_finish(f, "GeneratorWitness", f0),
579+
Never => Formatter::write_str(f, "Never"),
580+
Tuple(f0) => Formatter::debug_tuple_field1_finish(f, "Tuple", f0),
581+
Projection(f0) => Formatter::debug_tuple_field1_finish(f, "Projection", f0),
582+
Opaque(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Opaque", f0, f1),
583+
Param(f0) => Formatter::debug_tuple_field1_finish(f, "Param", f0),
584+
Bound(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Bound", f0, f1),
585+
Placeholder(f0) => Formatter::debug_tuple_field1_finish(f, "Placeholder", f0),
586+
Infer(f0) => Formatter::debug_tuple_field1_finish(f, "Infer", f0),
587+
TyKind::Error(f0) => Formatter::debug_tuple_field1_finish(f, "Error", f0),
688588
}
689589
}
690590
}

‎library/core/src/fmt/mod.rs

+227-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell};
66
use crate::char::EscapeDebugExtArgs;
7+
use crate::iter;
78
use crate::marker::PhantomData;
89
use crate::mem;
910
use crate::num::fmt as numfmt;
@@ -693,7 +694,7 @@ pub(crate) mod macros {
693694
/// Derive macro generating an impl of the trait `Debug`.
694695
#[rustc_builtin_macro]
695696
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
696-
#[allow_internal_unstable(core_intrinsics)]
697+
#[allow_internal_unstable(core_intrinsics, fmt_helpers_for_derive)]
697698
pub macro Debug($item:item) {
698699
/* compiler built-in */
699700
}
@@ -1964,6 +1965,129 @@ impl<'a> Formatter<'a> {
19641965
builders::debug_struct_new(self, name)
19651966
}
19661967

1968+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
1969+
/// `debug_struct_fields_finish` is more general, but this is faster for 1 field.
1970+
#[doc(hidden)]
1971+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
1972+
pub fn debug_struct_field1_finish<'b>(
1973+
&'b mut self,
1974+
name: &str,
1975+
name1: &str,
1976+
value1: &dyn Debug,
1977+
) -> Result {
1978+
let mut builder = builders::debug_struct_new(self, name);
1979+
builder.field(name1, value1);
1980+
builder.finish()
1981+
}
1982+
1983+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
1984+
/// `debug_struct_fields_finish` is more general, but this is faster for 2 fields.
1985+
#[doc(hidden)]
1986+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
1987+
pub fn debug_struct_field2_finish<'b>(
1988+
&'b mut self,
1989+
name: &str,
1990+
name1: &str,
1991+
value1: &dyn Debug,
1992+
name2: &str,
1993+
value2: &dyn Debug,
1994+
) -> Result {
1995+
let mut builder = builders::debug_struct_new(self, name);
1996+
builder.field(name1, value1);
1997+
builder.field(name2, value2);
1998+
builder.finish()
1999+
}
2000+
2001+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2002+
/// `debug_struct_fields_finish` is more general, but this is faster for 3 fields.
2003+
#[doc(hidden)]
2004+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2005+
pub fn debug_struct_field3_finish<'b>(
2006+
&'b mut self,
2007+
name: &str,
2008+
name1: &str,
2009+
value1: &dyn Debug,
2010+
name2: &str,
2011+
value2: &dyn Debug,
2012+
name3: &str,
2013+
value3: &dyn Debug,
2014+
) -> Result {
2015+
let mut builder = builders::debug_struct_new(self, name);
2016+
builder.field(name1, value1);
2017+
builder.field(name2, value2);
2018+
builder.field(name3, value3);
2019+
builder.finish()
2020+
}
2021+
2022+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2023+
/// `debug_struct_fields_finish` is more general, but this is faster for 4 fields.
2024+
#[doc(hidden)]
2025+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2026+
pub fn debug_struct_field4_finish<'b>(
2027+
&'b mut self,
2028+
name: &str,
2029+
name1: &str,
2030+
value1: &dyn Debug,
2031+
name2: &str,
2032+
value2: &dyn Debug,
2033+
name3: &str,
2034+
value3: &dyn Debug,
2035+
name4: &str,
2036+
value4: &dyn Debug,
2037+
) -> Result {
2038+
let mut builder = builders::debug_struct_new(self, name);
2039+
builder.field(name1, value1);
2040+
builder.field(name2, value2);
2041+
builder.field(name3, value3);
2042+
builder.field(name4, value4);
2043+
builder.finish()
2044+
}
2045+
2046+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2047+
/// `debug_struct_fields_finish` is more general, but this is faster for 5 fields.
2048+
#[doc(hidden)]
2049+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2050+
pub fn debug_struct_field5_finish<'b>(
2051+
&'b mut self,
2052+
name: &str,
2053+
name1: &str,
2054+
value1: &dyn Debug,
2055+
name2: &str,
2056+
value2: &dyn Debug,
2057+
name3: &str,
2058+
value3: &dyn Debug,
2059+
name4: &str,
2060+
value4: &dyn Debug,
2061+
name5: &str,
2062+
value5: &dyn Debug,
2063+
) -> Result {
2064+
let mut builder = builders::debug_struct_new(self, name);
2065+
builder.field(name1, value1);
2066+
builder.field(name2, value2);
2067+
builder.field(name3, value3);
2068+
builder.field(name4, value4);
2069+
builder.field(name5, value5);
2070+
builder.finish()
2071+
}
2072+
2073+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2074+
/// For the cases not covered by `debug_struct_field[12345]_finish`.
2075+
#[doc(hidden)]
2076+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2077+
pub fn debug_struct_fields_finish<'b>(
2078+
&'b mut self,
2079+
name: &str,
2080+
names: &[&str],
2081+
values: &[&dyn Debug],
2082+
) -> Result {
2083+
assert_eq!(names.len(), values.len());
2084+
let mut builder = builders::debug_struct_new(self, name);
2085+
for (name, value) in iter::zip(names, values) {
2086+
builder.field(name, value);
2087+
}
2088+
builder.finish()
2089+
}
2090+
19672091
/// Creates a `DebugTuple` builder designed to assist with creation of
19682092
/// `fmt::Debug` implementations for tuple structs.
19692093
///
@@ -1995,6 +2119,108 @@ impl<'a> Formatter<'a> {
19952119
builders::debug_tuple_new(self, name)
19962120
}
19972121

2122+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2123+
/// `debug_tuple_fields_finish` is more general, but this is faster for 1 field.
2124+
#[doc(hidden)]
2125+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2126+
pub fn debug_tuple_field1_finish<'b>(&'b mut self, name: &str, value1: &dyn Debug) -> Result {
2127+
let mut builder = builders::debug_tuple_new(self, name);
2128+
builder.field(value1);
2129+
builder.finish()
2130+
}
2131+
2132+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2133+
/// `debug_tuple_fields_finish` is more general, but this is faster for 2 fields.
2134+
#[doc(hidden)]
2135+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2136+
pub fn debug_tuple_field2_finish<'b>(
2137+
&'b mut self,
2138+
name: &str,
2139+
value1: &dyn Debug,
2140+
value2: &dyn Debug,
2141+
) -> Result {
2142+
let mut builder = builders::debug_tuple_new(self, name);
2143+
builder.field(value1);
2144+
builder.field(value2);
2145+
builder.finish()
2146+
}
2147+
2148+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2149+
/// `debug_tuple_fields_finish` is more general, but this is faster for 3 fields.
2150+
#[doc(hidden)]
2151+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2152+
pub fn debug_tuple_field3_finish<'b>(
2153+
&'b mut self,
2154+
name: &str,
2155+
value1: &dyn Debug,
2156+
value2: &dyn Debug,
2157+
value3: &dyn Debug,
2158+
) -> Result {
2159+
let mut builder = builders::debug_tuple_new(self, name);
2160+
builder.field(value1);
2161+
builder.field(value2);
2162+
builder.field(value3);
2163+
builder.finish()
2164+
}
2165+
2166+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2167+
/// `debug_tuple_fields_finish` is more general, but this is faster for 4 fields.
2168+
#[doc(hidden)]
2169+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2170+
pub fn debug_tuple_field4_finish<'b>(
2171+
&'b mut self,
2172+
name: &str,
2173+
value1: &dyn Debug,
2174+
value2: &dyn Debug,
2175+
value3: &dyn Debug,
2176+
value4: &dyn Debug,
2177+
) -> Result {
2178+
let mut builder = builders::debug_tuple_new(self, name);
2179+
builder.field(value1);
2180+
builder.field(value2);
2181+
builder.field(value3);
2182+
builder.field(value4);
2183+
builder.finish()
2184+
}
2185+
2186+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2187+
/// `debug_tuple_fields_finish` is more general, but this is faster for 5 fields.
2188+
#[doc(hidden)]
2189+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2190+
pub fn debug_tuple_field5_finish<'b>(
2191+
&'b mut self,
2192+
name: &str,
2193+
value1: &dyn Debug,
2194+
value2: &dyn Debug,
2195+
value3: &dyn Debug,
2196+
value4: &dyn Debug,
2197+
value5: &dyn Debug,
2198+
) -> Result {
2199+
let mut builder = builders::debug_tuple_new(self, name);
2200+
builder.field(value1);
2201+
builder.field(value2);
2202+
builder.field(value3);
2203+
builder.field(value4);
2204+
builder.field(value5);
2205+
builder.finish()
2206+
}
2207+
2208+
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
2209+
/// For the cases not covered by `debug_tuple_field[12345]_finish`.
2210+
#[doc(hidden)]
2211+
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
2212+
pub fn debug_tuple_fields_finish<'b>(
2213+
&'b mut self,
2214+
name: &str,
2215+
values: &[&dyn Debug],
2216+
) -> Result {
2217+
let mut builder = builders::debug_tuple_new(self, name);
2218+
for value in values {
2219+
builder.field(value);
2220+
}
2221+
builder.finish()
2222+
}
2223+
19982224
/// Creates a `DebugList` builder designed to assist with creation of
19992225
/// `fmt::Debug` implementations for list-like structures.
20002226
///

0 commit comments

Comments
 (0)
Please sign in to comment.