]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_builtin_macros/src/deriving/debug.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_builtin_macros / src / deriving / debug.rs
index e0f487e864898d72d530efd0d1b1b0815d01894d..809f9838d20becd0965c226095302737ce40d2b2 100644 (file)
@@ -7,6 +7,7 @@ use rustc_ast::{self as ast, MetaItem};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
+use thin_vec::{thin_vec, ThinVec};
 
 pub fn expand_deriving_debug(
     cx: &mut ExtCtxt<'_>,
@@ -23,6 +24,7 @@ pub fn expand_deriving_debug(
         span,
         path: path_std!(fmt::Debug),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: Vec::new(),
         supports_unions: false,
         methods: vec![MethodDef {
@@ -75,10 +77,25 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     // The number of fields that can be handled without an array.
     const CUTOFF: usize = 5;
 
+    fn expr_for_field(
+        cx: &ExtCtxt<'_>,
+        field: &FieldInfo,
+        index: usize,
+        len: usize,
+    ) -> ast::ptr::P<ast::Expr> {
+        if index < len - 1 {
+            field.self_expr.clone()
+        } else {
+            // Unsized types need an extra indirection, but only the last field
+            // may be unsized.
+            cx.expr_addr_of(field.span, field.self_expr.clone())
+        }
+    }
+
     if fields.is_empty() {
         // Special case for no fields.
         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 expr = cx.expr_call_global(span, fn_path_write_str, thin_vec![fmt, name]);
         BlockOrExpr::new_expr(expr)
     } else if fields.len() <= CUTOFF {
         // Few enough fields that we can use a specific-length method.
@@ -89,7 +106,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         };
         let fn_path_debug = cx.std_path(&[sym::fmt, sym::Formatter, Symbol::intern(&debug)]);
 
-        let mut args = Vec::with_capacity(2 + fields.len() * args_per_field);
+        let mut args = ThinVec::with_capacity(2 + fields.len() * args_per_field);
         args.extend([fmt, name]);
         for i in 0..fields.len() {
             let field = &fields[i];
@@ -97,47 +114,48 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
                 let name = cx.expr_str(field.span, field.name.unwrap().name);
                 args.push(name);
             }
-            // Use an extra indirection to make sure this works for unsized types.
-            let field = cx.expr_addr_of(field.span, field.self_expr.clone());
+
+            let field = expr_for_field(cx, field, i, fields.len());
             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 = Vec::with_capacity(fields.len());
-        let mut value_exprs = Vec::with_capacity(fields.len());
+        let mut name_exprs = ThinVec::with_capacity(fields.len());
+        let mut value_exprs = ThinVec::with_capacity(fields.len());
 
-        for field in fields {
+        for i in 0..fields.len() {
+            let field = &fields[i];
             if is_struct {
                 name_exprs.push(cx.expr_str(field.span, field.name.unwrap().name));
             }
 
-            // Use an extra indirection to make sure this works for unsized types.
-            let field = cx.expr_addr_of(field.span, field.self_expr.clone());
+            let field = expr_for_field(cx, field, i, fields.len());
             value_exprs.push(field);
         }
 
         // `let names: &'static _ = &["field1", "field2"];`
-        let names_let = if is_struct {
+        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);
-            Some(cx.stmt_let_ty(
+            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),
+            ast::TyKind::TraitObject(
+                vec![cx.trait_bound(path_debug, false)],
+                ast::TraitObjectSyntax::Dyn,
+            ),
         );
         let ty_slice = cx.ty(
             span,
@@ -160,7 +178,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         };
         let fn_path_debug_internal = cx.std_path(&[sym::fmt, sym::Formatter, sym_debug]);
 
-        let mut args = Vec::with_capacity(4);
+        let mut args = ThinVec::with_capacity(4);
         args.push(fmt);
         args.push(name);
         if is_struct {
@@ -169,7 +187,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         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);
+        let mut stmts = ThinVec::with_capacity(2);
         if is_struct {
             stmts.push(names_let.unwrap());
         }
@@ -206,18 +224,18 @@ fn show_fieldless_enum(
             let pat = match &v.data {
                 ast::VariantData::Tuple(fields, _) => {
                     debug_assert!(fields.is_empty());
-                    cx.pat_tuple_struct(span, variant_path, vec![])
+                    cx.pat_tuple_struct(span, variant_path, ThinVec::new())
                 }
                 ast::VariantData::Struct(fields, _) => {
                     debug_assert!(fields.is_empty());
-                    cx.pat_struct(span, variant_path, vec![])
+                    cx.pat_struct(span, variant_path, ThinVec::new())
                 }
                 ast::VariantData::Unit(_) => cx.pat_path(span, variant_path),
             };
             cx.arm(span, pat, cx.expr_str(span, v.ident.name))
         })
-        .collect::<Vec<_>>();
+        .collect::<ThinVec<_>>();
     let name = cx.expr_match(span, cx.expr_self(span), arms);
     let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
-    BlockOrExpr::new_expr(cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]))
+    BlockOrExpr::new_expr(cx.expr_call_global(span, fn_path_write_str, thin_vec![fmt, name]))
 }