diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 0be5f36de980b..f24f3f2df007d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -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. @@ -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. @@ -125,14 +125,25 @@ 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); } @@ -140,29 +151,28 @@ fn show_substructure( 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];` @@ -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 @@ -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)) } } diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index a9af7e00b1d5f..51ba40e50ae08 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -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))] @@ -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() } @@ -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() } @@ -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() } @@ -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() } @@ -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() diff --git a/tests/ui/derives/debug/derive-debug.rs b/tests/ui/derives/debug/derive-debug.rs index e4e377dd90d13..63ccf8457e8c5 100644 --- a/tests/ui/derives/debug/derive-debug.rs +++ b/tests/ui/derives/debug/derive-debug.rs @@ -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, @@ -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 }"); diff --git a/tests/ui/derives/deriving-all-codegen.stdout b/tests/ui/derives/deriving-all-codegen.stdout index 94603a91547c1..3d95302659c4d 100644 --- a/tests/ui/derives/deriving-all-codegen.stdout +++ b/tests/ui/derives/deriving-all-codegen.stdout @@ -101,8 +101,8 @@ impl ::core::marker::Copy for Point { } impl ::core::fmt::Debug for Point { #[inline] fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field2_finish(f, "Point", "x", - &self.x, "y", &&self.y) + ::core::fmt::Formatter::debug_struct_field2_finish(f, "Point x y", + &self.x, &&self.y) } } #[automatically_derived] @@ -185,8 +185,8 @@ impl ::core::marker::Copy for PackedPoint { } impl ::core::fmt::Debug for PackedPoint { #[inline] fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field2_finish(f, "PackedPoint", - "x", &{ self.x }, "y", &&{ self.y }) + ::core::fmt::Formatter::debug_struct_field2_finish(f, + "PackedPoint x y", &{ self.x }, &&{ self.y }) } } #[automatically_derived] @@ -338,8 +338,8 @@ impl ::core::marker::Copy for SingleField { } impl ::core::fmt::Debug for SingleField { #[inline] fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field1_finish(f, "SingleField", - "foo", &&self.foo) + ::core::fmt::Formatter::debug_struct_field1_finish(f, + "SingleField foo", &&self.foo) } } #[automatically_derived] @@ -422,13 +422,11 @@ impl ::core::marker::Copy for Big { } impl ::core::fmt::Debug for Big { #[inline] fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - let names: &'static _ = - &["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8"]; + let names: &'static _ = "Big b1 b2 b3 b4 b5 b6 b7 b8"; let values: &[&dyn ::core::fmt::Debug] = &[&self.b1, &self.b2, &self.b3, &self.b4, &self.b5, &self.b6, &self.b7, &&self.b8]; - ::core::fmt::Formatter::debug_struct_fields_finish(f, "Big", names, - values) + ::core::fmt::Formatter::debug_struct_fields_finish(f, names, values) } } #[automatically_derived] @@ -751,8 +749,8 @@ impl ::core::fmt::Debug for Generic where T::A: ::core::fmt::Debug { #[inline] fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - ::core::fmt::Formatter::debug_struct_field3_finish(f, "Generic", "t", - &self.t, "ta", &self.ta, "u", &&self.u) + ::core::fmt::Formatter::debug_struct_field3_finish(f, + "Generic t ta u", &self.t, &self.ta, &&self.u) } } #[automatically_derived] @@ -1040,7 +1038,7 @@ impl ::core::fmt::Debug for Enum1 { match self { Self::Single { x: __self_0 } => ::core::fmt::Formatter::debug_struct_field1_finish(f, - "Single", "x", &__self_0), + "Single x", &__self_0), } } } @@ -1306,8 +1304,8 @@ impl ::core::fmt::Debug for Mixed { ::core::fmt::Formatter::debug_tuple_field1_finish(f, "R", &__self_0), Self::S { d1: __self_0, d2: __self_1 } => - ::core::fmt::Formatter::debug_struct_field2_finish(f, "S", - "d1", __self_0, "d2", &__self_1), + ::core::fmt::Formatter::debug_struct_field2_finish(f, + "S d1 d2", __self_0, &__self_1), } } } diff --git a/tests/ui/stats/macro-stats.stderr b/tests/ui/stats/macro-stats.stderr index e4f5a95ac7fad..4806b3ad82c90 100644 --- a/tests/ui/stats/macro-stats.stderr +++ b/tests/ui/stats/macro-stats.stderr @@ -8,8 +8,8 @@ macro-stats q! 1 26 26.0 macro-stats #[derive(Ord)] 1 14 14.0 504 504.0 macro-stats #[derive(Default)] 2 14 7.0 405 202.5 macro-stats #[derive(Eq)] 1 10 10.0 311 311.0 -macro-stats #[derive(Debug)] 1 7 7.0 276 276.0 macro-stats #[derive(PartialEq)] 1 7 7.0 267 267.0 +macro-stats #[derive(Debug)] 1 7 7.0 267 267.0 macro-stats #[derive(PartialOrd)] 1 7 7.0 255 255.0 macro-stats #[derive(Copy)] 1 1 1.0 60 60.0 macro-stats p! 1 3 3.0 32 32.0