Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 46 additions & 36 deletions compiler/rustc_builtin_macros/src/deriving/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,26 @@ fn show_substructure(
_ => cx.dcx().span_bug(span, "unexpected substructure in `derive(Debug)`"),
};

let name = cx.expr_str(span, ident.name);
let expr_name = || cx.expr_str(span, ident.name);
let fmt = cx.expr_name(span, sym::f);

// Fieldless enums have been special-cased earlier
if fmt_detail == FmtDebug::Shallow {
let fn_path_write_str = cx.std_path(span, &[sym::fmt, sym::Formatter, sym::write_str]);
let expr = cx.expr_call_global(span, fn_path_write_str, thin_vec![fmt, name]);
let expr = cx.expr_call_global(span, fn_path_write_str, thin_vec![fmt, expr_name()]);
return BlockOrExpr::new_expr(expr);
}

// 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 {
let is_struct = match vdata {
ast::VariantData::Unit(..) => {
// Special fast path for unit variants.
assert!(fields.is_empty());
(false, 0)
false
}
ast::VariantData::Tuple(..) => (false, 1),
ast::VariantData::Struct { .. } => (true, 2),
ast::VariantData::Tuple(..) => false,
ast::VariantData::Struct { .. } => true,
};

// The number of fields that can be handled without an array.
Expand All @@ -114,7 +114,7 @@ fn show_substructure(
if fields.is_empty() {
// Special case for no fields.
let fn_path_write_str = cx.std_path(span, &[sym::fmt, sym::Formatter, sym::write_str]);
let expr = cx.expr_call_global(span, fn_path_write_str, thin_vec![fmt, name]);
let expr = cx.expr_call_global(span, fn_path_write_str, thin_vec![fmt, expr_name()]);
BlockOrExpr::new_expr(expr)
} else if fields.len() <= CUTOFF {
// Few enough fields that we can use a specific-length method.
Expand All @@ -125,44 +125,54 @@ fn show_substructure(
};
let fn_path_debug = cx.std_path(span, &[sym::fmt, sym::Formatter, Symbol::intern(&debug)]);

let mut args = ThinVec::with_capacity(2 + fields.len() * args_per_field);
args.extend([fmt, name]);
for (i, field) in fields.into_iter().enumerate() {
if is_struct {
let name = cx.expr_str(field.span, field.name.unwrap().name);
args.push(name);
let mut args = ThinVec::with_capacity(2 + fields.len());
args.extend([fmt]);

if is_struct {
let mut names = String::new();
names.push_str(ident.name.as_str());

for field in fields.iter() {
names.push(' ');
names.push_str(field.name.unwrap().name.as_str());
}

let name_expr = cx.expr_str(span, Symbol::intern(&names));
args.push(name_expr);
} else {
args.push(expr_name());
};

for (i, field) in fields.into_iter().enumerate() {
let field = expr_for_field(field, i);
args.push(field);
}
let expr = cx.expr_call_global(span, fn_path_debug, args);
BlockOrExpr::new_expr(expr)
} else {
// Enough fields that we must use the any-length method.
let mut name_exprs = ThinVec::with_capacity(fields.len());
let mut names = String::new();
if is_struct {
names.push_str(ident.name.as_str());
}
let mut value_exprs = ThinVec::with_capacity(fields.len());

for (i, field) in fields.into_iter().enumerate() {
if is_struct {
name_exprs.push(cx.expr_str(field.span, field.name.unwrap().name));
names.push(' ');
names.push_str(field.name.unwrap().name.as_str());
}

let field = expr_for_field(field, i);
value_exprs.push(field);
}

// `let names: &'static _ = &["field1", "field2"];`
// `let names: &'static _ = "StructName field1 field2"`
let names_let = is_struct.then(|| {
let lt_static = Some(cx.lifetime_static(span));
let ty_static_ref = cx.ty_ref(span, cx.ty_infer(span), lt_static, ast::Mutability::Not);
cx.stmt_let_ty(
span,
false,
sym::names,
Some(ty_static_ref),
cx.expr_array_ref(span, name_exprs),
)
let names_expr = cx.expr_str(span, Symbol::intern(&names));
cx.stmt_let_ty(span, false, sym::names, Some(ty_static_ref), names_expr)
});

// `let values: &[&dyn Debug] = &[&&self.field1, &&self.field2];`
Expand All @@ -186,7 +196,7 @@ fn show_substructure(
cx.expr_array_ref(span, value_exprs),
);

// `fmt::Formatter::debug_struct_fields_finish(fmt, name, names, values)` or
// `fmt::Formatter::debug_struct_fields_finish(fmt, names, values)` or
// `fmt::Formatter::debug_tuple_fields_finish(fmt, name, values)`
let sym_debug = if is_struct {
sym::debug_struct_fields_finish
Expand All @@ -195,20 +205,20 @@ fn show_substructure(
};
let fn_path_debug_internal = cx.std_path(span, &[sym::fmt, sym::Formatter, sym_debug]);

let mut args = ThinVec::with_capacity(4);
args.push(fmt);
args.push(name);
if is_struct {
args.push(cx.expr_name(span, sym::names));
}
args.push(cx.expr_name(span, sym::values));
let args = thin_vec![
fmt,
if is_struct { cx.expr_name(span, sym::names) } else { expr_name() },
cx.expr_name(span, sym::values)
];

let expr = cx.expr_call_global(span, fn_path_debug_internal, args);

let mut stmts = ThinVec::with_capacity(2);
if is_struct {
stmts.push(names_let.unwrap());
}
stmts.push(values_let);
let stmts = if is_struct {
thin_vec![names_let.unwrap(), values_let]
} else {
thin_vec![values_let]
};

BlockOrExpr::new_mixed(stmts, Some(expr))
}
}
Expand Down
87 changes: 37 additions & 50 deletions library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::marker::{PhantomData, PointeeSized};
use crate::num::imp::fmt as numfmt;
use crate::ops::Deref;
use crate::ptr::NonNull;
use crate::{iter, mem, result, str};
use crate::{mem, result, str};

mod builders;
#[cfg(not(no_fp_fmt_parse))]
Expand Down Expand Up @@ -2496,14 +2496,10 @@ impl<'a> Formatter<'a> {
/// 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);
pub fn debug_struct_field1_finish<'b>(&'b mut self, names: &str, value1: &dyn Debug) -> Result {
let mut names = names.split(' ');
let mut builder = builders::debug_struct_new(self, names.next().unwrap());
builder.field(names.next().unwrap(), value1);
builder.finish()
}

Expand All @@ -2514,15 +2510,14 @@ impl<'a> Formatter<'a> {
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_field2_finish<'b>(
&'b mut self,
name: &str,
name1: &str,
names: &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);
let mut names = names.split(' ');
let mut builder = builders::debug_struct_new(self, names.next().unwrap());
builder.field(names.next().unwrap(), value1);
builder.field(names.next().unwrap(), value2);
builder.finish()
}

Expand All @@ -2533,18 +2528,16 @@ impl<'a> Formatter<'a> {
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_field3_finish<'b>(
&'b mut self,
name: &str,
name1: &str,
names: &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);
let mut names = names.split(' ');
let mut builder = builders::debug_struct_new(self, names.next().unwrap());
builder.field(names.next().unwrap(), value1);
builder.field(names.next().unwrap(), value2);
builder.field(names.next().unwrap(), value3);
builder.finish()
}

Expand All @@ -2555,21 +2548,18 @@ impl<'a> Formatter<'a> {
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_field4_finish<'b>(
&'b mut self,
name: &str,
name1: &str,
names: &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);
let mut names = names.split(' ');
let mut builder = builders::debug_struct_new(self, names.next().unwrap());
builder.field(names.next().unwrap(), value1);
builder.field(names.next().unwrap(), value2);
builder.field(names.next().unwrap(), value3);
builder.field(names.next().unwrap(), value4);
builder.finish()
}

Expand All @@ -2580,40 +2570,37 @@ impl<'a> Formatter<'a> {
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_field5_finish<'b>(
&'b mut self,
name: &str,
name1: &str,
names: &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);
let mut names = names.split(' ');
let mut builder = builders::debug_struct_new(self, names.next().unwrap());
builder.field(names.next().unwrap(), value1);
builder.field(names.next().unwrap(), value2);
builder.field(names.next().unwrap(), value3);
builder.field(names.next().unwrap(), value4);
builder.field(names.next().unwrap(), value5);
builder.finish()
}

/// Shrinks `derive(Debug)` code, for faster compilation and smaller binaries.
/// For the cases not covered by `debug_struct_field[12345]_finish`.
/// Field names should be separated by space.
#[doc(hidden)]
#[unstable(feature = "fmt_helpers_for_derive", issue = "none")]
pub fn debug_struct_fields_finish<'b>(
&'b mut self,
name: &str,
names: &[&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) {
let mut names = names.split(' ');
let mut builder = builders::debug_struct_new(self, names.next().unwrap());
for value in values.into_iter() {
let name = names.next().unwrap();
builder.field(name, value);
}
builder.finish()
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/derives/debug/derive-debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ struct Tuple(isize, usize);
#[derive(Debug)]
struct Struct { x: isize, y: usize }

#[derive(Debug)]
struct BigStruct {
a: isize,
best: usize,
c: u64,
d: u32,
estimate: u8,
f: i8
}

#[derive(Debug)]
enum Enum {
Nullary,
Expand All @@ -29,6 +39,8 @@ pub fn main() {
t!(Unit, "Unit");
t!(Tuple(1, 2), "Tuple(1, 2)");
t!(Struct { x: 1, y: 2 }, "Struct { x: 1, y: 2 }");
t!(BigStruct { a: 1, best: 2, c: 3, d: 4, estimate: 5, f: 6 },
"BigStruct { a: 1, best: 2, c: 3, d: 4, estimate: 5, f: 6 }");
t!(Enum::Nullary, "Nullary");
t!(Enum::Variant(1, 2), "Variant(1, 2)");
t!(Enum::StructVariant { x: 1, y: 2 }, "StructVariant { x: 1, y: 2 }");
Expand Down
Loading
Loading