diff options
Diffstat (limited to 'compiler/rustc_builtin_macros/src/deriving')
14 files changed, 339 insertions, 158 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 240167146..0481a1189 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -17,6 +17,7 @@ pub fn expand_deriving_copy( span, path: path_std!(marker::Copy), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, additional_bounds: Vec::new(), supports_unions: true, methods: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index ef5a75f42..dfee2d3ce 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; pub fn expand_deriving_clone( cx: &mut ExtCtxt<'_>, @@ -73,6 +73,7 @@ pub fn expand_deriving_clone( span, path: path_std!(clone::Clone), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: bounds, supports_unions: true, methods: vec![MethodDef { @@ -99,7 +100,7 @@ fn cs_clone_simple( substr: &Substructure<'_>, is_union: bool, ) -> BlockOrExpr { - let mut stmts = Vec::new(); + let mut stmts = ThinVec::new(); let mut seen_type_names = FxHashSet::default(); let mut process_variant = |variant: &VariantData| { for field in variant.fields() { @@ -161,7 +162,7 @@ fn cs_clone( let all_fields; let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]); let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo| { - let args = vec![field.self_expr.clone()]; + let args = thin_vec![field.self_expr.clone()]; cx.expr_call_global(field.span, fn_path.clone(), args) }; @@ -199,7 +200,7 @@ fn cs_clone( let call = subcall(cx, field); cx.field_imm(field.span, ident, call) }) - .collect::<Vec<_>>(); + .collect::<ThinVec<_>>(); cx.expr_struct(trait_span, ctor_path, fields) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 3e994f037..af9719586 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; pub fn expand_deriving_eq( cx: &mut ExtCtxt<'_>, @@ -27,6 +27,7 @@ pub fn expand_deriving_eq( span, path: path_std!(cmp::Eq), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: true, methods: vec![MethodDef { @@ -55,7 +56,7 @@ fn cs_total_eq_assert( trait_span: Span, substr: &Substructure<'_>, ) -> BlockOrExpr { - let mut stmts = Vec::new(); + let mut stmts = ThinVec::new(); let mut seen_type_names = FxHashSet::default(); let mut process_variant = |variant: &ast::VariantData| { for field in variant.fields() { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index a926fca4e..cfd36f030 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -20,6 +20,7 @@ pub fn expand_deriving_ord( span, path: path_std!(cmp::Ord), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { @@ -63,14 +64,14 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Bl let [other_expr] = &field.other_selflike_exprs[..] else { cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); }; - let args = vec![field.self_expr.clone(), other_expr.clone()]; + let args = thin_vec![field.self_expr.clone(), other_expr.clone()]; cx.expr_call_global(field.span, cmp_path.clone(), args) } CsFold::Combine(span, expr1, expr2) => { let eq_arm = cx.arm(span, cx.pat_path(span, equal_path.clone()), expr1); let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) + cx.expr_match(span, expr2, thin_vec![eq_arm, neq_arm]) } CsFold::Fieldless => cx.expr_path(equal_path.clone()), }, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 9051fe0b2..bad47db0d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -29,16 +29,30 @@ pub fn expand_deriving_partial_eq( cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`"); }; - // We received `&T` arguments. Convert them to `T` by - // stripping `&` or adding `*`. This isn't necessary for - // type checking, but it results in much better error - // messages if something goes wrong. + // We received arguments of type `&T`. Convert them to type `T` by stripping + // any leading `&` or adding `*`. This isn't necessary for type checking, but + // it results in better error messages if something goes wrong. + // + // Note: for arguments that look like `&{ x }`, which occur with packed + // structs, this would cause expressions like `{ self.x } == { other.x }`, + // which isn't valid Rust syntax. This wouldn't break compilation because these + // AST nodes are constructed within the compiler. But it would mean that code + // printed by `-Zunpretty=expanded` (or `cargo expand`) would have invalid + // syntax, which would be suboptimal. So we wrap these in parens, giving + // `({ self.x }) == ({ other.x })`, which is valid syntax. let convert = |expr: &P<Expr>| { if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = &expr.kind { - inner.clone() + if let ExprKind::Block(..) = &inner.kind { + // `&{ x }` form: remove the `&`, add parens. + cx.expr_paren(field.span, inner.clone()) + } else { + // `&x` form: remove the `&`. + inner.clone() + } } else { + // No leading `&`: add a leading `*`. cx.expr_deref(field.span, expr.clone()) } }; @@ -84,6 +98,7 @@ pub fn expand_deriving_partial_eq( span, path: path_std!(cmp::PartialEq), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index c9dc89212..9f4624790 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -1,7 +1,7 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_std, pathvec_std}; -use rustc_ast::MetaItem; +use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -21,6 +21,27 @@ pub fn expand_deriving_partial_ord( let attrs = thin_vec![cx.attr_word(sym::inline, span)]; + // Order in which to perform matching + let tag_then_data = if let Annotatable::Item(item) = item + && let ItemKind::Enum(def, _) = &item.kind { + let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); + match dataful.iter().filter(|&&b| b).count() { + // No data, placing the tag check first makes codegen simpler + 0 => true, + 1..=2 => false, + _ => { + (0..dataful.len()-1).any(|i| { + if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) { + idx >= 2 + } else { + false + } + }) + } + } + } else { + true + }; let partial_cmp_def = MethodDef { name: sym::partial_cmp, generics: Bounds::empty(), @@ -30,7 +51,7 @@ pub fn expand_deriving_partial_ord( attributes: attrs, fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, combine_substructure: combine_substructure(Box::new(|cx, span, substr| { - cs_partial_cmp(cx, span, substr) + cs_partial_cmp(cx, span, substr, tag_then_data) })), }; @@ -38,6 +59,7 @@ pub fn expand_deriving_partial_ord( span, path: path_std!(cmp::PartialOrd), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: vec![], supports_unions: false, methods: vec![partial_cmp_def], @@ -47,7 +69,12 @@ pub fn expand_deriving_partial_ord( trait_def.expand(cx, mitem, item, push) } -pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr { +fn cs_partial_cmp( + cx: &mut ExtCtxt<'_>, + span: Span, + substr: &Substructure<'_>, + tag_then_data: bool, +) -> BlockOrExpr { let test_id = Ident::new(sym::cmp, span); let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]); @@ -71,15 +98,53 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_ let [other_expr] = &field.other_selflike_exprs[..] else { cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`"); }; - let args = vec![field.self_expr.clone(), other_expr.clone()]; + let args = thin_vec![field.self_expr.clone(), other_expr.clone()]; cx.expr_call_global(field.span, partial_cmp_path.clone(), args) } - CsFold::Combine(span, expr1, expr2) => { - let eq_arm = - cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1); - let neq_arm = - cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); - cx.expr_match(span, expr2, vec![eq_arm, neq_arm]) + CsFold::Combine(span, mut expr1, expr2) => { + // When the item is an enum, this expands to + // ``` + // match (expr2) { + // Some(Ordering::Equal) => expr1, + // cmp => cmp + // } + // ``` + // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match` + // against the enum variants. This means that we begin by comparing the enum tags, + // before either inspecting their contents (if they match), or returning + // the `cmp::Ordering` of comparing the enum tags. + // ``` + // match partial_cmp(self_tag, other_tag) { + // Some(Ordering::Equal) => match (self, other) { + // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), + // (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0), + // _ => Some(Ordering::Equal) + // } + // cmp => cmp + // } + // ``` + // If we have any certain enum layouts, flipping this results in better codegen + // ``` + // match (self, other) { + // (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0), + // _ => partial_cmp(self_tag, other_tag) + // } + // ``` + // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354 + + if !tag_then_data + && let ExprKind::Match(_, arms) = &mut expr1.kind + && let Some(last) = arms.last_mut() + && let PatKind::Wild = last.pat.kind { + last.body = expr2; + expr1 + } else { + let eq_arm = + cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1); + let neq_arm = + cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); + cx.expr_match(span, expr2, thin_vec![eq_arm, neq_arm]) + } } CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())), }, diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index e0f487e86..809f9838d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -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])) } diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 5f9519dad..3921533c8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -3,12 +3,12 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::pathvec_std; - use rustc_ast::ptr::P; use rustc_ast::{self as ast, Expr, MetaItem, Mutability}; 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_rustc_decodable( cx: &mut ExtCtxt<'_>, @@ -25,6 +25,7 @@ pub fn expand_deriving_rustc_decodable( span, path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { @@ -95,7 +96,7 @@ fn decodable_substructure( cx.expr_call_global( span, fn_read_struct_field_path.clone(), - vec![ + thin_vec![ blkdecoder.clone(), cx.expr_str(span, name), cx.expr_usize(span, field), @@ -111,7 +112,7 @@ fn decodable_substructure( cx.expr_call_global( trait_span, fn_read_struct_path, - vec![ + thin_vec![ decoder, cx.expr_str(trait_span, substr.type_ident.name), cx.expr_usize(trait_span, nfields), @@ -122,8 +123,8 @@ fn decodable_substructure( StaticEnum(_, fields) => { let variant = Ident::new(sym::i, trait_span); - let mut arms = Vec::with_capacity(fields.len() + 1); - let mut variants = Vec::with_capacity(fields.len()); + let mut arms = ThinVec::with_capacity(fields.len() + 1); + let mut variants = ThinVec::with_capacity(fields.len()); let fn_read_enum_variant_arg_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant_arg]); @@ -140,7 +141,7 @@ fn decodable_substructure( cx.expr_call_global( span, fn_read_enum_variant_arg_path.clone(), - vec![blkdecoder.clone(), idx, exprdecode.clone()], + thin_vec![blkdecoder.clone(), idx, exprdecode.clone()], ), ) }); @@ -161,7 +162,7 @@ fn decodable_substructure( let result = cx.expr_call_global( trait_span, fn_read_enum_variant_path, - vec![blkdecoder, variant_array_ref, lambda], + thin_vec![blkdecoder, variant_array_ref, lambda], ); let fn_read_enum_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]); @@ -169,7 +170,7 @@ fn decodable_substructure( cx.expr_call_global( trait_span, fn_read_enum_path, - vec![ + thin_vec![ decoder, cx.expr_str(trait_span, substr.type_ident.name), cx.lambda1(trait_span, result, blkarg), diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 182707472..4d753a2ed 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -8,7 +8,7 @@ use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use smallvec::SmallVec; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; pub fn expand_deriving_default( cx: &mut ExtCtxt<'_>, @@ -25,6 +25,7 @@ pub fn expand_deriving_default( span, path: Path::new(vec![kw::Default, sym::Default]), skip_path_as_bound: has_a_default_variant(item), + needs_copy_as_bound_if_packed: false, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { @@ -59,7 +60,7 @@ fn default_struct_substructure( ) -> BlockOrExpr { // Note that `kw::Default` is "default" and `sym::Default` is "Default"! let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]); - let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new()); + let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ThinVec::new()); let expr = match summary { Unnamed(_, false) => cx.expr_ident(trait_span, substr.type_ident), diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index 2afeed927..a3b11309d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -88,11 +88,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::pathvec_std; - use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability}; 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_rustc_encodable( cx: &mut ExtCtxt<'_>, @@ -109,6 +109,7 @@ pub fn expand_deriving_rustc_encodable( span, path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { @@ -168,19 +169,20 @@ fn encodable_substructure( Struct(_, fields) => { let fn_emit_struct_field_path = cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]); - let mut stmts = Vec::new(); + let mut stmts = ThinVec::new(); for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() { let name = match name { Some(id) => id.name, None => Symbol::intern(&format!("_field{}", i)), }; let self_ref = cx.expr_addr_of(span, self_expr.clone()); - let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); + let enc = + cx.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]); let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_call_global( span, fn_emit_struct_field_path.clone(), - vec![ + thin_vec![ blkencoder.clone(), cx.expr_str(span, name), cx.expr_usize(span, i), @@ -202,7 +204,7 @@ fn encodable_substructure( // unit structs have no fields and need to return Ok() let blk = if stmts.is_empty() { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![])); + let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new())); cx.lambda1(trait_span, ok, blkarg) } else { cx.lambda_stmts_1(trait_span, stmts, blkarg) @@ -214,7 +216,7 @@ fn encodable_substructure( let expr = cx.expr_call_global( trait_span, fn_emit_struct_path, - vec![ + thin_vec![ encoder, cx.expr_str(trait_span, substr.type_ident.name), cx.expr_usize(trait_span, fields.len()), @@ -235,19 +237,22 @@ fn encodable_substructure( let fn_emit_enum_variant_arg_path: Vec<_> = cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]); - let mut stmts = Vec::new(); + let mut stmts = ThinVec::new(); if !fields.is_empty() { let last = fields.len() - 1; for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() { let self_ref = cx.expr_addr_of(span, self_expr.clone()); - let enc = - cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); + let enc = cx.expr_call( + span, + fn_path.clone(), + thin_vec![self_ref, blkencoder.clone()], + ); let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_call_global( span, fn_emit_enum_variant_arg_path.clone(), - vec![blkencoder.clone(), cx.expr_usize(span, i), lambda], + thin_vec![blkencoder.clone(), cx.expr_usize(span, i), lambda], ); let call = if i != last { cx.expr_try(span, call) @@ -257,7 +262,7 @@ fn encodable_substructure( stmts.push(cx.stmt_expr(call)); } } else { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, vec![])); + let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new())); let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok))); stmts.push(cx.stmt_expr(ret_ok)); } @@ -271,7 +276,7 @@ fn encodable_substructure( let call = cx.expr_call_global( trait_span, fn_emit_enum_variant_path, - vec![ + thin_vec![ blkencoder, name, cx.expr_usize(trait_span, *idx), @@ -286,9 +291,9 @@ fn encodable_substructure( let expr = cx.expr_call_global( trait_span, fn_emit_enum_path, - vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk], + thin_vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk], ); - BlockOrExpr::new_mixed(vec![me], Some(expr)) + BlockOrExpr::new_mixed(thin_vec![me], Some(expr)) } _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"), diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 17b7ac0eb..1f819beeb 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -165,18 +165,19 @@ pub use SubstructureFields::*; use crate::deriving; use rustc_ast::ptr::P; use rustc_ast::{ - self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind, + self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, + Mutability, PatKind, TyKind, VariantData, }; -use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::cell::RefCell; use std::iter; use std::ops::Not; use std::vec; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; use ty::{Bounds, Path, Ref, Self_, Ty}; pub mod ty; @@ -191,6 +192,9 @@ pub struct TraitDef<'a> { /// Whether to skip adding the current trait as a bound to the type parameters of the type. pub skip_path_as_bound: bool, + /// Whether `Copy` is needed as an additional bound on type parameters in a packed struct. + pub needs_copy_as_bound_if_packed: bool, + /// Additional bounds required of any type parameters of the type, /// other than the current trait pub additional_bounds: Vec<Ty>, @@ -314,7 +318,7 @@ pub fn combine_substructure( } struct TypeParameter { - bound_generic_params: Vec<ast::GenericParam>, + bound_generic_params: ThinVec<ast::GenericParam>, ty: P<ast::Ty>, } @@ -324,18 +328,18 @@ struct TypeParameter { /// avoiding the insertion of any unnecessary blocks. /// /// The statements come before the expression. -pub struct BlockOrExpr(Vec<ast::Stmt>, Option<P<Expr>>); +pub struct BlockOrExpr(ThinVec<ast::Stmt>, Option<P<Expr>>); impl BlockOrExpr { - pub fn new_stmts(stmts: Vec<ast::Stmt>) -> BlockOrExpr { + pub fn new_stmts(stmts: ThinVec<ast::Stmt>) -> BlockOrExpr { BlockOrExpr(stmts, None) } pub fn new_expr(expr: P<Expr>) -> BlockOrExpr { - BlockOrExpr(vec![], Some(expr)) + BlockOrExpr(ThinVec::new(), Some(expr)) } - pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr { + pub fn new_mixed(stmts: ThinVec<ast::Stmt>, expr: Option<P<Expr>>) -> BlockOrExpr { BlockOrExpr(stmts, expr) } @@ -351,7 +355,7 @@ impl BlockOrExpr { fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P<Expr> { if self.0.is_empty() { match self.1 { - None => cx.expr_block(cx.block(span, vec![])), + None => cx.expr_block(cx.block(span, ThinVec::new())), Some(expr) => expr, } } else if self.0.len() == 1 @@ -381,7 +385,7 @@ fn find_type_parameters( struct Visitor<'a, 'b> { cx: &'a ExtCtxt<'b>, ty_param_names: &'a [Symbol], - bound_generic_params_stack: Vec<ast::GenericParam>, + bound_generic_params_stack: ThinVec<ast::GenericParam>, type_params: Vec<TypeParameter>, } @@ -418,7 +422,7 @@ fn find_type_parameters( let mut visitor = Visitor { cx, ty_param_names, - bound_generic_params_stack: Vec::new(), + bound_generic_params_stack: ThinVec::new(), type_params: Vec::new(), }; visit::Visitor::visit_ty(&mut visitor, ty); @@ -455,18 +459,6 @@ impl<'a> TraitDef<'a> { } false }); - let has_no_type_params = match &item.kind { - ast::ItemKind::Struct(_, generics) - | ast::ItemKind::Enum(_, generics) - | ast::ItemKind::Union(_, generics) => !generics - .params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })), - _ => unreachable!(), - }; - let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); - let copy_fields = - is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id); let newitem = match &item.kind { ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def( @@ -475,7 +467,7 @@ impl<'a> TraitDef<'a> { item.ident, generics, from_scratch, - copy_fields, + is_packed, ), ast::ItemKind::Enum(enum_def, generics) => { // We ignore `is_packed` here, because `repr(packed)` @@ -493,7 +485,7 @@ impl<'a> TraitDef<'a> { item.ident, generics, from_scratch, - copy_fields, + is_packed, ) } else { cx.span_err(mitem.span, "this trait cannot be derived for unions"); @@ -565,6 +557,7 @@ impl<'a> TraitDef<'a> { generics: &Generics, field_tys: Vec<P<ast::Ty>>, methods: Vec<P<ast::AssocItem>>, + is_packed: bool, ) -> P<ast::Item> { let trait_path = self.path.to_path(cx, self.span, type_ident, generics); @@ -601,26 +594,46 @@ impl<'a> TraitDef<'a> { let span = generics.span.with_ctxt(ctxt); // Create the generic parameters - let params: Vec<_> = generics + let params: ThinVec<_> = generics .params .iter() .map(|param| match ¶m.kind { GenericParamKind::Lifetime { .. } => param.clone(), GenericParamKind::Type { .. } => { - // I don't think this can be moved out of the loop, since - // a GenericBound requires an ast id - let bounds: Vec<_> = - // extra restrictions on the generics parameters to the - // type being derived upon - self.additional_bounds.iter().map(|p| { - cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)) - }).chain( - // require the current trait - self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone())) - ).chain( - // also add in any bounds from the declaration - param.bounds.iter().cloned() - ).collect(); + // Extra restrictions on the generics parameters to the + // type being derived upon. + let bounds: Vec<_> = self + .additional_bounds + .iter() + .map(|p| { + cx.trait_bound( + p.to_path(cx, self.span, type_ident, generics), + self.is_const, + ) + }) + .chain( + // Add a bound for the current trait. + self.skip_path_as_bound + .not() + .then(|| cx.trait_bound(trait_path.clone(), self.is_const)), + ) + .chain({ + // Add a `Copy` bound if required. + if is_packed && self.needs_copy_as_bound_if_packed { + let p = deriving::path_std!(marker::Copy); + Some(cx.trait_bound( + p.to_path(cx, self.span, type_ident, generics), + self.is_const, + )) + } else { + None + } + }) + .chain( + // Also add in any bounds from the declaration. + param.bounds.iter().cloned(), + ) + .collect(); cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) } @@ -689,11 +702,25 @@ impl<'a> TraitDef<'a> { let mut bounds: Vec<_> = self .additional_bounds .iter() - .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))) + .map(|p| { + cx.trait_bound( + p.to_path(cx, self.span, type_ident, generics), + self.is_const, + ) + }) .collect(); - // require the current trait - bounds.push(cx.trait_bound(trait_path.clone())); + // Require the current trait. + bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); + + // Add a `Copy` bound if required. + if is_packed && self.needs_copy_as_bound_if_packed { + let p = deriving::path_std!(marker::Copy); + bounds.push(cx.trait_bound( + p.to_path(cx, self.span, type_ident, generics), + self.is_const, + )); + } let predicate = ast::WhereBoundPredicate { span: self.span, @@ -734,8 +761,7 @@ impl<'a> TraitDef<'a> { let path = cx.path_all(self.span, false, vec![type_ident], self_params); let self_type = cx.ty_path(path); - let attr = cx.attr_word(sym::automatically_derived, self.span); - let attrs = thin_vec![attr]; + let attrs = thin_vec![cx.attr_word(sym::automatically_derived, self.span),]; let opt_trait_ref = Some(trait_ref); cx.item( @@ -762,7 +788,7 @@ impl<'a> TraitDef<'a> { type_ident: Ident, generics: &Generics, from_scratch: bool, - copy_fields: bool, + is_packed: bool, ) -> P<ast::Item> { let field_tys: Vec<P<ast::Ty>> = struct_def.fields().iter().map(|field| field.ty.clone()).collect(); @@ -790,7 +816,7 @@ impl<'a> TraitDef<'a> { type_ident, &selflike_args, &nonselflike_args, - copy_fields, + is_packed, ) }; @@ -806,7 +832,7 @@ impl<'a> TraitDef<'a> { }) .collect(); - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) + self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) } fn expand_enum_def( @@ -861,7 +887,8 @@ impl<'a> TraitDef<'a> { }) .collect(); - self.create_derived_impl(cx, type_ident, generics, field_tys, methods) + let is_packed = false; // enums are never packed + self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed) } } @@ -908,19 +935,17 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'_>, type_ident: Ident, generics: &Generics, - ) -> (Option<ast::ExplicitSelf>, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) { - let mut selflike_args = Vec::new(); + ) -> (Option<ast::ExplicitSelf>, ThinVec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) { + let mut selflike_args = ThinVec::new(); let mut nonselflike_args = Vec::new(); let mut nonself_arg_tys = Vec::new(); let span = trait_.span; - let explicit_self = if self.explicit_self { + let explicit_self = self.explicit_self.then(|| { let (self_expr, explicit_self) = ty::get_explicit_self(cx, span); selflike_args.push(self_expr); - Some(explicit_self) - } else { - None - }; + explicit_self + }); for (ty, name) in self.nonself_args.iter() { let ast_ty = ty.to_ty(cx, span, type_ident, generics); @@ -1011,8 +1036,8 @@ impl<'a> MethodDef<'a> { /// ``` /// But if the struct is `repr(packed)`, we can't use something like /// `&self.x` because that might cause an unaligned ref. So for any trait - /// method that takes a reference, if the struct impls `Copy` then we use a - /// local block to force a copy: + /// method that takes a reference, we use a local block to force a copy. + /// This requires that the field impl `Copy`. /// ``` /// # struct A { x: u8, y: u8 } /// impl PartialEq for A { @@ -1027,10 +1052,6 @@ impl<'a> MethodDef<'a> { /// ::core::hash::Hash::hash(&{ self.y }, state) /// } /// } - /// ``` - /// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This - /// only works if the fields match the alignment required by the - /// `packed(N)` attribute. (We'll get errors later on if not.) fn expand_struct_method_body<'b>( &self, cx: &mut ExtCtxt<'_>, @@ -1039,12 +1060,12 @@ impl<'a> MethodDef<'a> { type_ident: Ident, selflike_args: &[P<Expr>], nonselflike_args: &[P<Expr>], - copy_fields: bool, + is_packed: bool, ) -> BlockOrExpr { assert!(selflike_args.len() == 1 || selflike_args.len() == 2); let selflike_fields = - trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields); + trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed); self.call_substructure_method( cx, trait_, @@ -1112,7 +1133,7 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'b>, enum_def: &'b EnumDef, type_ident: Ident, - selflike_args: Vec<P<Expr>>, + selflike_args: ThinVec<P<Expr>>, nonselflike_args: &[P<Expr>], ) -> BlockOrExpr { let span = trait_.span; @@ -1125,7 +1146,7 @@ impl<'a> MethodDef<'a> { // There is no sensible code to be generated for *any* deriving on a // zero-variant enum. So we just generate a failing expression. if variants.is_empty() { - return BlockOrExpr(vec![], Some(deriving::call_unreachable(cx, span))); + return BlockOrExpr(ThinVec::new(), Some(deriving::call_unreachable(cx, span))); } let prefixes = iter::once("__self".to_string()) @@ -1161,13 +1182,13 @@ impl<'a> MethodDef<'a> { let other_selflike_exprs = tag_exprs; let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs }; - let tag_let_stmts: Vec<_> = iter::zip(&tag_idents, &selflike_args) + let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args) .map(|(&ident, selflike_arg)| { let variant_value = deriving::call_intrinsic( cx, span, sym::discriminant_value, - vec![selflike_arg.clone()], + thin_vec![selflike_arg.clone()], ); cx.stmt_let(span, false, ident, variant_value) }) @@ -1226,7 +1247,7 @@ impl<'a> MethodDef<'a> { // (Variant2, Variant2, ...) => Body2 // ... // where each tuple has length = selflike_args.len() - let mut match_arms: Vec<ast::Arm> = variants + let mut match_arms: ThinVec<ast::Arm> = variants .iter() .enumerate() .filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty())) @@ -1239,7 +1260,7 @@ impl<'a> MethodDef<'a> { let sp = variant.span.with_ctxt(trait_.span.ctxt()); let variant_path = cx.path(sp, vec![type_ident, variant.ident]); let by_ref = ByRef::No; // because enums can't be repr(packed) - let mut subpats: Vec<_> = trait_.create_struct_patterns( + let mut subpats = trait_.create_struct_patterns( cx, variant_path, &variant.data, @@ -1315,7 +1336,7 @@ impl<'a> MethodDef<'a> { // ... // _ => ::core::intrinsics::unreachable() // } - let get_match_expr = |mut selflike_args: Vec<P<Expr>>| { + let get_match_expr = |mut selflike_args: ThinVec<P<Expr>>| { let match_arg = if selflike_args.len() == 1 { selflike_args.pop().unwrap() } else { @@ -1341,7 +1362,7 @@ impl<'a> MethodDef<'a> { tag_let_stmts.append(&mut tag_check_plus_match.0); BlockOrExpr(tag_let_stmts, tag_check_plus_match.1) } else { - BlockOrExpr(vec![], Some(get_match_expr(selflike_args))) + BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args))) } } @@ -1406,7 +1427,7 @@ impl<'a> TraitDef<'a> { struct_def: &'a VariantData, prefixes: &[String], by_ref: ByRef, - ) -> Vec<P<ast::Pat>> { + ) -> ThinVec<P<ast::Pat>> { prefixes .iter() .map(|prefix| { @@ -1514,7 +1535,7 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt<'_>, selflike_args: &[P<Expr>], struct_def: &'a VariantData, - copy_fields: bool, + is_packed: bool, ) -> Vec<FieldInfo> { self.create_fields(struct_def, |i, struct_field, sp| { selflike_args @@ -1533,10 +1554,54 @@ impl<'a> TraitDef<'a> { }), ), ); - if copy_fields { - field_expr = cx.expr_block( - cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]), - ); + if is_packed { + // In general, fields in packed structs are copied via a + // block, e.g. `&{self.0}`. The two exceptions are `[u8]` + // and `str` fields, which cannot be copied and also never + // cause unaligned references. These exceptions are allowed + // to handle the `FlexZeroSlice` type in the `zerovec` + // crate within `icu4x-0.9.0`. + // + // Once use of `icu4x-0.9.0` has dropped sufficiently, this + // exception should be removed. + let is_simple_path = |ty: &P<ast::Ty>, sym| { + if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind && + let [seg] = segments.as_slice() && + seg.ident.name == sym && seg.args.is_none() + { + true + } else { + false + } + }; + + let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind && + is_simple_path(ty, sym::u8) + { + Some("byte") + } else if is_simple_path(&struct_field.ty, sym::str) { + Some("string") + } else { + None + }; + + if let Some(ty) = exception { + cx.sess.parse_sess.buffer_lint_with_diagnostic( + BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + sp, + ast::CRATE_NODE_ID, + &format!( + "{} slice in a packed struct that derives a built-in trait", + ty + ), + rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive + ); + } else { + // Wrap the expression in `{...}`, causing a copy. + field_expr = cx.expr_block( + cx.block(struct_field.span, thin_vec![cx.stmt_expr(field_expr)]), + ); + } } cx.expr_addr_of(sp, field_expr) }) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index c6f5f5d08..26f91b714 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -9,6 +9,7 @@ use rustc_expand::base::ExtCtxt; use rustc_span::source_map::{respan, DUMMY_SP}; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; +use thin_vec::ThinVec; /// A path, e.g., `::std::option::Option::<i32>` (global). Has support /// for type parameters. @@ -102,7 +103,7 @@ impl Ty { Path(p) => p.to_ty(cx, span, self_ty, self_generics), Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)), Unit => { - let ty = ast::TyKind::Tup(vec![]); + let ty = ast::TyKind::Tup(ThinVec::new()); cx.ty(span, ty) } } @@ -154,7 +155,7 @@ fn mk_ty_param( .iter() .map(|b| { let path = b.to_path(cx, span, self_ident, self_generics); - cx.trait_bound(path) + cx.trait_bound(path, false) }) .collect(); cx.typaram(span, Ident::new(name, span), bounds, None) @@ -185,7 +186,11 @@ impl Bounds { Generics { params, - where_clause: ast::WhereClause { has_where_token: false, predicates: Vec::new(), span }, + where_clause: ast::WhereClause { + has_where_token: false, + predicates: ThinVec::new(), + span, + }, span, } } diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index f8570d8f8..4eee573db 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -1,11 +1,11 @@ use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::{path_std, pathvec_std}; - use rustc_ast::{AttrVec, MetaItem, Mutability}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; +use thin_vec::thin_vec; pub fn expand_deriving_hash( cx: &mut ExtCtxt<'_>, @@ -24,6 +24,7 @@ pub fn expand_deriving_hash( span, path, skip_path_as_bound: false, + needs_copy_as_bound_if_packed: true, additional_bounds: Vec::new(), supports_unions: false, methods: vec![MethodDef { @@ -59,7 +60,7 @@ fn hash_substructure( cx.expr_path(cx.path_global(span, strs)) }; - let expr = cx.expr_call(span, hash_path, vec![expr, state_expr.clone()]); + let expr = cx.expr_call(span, hash_path, thin_vec![expr, state_expr.clone()]); cx.stmt_expr(expr) }; @@ -71,7 +72,7 @@ fn hash_substructure( } EnumTag(tag_field, match_expr) => { assert!(tag_field.other_selflike_exprs.is_empty()); - let stmts = vec![call_hash(tag_field.span, tag_field.self_expr.clone())]; + let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())]; (stmts, match_expr.clone()) } _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"), diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index de657e4e6..d34336e76 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -6,6 +6,7 @@ use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; +use thin_vec::{thin_vec, ThinVec}; macro path_local($x:ident) { generic::ty::Path::new_local(sym::$x) @@ -92,7 +93,7 @@ fn call_intrinsic( cx: &ExtCtxt<'_>, span: Span, intrinsic: Symbol, - args: Vec<P<ast::Expr>>, + args: ThinVec<P<ast::Expr>>, ) -> P<ast::Expr> { let span = cx.with_def_site_ctxt(span); let path = cx.std_path(&[sym::intrinsics, intrinsic]); @@ -103,10 +104,10 @@ fn call_intrinsic( fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> { let span = cx.with_def_site_ctxt(span); let path = cx.std_path(&[sym::intrinsics, sym::unreachable]); - let call = cx.expr_call_global(span, path, vec![]); + let call = cx.expr_call_global(span, path, ThinVec::new()); cx.expr_block(P(ast::Block { - stmts: vec![cx.stmt_expr(call)], + stmts: thin_vec![cx.stmt_expr(call)], id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), span, @@ -202,7 +203,7 @@ fn inject_impl_of_structural_trait( generics, of_trait: Some(trait_ref), self_ty: self_type, - items: Vec::new(), + items: ThinVec::new(), })), ); @@ -211,7 +212,7 @@ fn inject_impl_of_structural_trait( fn assert_ty_bounds( cx: &mut ExtCtxt<'_>, - stmts: &mut Vec<ast::Stmt>, + stmts: &mut ThinVec<ast::Stmt>, ty: P<ast::Ty>, span: Span, assert_path: &[Symbol], |