Auto merge of #98190 - nnethercote:optimize-derive-Debug-code, r=scottmcm

Improve `derive(Debug)`

r? `@ghost`
This commit is contained in:
bors 2022-06-26 15:00:04 +00:00
commit 788ddedb0d
10 changed files with 412 additions and 232 deletions

View File

@ -3,14 +3,10 @@ use crate::deriving::generic::*;
use crate::deriving::path_std;
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Expr, LocalKind, MetaItem};
use rustc_ast::{self as ast, Expr, MetaItem};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
fn make_mut_borrow(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<Expr>) -> P<Expr> {
cx.expr(sp, ast::ExprKind::AddrOf(ast::BorrowKind::Ref, ast::Mutability::Mut, expr))
}
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
pub fn expand_deriving_debug(
cx: &mut ExtCtxt<'_>,
@ -49,11 +45,7 @@ pub fn expand_deriving_debug(
trait_def.expand(cx, mitem, item, push)
}
/// We use the debug builders to do the heavy lifting here
fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
// build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
// or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
// based on the "shape".
let (ident, vdata, fields) = match substr.fields {
Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
@ -67,93 +59,130 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
let fmt = substr.nonself_args[0].clone();
// Special fast path for unit variants. In the common case of an enum that is entirely unit
// variants (i.e. a C-like enum), this fast path allows LLVM to eliminate the entire switch in
// favor of a lookup table.
if let ast::VariantData::Unit(..) = vdata {
let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
let stmts = vec![cx.stmt_expr(expr)];
let block = cx.block(span, stmts);
return cx.expr_block(block);
}
let builder = Ident::new(sym::debug_trait_builder, span);
let builder_expr = cx.expr_ident(span, builder);
let mut stmts = Vec::with_capacity(fields.len() + 2);
let fn_path_finish;
match vdata {
// Struct and tuples are similar enough that we use the same code for both,
// with some extra pieces for structs due to the field names.
let (is_struct, args_per_field) = match vdata {
ast::VariantData::Unit(..) => {
cx.span_bug(span, "unit variants should have been handled above");
// Special fast path for unit variants.
//let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
//return cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
assert!(fields.is_empty());
(false, 0)
}
ast::VariantData::Tuple(..) => {
// tuple struct/"normal" variant
let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]);
let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]);
let expr = make_mut_borrow(cx, span, expr);
stmts.push(cx.stmt_let(span, false, builder, expr));
ast::VariantData::Tuple(..) => (false, 1),
ast::VariantData::Struct(..) => (true, 2),
};
for field in fields {
// Use double indirection to make sure this works for unsized types
let field = cx.expr_addr_of(field.span, field.self_.clone());
let field = cx.expr_addr_of(field.span, field);
// The number of fields that can be handled without an array.
const CUTOFF: usize = 5;
let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::field]);
let expr =
cx.expr_call_global(span, fn_path_field, vec![builder_expr.clone(), field]);
if fields.is_empty() {
// Special case for no fields.
let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
cx.expr_call_global(span, fn_path_write_str, vec![fmt, name])
} else if fields.len() <= CUTOFF {
// Few enough fields that we can use a specific-length method.
let debug = if is_struct {
format!("debug_struct_field{}_finish", fields.len())
} else {
format!("debug_tuple_field{}_finish", fields.len())
};
let fn_path_debug = cx.std_path(&[sym::fmt, sym::Formatter, Symbol::intern(&debug)]);
// Use `let _ = expr;` to avoid triggering the
// unused_results lint.
stmts.push(stmt_let_underscore(cx, span, expr));
}
fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::finish]);
}
ast::VariantData::Struct(..) => {
// normal struct/struct variant
let fn_path_debug_struct = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_struct]);
let expr = cx.expr_call_global(span, fn_path_debug_struct, vec![fmt, name]);
let expr = make_mut_borrow(cx, span, expr);
stmts.push(cx.stmt_let(DUMMY_SP, false, builder, expr));
for field in fields {
let mut args = Vec::with_capacity(2 + fields.len() * args_per_field);
args.extend([fmt, name]);
for i in 0..fields.len() {
let field = &fields[i];
if is_struct {
let name = cx.expr_lit(
field.span,
ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
);
// Use double indirection to make sure this works for unsized types
let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::field]);
let field = cx.expr_addr_of(field.span, field.self_.clone());
let field = cx.expr_addr_of(field.span, field);
let expr = cx.expr_call_global(
span,
fn_path_field,
vec![builder_expr.clone(), name, field],
);
stmts.push(stmt_let_underscore(cx, span, expr));
args.push(name);
}
fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::finish]);
// Use double indirection to make sure this works for unsized types
let field = cx.expr_addr_of(field.span, field.self_.clone());
let field = cx.expr_addr_of(field.span, field);
args.push(field);
}
cx.expr_call_global(span, fn_path_debug, args)
} else {
// Enough fields that we must use the any-length method.
let mut name_exprs = Vec::with_capacity(fields.len());
let mut value_exprs = Vec::with_capacity(fields.len());
for field in fields {
if is_struct {
name_exprs.push(cx.expr_lit(
field.span,
ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
));
}
// Use double indirection to make sure this works for unsized types
let value_ref = cx.expr_addr_of(field.span, field.self_.clone());
value_exprs.push(cx.expr_addr_of(field.span, value_ref));
}
// `let names: &'static _ = &["field1", "field2"];`
let names_let = if is_struct {
let lt_static = Some(cx.lifetime_static(span));
let ty_static_ref =
cx.ty_rptr(span, cx.ty_infer(span), lt_static, ast::Mutability::Not);
Some(cx.stmt_let_ty(
span,
false,
Ident::new(sym::names, span),
Some(ty_static_ref),
cx.expr_array_ref(span, name_exprs),
))
} else {
None
};
// `let values: &[&dyn Debug] = &[&&self.field1, &&self.field2];`
let path_debug = cx.path_global(span, cx.std_path(&[sym::fmt, sym::Debug]));
let ty_dyn_debug = cx.ty(
span,
ast::TyKind::TraitObject(vec![cx.trait_bound(path_debug)], ast::TraitObjectSyntax::Dyn),
);
let ty_slice = cx.ty(
span,
ast::TyKind::Slice(cx.ty_rptr(span, ty_dyn_debug, None, ast::Mutability::Not)),
);
let values_let = cx.stmt_let_ty(
span,
false,
Ident::new(sym::values, span),
Some(cx.ty_rptr(span, ty_slice, None, ast::Mutability::Not)),
cx.expr_array_ref(span, value_exprs),
);
// `fmt::Formatter::debug_struct_fields_finish(fmt, name, names, values)` or
// `fmt::Formatter::debug_tuple_fields_finish(fmt, name, values)`
let sym_debug = if is_struct {
sym::debug_struct_fields_finish
} else {
sym::debug_tuple_fields_finish
};
let fn_path_debug_internal = cx.std_path(&[sym::fmt, sym::Formatter, sym_debug]);
let mut args = Vec::with_capacity(4);
args.push(fmt);
args.push(name);
if is_struct {
args.push(cx.expr_ident(span, Ident::new(sym::names, span)));
}
args.push(cx.expr_ident(span, Ident::new(sym::values, span)));
let expr = cx.expr_call_global(span, fn_path_debug_internal, args);
let mut stmts = Vec::with_capacity(3);
if is_struct {
stmts.push(names_let.unwrap());
}
stmts.push(values_let);
stmts.push(cx.stmt_expr(expr));
cx.expr_block(cx.block(span, stmts))
}
let expr = cx.expr_call_global(span, fn_path_finish, vec![builder_expr]);
stmts.push(cx.stmt_expr(expr));
let block = cx.block(span, stmts);
cx.expr_block(block)
}
fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast::Stmt {
let local = P(ast::Local {
pat: cx.pat_wild(sp),
ty: None,
id: ast::DUMMY_NODE_ID,
kind: LocalKind::Init(expr),
span: sp,
attrs: ast::AttrVec::new(),
tokens: None,
});
ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
}

View File

@ -162,14 +162,13 @@ fn decodable_substructure(
cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms),
);
let lambda = cx.lambda(trait_span, vec![blkarg, variant], result);
let variant_vec = cx.expr_vec(trait_span, variants);
let variant_vec = cx.expr_addr_of(trait_span, variant_vec);
let variant_array_ref = cx.expr_array_ref(trait_span, variants);
let fn_read_enum_variant_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]);
let result = cx.expr_call_global(
trait_span,
fn_read_enum_variant_path,
vec![blkdecoder, variant_vec, lambda],
vec![blkdecoder, variant_array_ref, lambda],
);
let fn_read_enum_path: Vec<_> =
cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]);

View File

@ -776,7 +776,7 @@ impl<'a, 'b> Context<'a, 'b> {
// First, build up the static array which will become our precompiled
// format "string"
let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces);
let pieces = self.ecx.expr_array_ref(self.fmtsp, self.str_pieces);
// We need to construct a &[ArgumentV1] to pass into the fmt::Arguments
// constructor. In general the expressions in this slice might be
@ -849,7 +849,7 @@ impl<'a, 'b> Context<'a, 'b> {
fmt_args.push(Context::format_arg(self.ecx, self.macsp, span, arg_ty, arg));
}
let args_array = self.ecx.expr_vec(self.macsp, fmt_args);
let args_array = self.ecx.expr_array(self.macsp, fmt_args);
let args_slice = self.ecx.expr_addr_of(
self.macsp,
if no_need_for_match {
@ -879,7 +879,7 @@ impl<'a, 'b> Context<'a, 'b> {
} else {
// Build up the static array which will store our precompiled
// nonstandard placeholders, if there are any.
let fmt = self.ecx.expr_vec_slice(self.macsp, self.pieces);
let fmt = self.ecx.expr_array_ref(self.macsp, self.pieces);
let path = self.ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]);
let unsafe_arg = self.ecx.expr_call_global(self.macsp, path, Vec::new());

View File

@ -317,7 +317,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
proc_macro_ty_method_path(cx, custom_derive),
vec![
cx.expr_str(span, cd.trait_name),
cx.expr_vec_slice(
cx.expr_array_ref(
span,
cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<Vec<_>>(),
),
@ -362,7 +362,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
ast::Mutability::Not,
),
ast::Mutability::Not,
cx.expr_vec_slice(span, decls),
cx.expr_array_ref(span, decls),
)
.map(|mut i| {
let attr = cx.meta_word(span, sym::rustc_proc_macro_decls);

View File

@ -352,7 +352,7 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P<ast::Expr> {
debug!("building test vector from {} tests", cx.test_cases.len());
let ecx = &cx.ext_cx;
ecx.expr_vec_slice(
ecx.expr_array_ref(
sp,
cx.test_cases
.iter()

View File

@ -57,6 +57,10 @@ impl<'a> ExtCtxt<'a> {
P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind, tokens: None })
}
pub fn ty_infer(&self, span: Span) -> P<ast::Ty> {
self.ty(span, ast::TyKind::Infer)
}
pub fn ty_path(&self, path: ast::Path) -> P<ast::Ty> {
self.ty(path.span, ast::TyKind::Path(None, path))
}
@ -140,11 +144,26 @@ impl<'a> ExtCtxt<'a> {
ast::Lifetime { id: ast::DUMMY_NODE_ID, ident: ident.with_span_pos(span) }
}
pub fn lifetime_static(&self, span: Span) -> ast::Lifetime {
self.lifetime(span, Ident::new(kw::StaticLifetime, span))
}
pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) }
}
pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P<ast::Expr>) -> ast::Stmt {
self.stmt_let_ty(sp, mutbl, ident, None, ex)
}
pub fn stmt_let_ty(
&self,
sp: Span,
mutbl: bool,
ident: Ident,
ty: Option<P<ast::Ty>>,
ex: P<ast::Expr>,
) -> ast::Stmt {
let pat = if mutbl {
let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mut);
self.pat_ident_binding_mode(sp, ident, binding_mode)
@ -153,7 +172,7 @@ impl<'a> ExtCtxt<'a> {
};
let local = P(ast::Local {
pat,
ty: None,
ty,
id: ast::DUMMY_NODE_ID,
kind: LocalKind::Init(ex),
span: sp,
@ -315,12 +334,16 @@ impl<'a> ExtCtxt<'a> {
self.expr_lit(sp, ast::LitKind::Bool(value))
}
pub fn expr_vec(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
/// `[expr1, expr2, ...]`
pub fn expr_array(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
self.expr(sp, ast::ExprKind::Array(exprs))
}
pub fn expr_vec_slice(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
self.expr_addr_of(sp, self.expr_vec(sp, exprs))
/// `&[expr1, expr2, ...]`
pub fn expr_array_ref(&self, sp: Span, exprs: Vec<P<ast::Expr>>) -> P<ast::Expr> {
self.expr_addr_of(sp, self.expr_array(sp, exprs))
}
pub fn expr_str(&self, sp: Span, s: Symbol) -> P<ast::Expr> {
self.expr_lit(sp, ast::LitKind::Str(s, ast::StrStyle::Cooked))
}

View File

@ -567,8 +567,10 @@ symbols! {
debug_assert_ne_macro,
debug_assertions,
debug_struct,
debug_struct_fields_finish,
debug_trait_builder,
debug_tuple,
debug_tuple_fields_finish,
debugger_visualizer,
decl_macro,
declare_lint_pass,

View File

@ -1,3 +1,4 @@
#![feature(fmt_helpers_for_derive)]
#![feature(min_specialization)]
#![feature(rustc_attrs)]

View File

@ -554,137 +554,37 @@ impl<I: Interner> hash::Hash for TyKind<I> {
// This is manually implemented because a derive would require `I: Debug`
impl<I: Interner> fmt::Debug for TyKind<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match (&*self,) {
(&Bool,) => fmt::Formatter::write_str(f, "Bool"),
(&Char,) => fmt::Formatter::write_str(f, "Char"),
(&Int(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Int");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Uint(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Uint");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Float(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Float");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Adt(ref __self_0, ref __self_1),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Adt");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Foreign(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Foreign");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Str,) => fmt::Formatter::write_str(f, "Str"),
(&Array(ref __self_0, ref __self_1),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Array");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Slice(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Slice");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&RawPtr(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "RawPtr");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Ref(ref __self_0, ref __self_1, ref __self_2),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Ref");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&FnDef(ref __self_0, ref __self_1),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnDef");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&FnPtr(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "FnPtr");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Dynamic(ref __self_0, ref __self_1),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Dynamic");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Closure(ref __self_0, ref __self_1),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Closure");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Generator(ref __self_0, ref __self_1, ref __self_2),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Generator");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_2);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&GeneratorWitness(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "GeneratorWitness");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Never,) => fmt::Formatter::write_str(f, "Never"),
(&Tuple(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Tuple");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Projection(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Projection");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Opaque(ref __self_0, ref __self_1),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Opaque");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Param(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Param");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Bound(ref __self_0, ref __self_1),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Bound");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_1);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Placeholder(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Placeholder");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Infer(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Infer");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
}
(&Error(ref __self_0),) => {
let debug_trait_builder = &mut fmt::Formatter::debug_tuple(f, "Error");
let _ = fmt::DebugTuple::field(debug_trait_builder, &__self_0);
fmt::DebugTuple::finish(debug_trait_builder)
use std::fmt::*;
match self {
Bool => Formatter::write_str(f, "Bool"),
Char => Formatter::write_str(f, "Char"),
Int(f0) => Formatter::debug_tuple_field1_finish(f, "Int", f0),
Uint(f0) => Formatter::debug_tuple_field1_finish(f, "Uint", f0),
Float(f0) => Formatter::debug_tuple_field1_finish(f, "Float", f0),
Adt(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Adt", f0, f1),
Foreign(f0) => Formatter::debug_tuple_field1_finish(f, "Foreign", f0),
Str => Formatter::write_str(f, "Str"),
Array(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Array", f0, f1),
Slice(f0) => Formatter::debug_tuple_field1_finish(f, "Slice", f0),
RawPtr(f0) => Formatter::debug_tuple_field1_finish(f, "RawPtr", f0),
Ref(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Ref", f0, f1, f2),
FnDef(f0, f1) => Formatter::debug_tuple_field2_finish(f, "FnDef", f0, f1),
FnPtr(f0) => Formatter::debug_tuple_field1_finish(f, "FnPtr", f0),
Dynamic(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Dynamic", f0, f1),
Closure(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Closure", f0, f1),
Generator(f0, f1, f2) => {
Formatter::debug_tuple_field3_finish(f, "Generator", f0, f1, f2)
}
GeneratorWitness(f0) => Formatter::debug_tuple_field1_finish(f, "GeneratorWitness", f0),
Never => Formatter::write_str(f, "Never"),
Tuple(f0) => Formatter::debug_tuple_field1_finish(f, "Tuple", f0),
Projection(f0) => Formatter::debug_tuple_field1_finish(f, "Projection", f0),
Opaque(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Opaque", f0, f1),
Param(f0) => Formatter::debug_tuple_field1_finish(f, "Param", f0),
Bound(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Bound", f0, f1),
Placeholder(f0) => Formatter::debug_tuple_field1_finish(f, "Placeholder", f0),
Infer(f0) => Formatter::debug_tuple_field1_finish(f, "Infer", f0),
TyKind::Error(f0) => Formatter::debug_tuple_field1_finish(f, "Error", f0),
}
}
}

View File

@ -4,6 +4,7 @@
use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell};
use crate::char::EscapeDebugExtArgs;
use crate::iter;
use crate::marker::PhantomData;
use crate::mem;
use crate::num::fmt as numfmt;
@ -693,7 +694,7 @@ pub(crate) mod macros {
/// Derive macro generating an impl of the trait `Debug`.
#[rustc_builtin_macro]
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
#[allow_internal_unstable(core_intrinsics)]
#[allow_internal_unstable(core_intrinsics, fmt_helpers_for_derive)]
pub macro Debug($item:item) {
/* compiler built-in */
}
@ -1964,6 +1965,129 @@ impl<'a> Formatter<'a> {
builders::debug_struct_new(self, name)
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_struct_fields_finish` is more general, but this is faster for 1 field.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_field1_finish<'b>(
&'b mut self,
name: &str,
name1: &str,
value1: &dyn Debug,
) -> Result {
let mut builder = builders::debug_struct_new(self, name);
builder.field(name1, value1);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_struct_fields_finish` is more general, but this is faster for 2 fields.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_field2_finish<'b>(
&'b mut self,
name: &str,
name1: &str,
value1: &dyn Debug,
name2: &str,
value2: &dyn Debug,
) -> Result {
let mut builder = builders::debug_struct_new(self, name);
builder.field(name1, value1);
builder.field(name2, value2);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_struct_fields_finish` is more general, but this is faster for 3 fields.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_field3_finish<'b>(
&'b mut self,
name: &str,
name1: &str,
value1: &dyn Debug,
name2: &str,
value2: &dyn Debug,
name3: &str,
value3: &dyn Debug,
) -> Result {
let mut builder = builders::debug_struct_new(self, name);
builder.field(name1, value1);
builder.field(name2, value2);
builder.field(name3, value3);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_struct_fields_finish` is more general, but this is faster for 4 fields.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_field4_finish<'b>(
&'b mut self,
name: &str,
name1: &str,
value1: &dyn Debug,
name2: &str,
value2: &dyn Debug,
name3: &str,
value3: &dyn Debug,
name4: &str,
value4: &dyn Debug,
) -> Result {
let mut builder = builders::debug_struct_new(self, name);
builder.field(name1, value1);
builder.field(name2, value2);
builder.field(name3, value3);
builder.field(name4, value4);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_struct_fields_finish` is more general, but this is faster for 5 fields.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_field5_finish<'b>(
&'b mut self,
name: &str,
name1: &str,
value1: &dyn Debug,
name2: &str,
value2: &dyn Debug,
name3: &str,
value3: &dyn Debug,
name4: &str,
value4: &dyn Debug,
name5: &str,
value5: &dyn Debug,
) -> Result {
let mut builder = builders::debug_struct_new(self, name);
builder.field(name1, value1);
builder.field(name2, value2);
builder.field(name3, value3);
builder.field(name4, value4);
builder.field(name5, value5);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// For the cases not covered by `debug_struct_field[12345]_finish`.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_fields_finish<'b>(
&'b mut self,
name: &str,
names: &[&str],
values: &[&dyn Debug],
) -> Result {
assert_eq!(names.len(), values.len());
let mut builder = builders::debug_struct_new(self, name);
for (name, value) in iter::zip(names, values) {
builder.field(name, value);
}
builder.finish()
}
/// Creates a `DebugTuple` builder designed to assist with creation of
/// `fmt::Debug` implementations for tuple structs.
///
@ -1995,6 +2119,108 @@ impl<'a> Formatter<'a> {
builders::debug_tuple_new(self, name)
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_tuple_fields_finish` is more general, but this is faster for 1 field.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_tuple_field1_finish<'b>(&'b mut self, name: &str, value1: &dyn Debug) -> Result {
let mut builder = builders::debug_tuple_new(self, name);
builder.field(value1);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_tuple_fields_finish` is more general, but this is faster for 2 fields.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_tuple_field2_finish<'b>(
&'b mut self,
name: &str,
value1: &dyn Debug,
value2: &dyn Debug,
) -> Result {
let mut builder = builders::debug_tuple_new(self, name);
builder.field(value1);
builder.field(value2);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_tuple_fields_finish` is more general, but this is faster for 3 fields.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_tuple_field3_finish<'b>(
&'b mut self,
name: &str,
value1: &dyn Debug,
value2: &dyn Debug,
value3: &dyn Debug,
) -> Result {
let mut builder = builders::debug_tuple_new(self, name);
builder.field(value1);
builder.field(value2);
builder.field(value3);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_tuple_fields_finish` is more general, but this is faster for 4 fields.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_tuple_field4_finish<'b>(
&'b mut self,
name: &str,
value1: &dyn Debug,
value2: &dyn Debug,
value3: &dyn Debug,
value4: &dyn Debug,
) -> Result {
let mut builder = builders::debug_tuple_new(self, name);
builder.field(value1);
builder.field(value2);
builder.field(value3);
builder.field(value4);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// `debug_tuple_fields_finish` is more general, but this is faster for 5 fields.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_tuple_field5_finish<'b>(
&'b mut self,
name: &str,
value1: &dyn Debug,
value2: &dyn Debug,
value3: &dyn Debug,
value4: &dyn Debug,
value5: &dyn Debug,
) -> Result {
let mut builder = builders::debug_tuple_new(self, name);
builder.field(value1);
builder.field(value2);
builder.field(value3);
builder.field(value4);
builder.field(value5);
builder.finish()
}
/// Used to shrink `derive(Debug)` code, for faster compilation and smaller binaries.
/// For the cases not covered by `debug_tuple_field[12345]_finish`.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_tuple_fields_finish<'b>(
&'b mut self,
name: &str,
values: &[&dyn Debug],
) -> Result {
let mut builder = builders::debug_tuple_new(self, name);
for value in values {
builder.field(value);
}
builder.finish()
}
/// Creates a `DebugList` builder designed to assist with creation of
/// `fmt::Debug` implementations for list-like structures.
///