diff options
Diffstat (limited to '')
30 files changed, 505 insertions, 604 deletions
diff --git a/compiler/rustc_builtin_macros/src/format/ast.rs b/compiler/rustc_ast/src/format.rs index 01dbffa21..d021bea5e 100644 --- a/compiler/rustc_builtin_macros/src/format/ast.rs +++ b/compiler/rustc_ast/src/format.rs @@ -1,5 +1,5 @@ -use rustc_ast::ptr::P; -use rustc_ast::Expr; +use crate::ptr::P; +use crate::Expr; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -39,7 +39,7 @@ use rustc_span::Span; /// Basically the "AST" for a complete `format_args!()`. /// /// E.g., `format_args!("hello {name}");`. -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct FormatArgs { pub span: Span, pub template: Vec<FormatArgsPiece>, @@ -49,7 +49,7 @@ pub struct FormatArgs { /// A piece of a format template string. /// /// E.g. "hello" or "{name}". -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub enum FormatArgsPiece { Literal(Symbol), Placeholder(FormatPlaceholder), @@ -59,7 +59,7 @@ pub enum FormatArgsPiece { /// /// E.g. `1, 2, name="ferris", n=3`, /// but also implicit captured arguments like `x` in `format_args!("{x}")`. -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct FormatArguments { arguments: Vec<FormatArgument>, num_unnamed_args: usize, @@ -67,6 +67,12 @@ pub struct FormatArguments { names: FxHashMap<Symbol, usize>, } +// FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930. +#[cfg(parallel_compiler)] +unsafe impl Sync for FormatArguments {} +#[cfg(parallel_compiler)] +unsafe impl Send for FormatArguments {} + impl FormatArguments { pub fn new() -> Self { Self { @@ -121,18 +127,22 @@ impl FormatArguments { &self.arguments[..self.num_explicit_args] } - pub fn into_vec(self) -> Vec<FormatArgument> { - self.arguments + pub fn all_args(&self) -> &[FormatArgument] { + &self.arguments[..] + } + + pub fn all_args_mut(&mut self) -> &mut [FormatArgument] { + &mut self.arguments[..] } } -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct FormatArgument { pub kind: FormatArgumentKind, pub expr: P<Expr>, } -#[derive(Clone, Debug)] +#[derive(Clone, Encodable, Decodable, Debug)] pub enum FormatArgumentKind { /// `format_args(…, arg)` Normal, @@ -152,7 +162,7 @@ impl FormatArgumentKind { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub struct FormatPlaceholder { /// Index into [`FormatArgs::arguments`]. pub argument: FormatArgPosition, @@ -164,7 +174,7 @@ pub struct FormatPlaceholder { pub format_options: FormatOptions, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub struct FormatArgPosition { /// Which argument this position refers to (Ok), /// or would've referred to if it existed (Err). @@ -175,7 +185,7 @@ pub struct FormatArgPosition { pub span: Option<Span>, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatArgPositionKind { /// `{}` or `{:.*}` Implicit, @@ -185,7 +195,7 @@ pub enum FormatArgPositionKind { Named, } -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)] pub enum FormatTrait { /// `{}` Display, @@ -207,7 +217,7 @@ pub enum FormatTrait { UpperHex, } -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)] pub struct FormatOptions { /// The width. E.g. `{:5}` or `{:width$}`. pub width: Option<FormatCount>, @@ -217,11 +227,33 @@ pub struct FormatOptions { pub alignment: Option<FormatAlignment>, /// The fill character. E.g. the `.` in `{:.>10}`. pub fill: Option<char>, - /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags. - pub flags: u32, + /// The `+` or `-` flag. + pub sign: Option<FormatSign>, + /// The `#` flag. + pub alternate: bool, + /// The `0` flag. E.g. the `0` in `{:02x}`. + pub zero_pad: bool, + /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`. + pub debug_hex: Option<FormatDebugHex>, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatSign { + /// The `+` flag. + Plus, + /// The `-` flag. + Minus, +} + +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] +pub enum FormatDebugHex { + /// The `x` flag in `{:x?}`. + Lower, + /// The `X` flag in `{:X?}`. + Upper, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatAlignment { /// `{:<}` Left, @@ -231,7 +263,7 @@ pub enum FormatAlignment { Center, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatCount { /// `{:5}` or `{:.5}` Literal(usize), diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 467fa932a..336e14ef9 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -23,5 +23,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec = "0.2.9" +thin-vec = "0.2.12" tracing = "0.1" diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_builtin_macros/locales/en-US.ftl index 4d088e27b..4d088e27b 100644 --- a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl +++ b/compiler/rustc_builtin_macros/locales/en-US.ftl diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index dcf500ddb..ac6697232 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -6,7 +6,7 @@ use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe}; 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( ecx: &mut ExtCtxt<'_>, @@ -39,10 +39,10 @@ pub fn expand( let span = ecx.with_def_site_ctxt(item.span); // Generate item statements for the allocator methods. - let stmts = vec![generate_handler(ecx, item.ident, span, sig_span)]; + let stmts = thin_vec![generate_handler(ecx, item.ident, span, sig_span)]; // Generate anonymous constant serving as container for the allocator methods. - let const_ty = ecx.ty(sig_span, TyKind::Tup(Vec::new())); + let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new())); let const_body = ecx.expr_block(ecx.block(span, stmts)); let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); let const_item = if is_stmt { @@ -67,13 +67,16 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]); let layout_new = cx.expr_path(cx.path(span, layout_new)); - let layout = - cx.expr_call(span, layout_new, vec![cx.expr_ident(span, size), cx.expr_ident(span, align)]); + let layout = cx.expr_call( + span, + layout_new, + thin_vec![cx.expr_ident(span, size), cx.expr_ident(span, align)], + ); - let call = cx.expr_call_ident(sig_span, handler, vec![layout]); + let call = cx.expr_call_ident(sig_span, handler, thin_vec![layout]); let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never)); - let params = vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)]; + let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)]; let decl = cx.fn_decl(params, never); let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() }; let sig = FnSig { decl, header, span: span }; diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 925392b50..3fdbc9715 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -152,7 +152,7 @@ pub fn parse_asm_args<'a>( ast::InlineAsmOperand::InOut { reg, expr, late: true } } } else if p.eat_keyword(kw::Const) { - let anon_const = p.parse_anon_const_expr()?; + let anon_const = p.parse_expr_anon_const()?; ast::InlineAsmOperand::Const { anon_const } } else if p.eat_keyword(sym::sym) { let expr = p.parse_expr()?; diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 8555c3593..75af5e2b1 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -11,6 +11,7 @@ use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_parse::parser::Parser; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use thin_vec::thin_vec; pub fn expand_assert<'cx>( cx: &'cx mut ExtCtxt<'_>, @@ -79,7 +80,7 @@ pub fn expand_assert<'cx>( let then = cx.expr_call_global( call_site_span, cx.std_path(&[sym::panicking, sym::panic]), - vec![cx.expr_str( + thin_vec![cx.expr_str( DUMMY_SP, Symbol::intern(&format!( "assertion failed: {}", diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 93b07801e..b0b4dda16 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -12,7 +12,7 @@ use rustc_span::{ symbol::{sym, Ident, Symbol}, Span, }; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; pub(super) struct Context<'cx, 'a> { // An optimization. @@ -83,12 +83,12 @@ impl<'cx, 'a> Context<'cx, 'a> { let Self { best_case_captures, capture_decls, cx, local_bind_decls, span, .. } = self; - let mut assert_then_stmts = Vec::with_capacity(2); + let mut assert_then_stmts = ThinVec::with_capacity(2); assert_then_stmts.extend(best_case_captures); assert_then_stmts.push(self.cx.stmt_expr(panic)); let assert_then = self.cx.block(span, assert_then_stmts); - let mut stmts = Vec::with_capacity(4); + let mut stmts = ThinVec::with_capacity(4); stmts.push(initial_imports); stmts.extend(capture_decls.into_iter().map(|c| c.decl)); stmts.extend(local_bind_decls); @@ -120,7 +120,7 @@ impl<'cx, 'a> Context<'cx, 'a> { thin_vec![self.cx.attr_nested_word(sym::allow, sym::unused_imports, self.span)], ItemKind::Use(UseTree { prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])), - kind: UseTreeKind::Nested(vec![ + kind: UseTreeKind::Nested(thin_vec![ nested_tree(self, sym::TryCaptureGeneric), nested_tree(self, sym::TryCapturePrintable), ]), @@ -136,7 +136,7 @@ impl<'cx, 'a> Context<'cx, 'a> { self.cx.expr_call( self.span, self.cx.expr_path(self.cx.path(self.span, unlikely_path)), - vec![self.cx.expr(self.span, ExprKind::Unary(UnOp::Not, cond_expr))], + thin_vec![self.cx.expr(self.span, ExprKind::Unary(UnOp::Not, cond_expr))], ) } @@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Continue(_) | ExprKind::Err | ExprKind::Field(_, _) + | ExprKind::FormatArgs(_) | ExprKind::ForLoop(_, _, _, _) | ExprKind::If(_, _, _) | ExprKind::IncludedBytes(..) @@ -338,7 +339,7 @@ impl<'cx, 'a> Context<'cx, 'a> { let init = self.cx.expr_call( self.span, self.cx.expr_path(self.cx.path(self.span, init_std_path)), - vec![], + ThinVec::new(), ); let capture = Capture { decl: self.cx.stmt_let(self.span, true, ident, init), ident }; self.capture_decls.push(capture); @@ -365,7 +366,7 @@ impl<'cx, 'a> Context<'cx, 'a> { self.cx.expr_path( self.cx.path(self.span, self.cx.std_path(&[sym::asserting, sym::Wrapper])), ), - vec![self.cx.expr_path(Path::from_ident(local_bind))], + thin_vec![self.cx.expr_path(Path::from_ident(local_bind))], ); let try_capture_call = self .cx @@ -377,7 +378,7 @@ impl<'cx, 'a> Context<'cx, 'a> { ident: Ident::new(sym::try_capture, self.span), }, expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)), - vec![expr_addr_of_mut( + thin_vec![expr_addr_of_mut( self.cx, self.span, self.cx.expr_path(Path::from_ident(capture)), @@ -388,7 +389,7 @@ impl<'cx, 'a> Context<'cx, 'a> { let local_bind_path = self.cx.expr_path(Path::from_ident(local_bind)); let rslt = if self.is_consumed { let ret = self.cx.stmt_expr(local_bind_path); - self.cx.expr_block(self.cx.block(self.span, vec![try_capture_call, ret])) + self.cx.expr_block(self.cx.block(self.span, thin_vec![try_capture_call, ret])) } else { self.best_case_captures.push(try_capture_call); local_bind_path @@ -440,7 +441,7 @@ fn expr_method_call( cx: &ExtCtxt<'_>, seg: PathSegment, receiver: P<Expr>, - args: Vec<P<Expr>>, + args: ThinVec<P<Expr>>, span: Span, ) -> P<Expr> { cx.expr(span, ExprKind::MethodCall(Box::new(MethodCall { seg, receiver, args, span }))) 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], diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index e5a5e6069..f011cb754 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -8,8 +8,8 @@ use rustc_ast::{self as ast, GenericArg}; use rustc_expand::base::{self, *}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; - use std::env; +use thin_vec::thin_vec; pub fn expand_option_env<'cx>( cx: &'cx mut ExtCtxt<'_>, @@ -41,7 +41,7 @@ pub fn expand_option_env<'cx>( Some(value) => cx.expr_call_global( sp, cx.std_path(&[sym::option, sym::Option, sym::Some]), - vec![cx.expr_str(sp, value)], + thin_vec![cx.expr_str(sp, value)], ), }; MacEager::expr(e) @@ -53,7 +53,7 @@ pub fn expand_env<'cx>( tts: TokenStream, ) -> Box<dyn base::MacResult + 'cx> { let mut exprs = match get_exprs_from_tts(cx, tts) { - Some(exprs) if exprs.is_empty() => { + Some(exprs) if exprs.is_empty() || exprs.len() > 2 => { cx.span_err(sp, "env! takes 1 or 2 arguments"); return DummyResult::any(sp); } @@ -64,28 +64,48 @@ pub fn expand_env<'cx>( let Some((var, _style)) = expr_to_string(cx, exprs.next().unwrap(), "expected string literal") else { return DummyResult::any(sp); }; - let msg = match exprs.next() { - None => Symbol::intern(&format!("environment variable `{}` not defined", var)), + + let custom_msg = match exprs.next() { + None => None, Some(second) => match expr_to_string(cx, second, "expected string literal") { None => return DummyResult::any(sp), - Some((s, _style)) => s, + Some((s, _style)) => Some(s), }, }; - if exprs.next().is_some() { - cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::any(sp); - } - let sp = cx.with_def_site_ctxt(sp); let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern); cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { - cx.span_err(sp, msg.as_str()); + let (msg, help) = match custom_msg { + None => ( + format!("environment variable `{var}` not defined at compile time"), + Some(help_for_missing_env_var(var.as_str())), + ), + Some(s) => (s.to_string(), None), + }; + let mut diag = cx.struct_span_err(sp, &msg); + if let Some(help) = help { + diag.help(help); + } + diag.emit(); return DummyResult::any(sp); } Some(value) => cx.expr_str(sp, value), }; MacEager::expr(e) } + +fn help_for_missing_env_var(var: &str) -> String { + if var.starts_with("CARGO_") + || var.starts_with("DEP_") + || matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET") + { + format!( + "Cargo sets build script variables at run time. Use `std::env::var(\"{var}\")` instead" + ) + } else { + format!("Use `std::env::var(\"{var}\")` to read the variable at run time") + } +} diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 9f4bbbc62..e93a23394 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1,7 +1,11 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::Expr; +use rustc_ast::{ + Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs, + FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount, + FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, +}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, Applicability, MultiSpan, PResult}; use rustc_expand::base::{self, *}; @@ -12,21 +16,15 @@ use rustc_span::{BytePos, InnerSpan, Span}; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; -mod ast; -use ast::*; - -mod expand; -use expand::expand_parsed_format_args; - // The format_args!() macro is expanded in three steps: // 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax, // but doesn't parse the template (the literal) itself. // 2. Second, `make_format_args` will parse the template, the format options, resolve argument references, -// produce diagnostics, and turn the whole thing into a `FormatArgs` structure. -// 3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure -// into the expression that the macro expands to. +// produce diagnostics, and turn the whole thing into a `FormatArgs` AST node. +// 3. Much later, in AST lowering (rustc_ast_lowering), that `FormatArgs` structure will be turned +// into the expression of type `core::fmt::Arguments`. -// See format/ast.rs for the FormatArgs structure and glossary. +// See rustc_ast/src/format.rs for the FormatArgs structure and glossary. // Only used in parse_args and report_invalid_references, // to indicate how a referred argument was used. @@ -437,7 +435,16 @@ pub fn make_format_args( format_options: FormatOptions { fill: format.fill, alignment, - flags: format.flags, + sign: format.sign.map(|s| match s { + parse::Sign::Plus => FormatSign::Plus, + parse::Sign::Minus => FormatSign::Minus, + }), + alternate: format.alternate, + zero_pad: format.zero_pad, + debug_hex: format.debug_hex.map(|s| match s { + parse::DebugHex::Lower => FormatDebugHex::Lower, + parse::DebugHex::Upper => FormatDebugHex::Upper, + }), precision, width, }, @@ -850,7 +857,7 @@ fn expand_format_args_impl<'cx>( match parse_args(ecx, sp, tts) { Ok((efmt, args)) => { if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) { - MacEager::expr(expand_parsed_format_args(ecx, format_args)) + MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))) } else { MacEager::expr(DummyResult::raw_expr(sp, true)) } diff --git a/compiler/rustc_builtin_macros/src/format/expand.rs b/compiler/rustc_builtin_macros/src/format/expand.rs deleted file mode 100644 index 9dde5efcb..000000000 --- a/compiler/rustc_builtin_macros/src/format/expand.rs +++ /dev/null @@ -1,353 +0,0 @@ -use super::*; -use rustc_ast as ast; -use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{BlockCheckMode, UnsafeSource}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_span::{sym, symbol::kw}; - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -enum ArgumentType { - Format(FormatTrait), - Usize, -} - -fn make_argument(ecx: &ExtCtxt<'_>, sp: Span, arg: P<ast::Expr>, ty: ArgumentType) -> P<ast::Expr> { - // Generate: - // ::core::fmt::ArgumentV1::new_…(arg) - use ArgumentType::*; - use FormatTrait::*; - ecx.expr_call_global( - sp, - ecx.std_path(&[ - sym::fmt, - sym::ArgumentV1, - match ty { - Format(Display) => sym::new_display, - Format(Debug) => sym::new_debug, - Format(LowerExp) => sym::new_lower_exp, - Format(UpperExp) => sym::new_upper_exp, - Format(Octal) => sym::new_octal, - Format(Pointer) => sym::new_pointer, - Format(Binary) => sym::new_binary, - Format(LowerHex) => sym::new_lower_hex, - Format(UpperHex) => sym::new_upper_hex, - Usize => sym::from_usize, - }, - ]), - vec![arg], - ) -} - -fn make_count( - ecx: &ExtCtxt<'_>, - sp: Span, - count: &Option<FormatCount>, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, -) -> P<ast::Expr> { - // Generate: - // ::core::fmt::rt::v1::Count::…(…) - match count { - Some(FormatCount::Literal(n)) => ecx.expr_call_global( - sp, - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Is]), - vec![ecx.expr_usize(sp, *n)], - ), - Some(FormatCount::Argument(arg)) => { - if let Ok(arg_index) = arg.index { - let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize)); - ecx.expr_call_global( - sp, - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Param]), - vec![ecx.expr_usize(sp, i)], - ) - } else { - DummyResult::raw_expr(sp, true) - } - } - None => ecx.expr_path(ecx.path_global( - sp, - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Implied]), - )), - } -} - -fn make_format_spec( - ecx: &ExtCtxt<'_>, - sp: Span, - placeholder: &FormatPlaceholder, - argmap: &mut FxIndexSet<(usize, ArgumentType)>, -) -> P<ast::Expr> { - // Generate: - // ::core::fmt::rt::v1::Argument { - // position: 0usize, - // format: ::core::fmt::rt::v1::FormatSpec { - // fill: ' ', - // align: ::core::fmt::rt::v1::Alignment::Unknown, - // flags: 0u32, - // precision: ::core::fmt::rt::v1::Count::Implied, - // width: ::core::fmt::rt::v1::Count::Implied, - // }, - // } - let position = match placeholder.argument.index { - Ok(arg_index) => { - let (i, _) = - argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait))); - ecx.expr_usize(sp, i) - } - Err(_) => DummyResult::raw_expr(sp, true), - }; - let fill = ecx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' ')); - let align = ecx.expr_path(ecx.path_global( - sp, - ecx.std_path(&[ - sym::fmt, - sym::rt, - sym::v1, - sym::Alignment, - match placeholder.format_options.alignment { - Some(FormatAlignment::Left) => sym::Left, - Some(FormatAlignment::Right) => sym::Right, - Some(FormatAlignment::Center) => sym::Center, - None => sym::Unknown, - }, - ]), - )); - let flags = ecx.expr_u32(sp, placeholder.format_options.flags); - let prec = make_count(ecx, sp, &placeholder.format_options.precision, argmap); - let width = make_count(ecx, sp, &placeholder.format_options.width, argmap); - ecx.expr_struct( - sp, - ecx.path_global(sp, ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Argument])), - vec![ - ecx.field_imm(sp, Ident::new(sym::position, sp), position), - ecx.field_imm( - sp, - Ident::new(sym::format, sp), - ecx.expr_struct( - sp, - ecx.path_global( - sp, - ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::FormatSpec]), - ), - vec![ - ecx.field_imm(sp, Ident::new(sym::fill, sp), fill), - ecx.field_imm(sp, Ident::new(sym::align, sp), align), - ecx.field_imm(sp, Ident::new(sym::flags, sp), flags), - ecx.field_imm(sp, Ident::new(sym::precision, sp), prec), - ecx.field_imm(sp, Ident::new(sym::width, sp), width), - ], - ), - ), - ], - ) -} - -pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<ast::Expr> { - let macsp = ecx.with_def_site_ctxt(ecx.call_site()); - - let lit_pieces = ecx.expr_array_ref( - fmt.span, - fmt.template - .iter() - .enumerate() - .filter_map(|(i, piece)| match piece { - &FormatArgsPiece::Literal(s) => Some(ecx.expr_str(fmt.span, s)), - &FormatArgsPiece::Placeholder(_) => { - // Inject empty string before placeholders when not already preceded by a literal piece. - if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) { - Some(ecx.expr_str(fmt.span, kw::Empty)) - } else { - None - } - } - }) - .collect(), - ); - - // Whether we'll use the `Arguments::new_v1_formatted` form (true), - // or the `Arguments::new_v1` form (false). - let mut use_format_options = false; - - // Create a list of all _unique_ (argument, format trait) combinations. - // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)] - let mut argmap = FxIndexSet::default(); - for piece in &fmt.template { - let FormatArgsPiece::Placeholder(placeholder) = piece else { continue }; - if placeholder.format_options != Default::default() { - // Can't use basic form if there's any formatting options. - use_format_options = true; - } - if let Ok(index) = placeholder.argument.index { - if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) { - // Duplicate (argument, format trait) combination, - // which we'll only put once in the args array. - use_format_options = true; - } - } - } - - let format_options = use_format_options.then(|| { - // Generate: - // &[format_spec_0, format_spec_1, format_spec_2] - ecx.expr_array_ref( - macsp, - fmt.template - .iter() - .filter_map(|piece| { - let FormatArgsPiece::Placeholder(placeholder) = piece else { return None }; - Some(make_format_spec(ecx, macsp, placeholder, &mut argmap)) - }) - .collect(), - ) - }); - - let arguments = fmt.arguments.into_vec(); - - // If the args array contains exactly all the original arguments once, - // in order, we can use a simple array instead of a `match` construction. - // However, if there's a yield point in any argument except the first one, - // we don't do this, because an ArgumentV1 cannot be kept across yield points. - let use_simple_array = argmap.len() == arguments.len() - && argmap.iter().enumerate().all(|(i, &(j, _))| i == j) - && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr)); - - let args = if use_simple_array { - // Generate: - // &[ - // ::core::fmt::ArgumentV1::new_display(&arg0), - // ::core::fmt::ArgumentV1::new_lower_hex(&arg1), - // ::core::fmt::ArgumentV1::new_debug(&arg2), - // ] - ecx.expr_array_ref( - macsp, - arguments - .into_iter() - .zip(argmap) - .map(|(arg, (_, ty))| { - let sp = arg.expr.span.with_ctxt(macsp.ctxt()); - make_argument(ecx, sp, ecx.expr_addr_of(sp, arg.expr), ty) - }) - .collect(), - ) - } else { - // Generate: - // match (&arg0, &arg1, &arg2) { - // args => &[ - // ::core::fmt::ArgumentV1::new_display(args.0), - // ::core::fmt::ArgumentV1::new_lower_hex(args.1), - // ::core::fmt::ArgumentV1::new_debug(args.0), - // ] - // } - let args_ident = Ident::new(sym::args, macsp); - let args = argmap - .iter() - .map(|&(arg_index, ty)| { - if let Some(arg) = arguments.get(arg_index) { - let sp = arg.expr.span.with_ctxt(macsp.ctxt()); - make_argument( - ecx, - sp, - ecx.expr_field( - sp, - ecx.expr_ident(macsp, args_ident), - Ident::new(sym::integer(arg_index), macsp), - ), - ty, - ) - } else { - DummyResult::raw_expr(macsp, true) - } - }) - .collect(); - ecx.expr_addr_of( - macsp, - ecx.expr_match( - macsp, - ecx.expr_tuple( - macsp, - arguments - .into_iter() - .map(|arg| { - ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr) - }) - .collect(), - ), - vec![ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))], - ), - ) - }; - - if let Some(format_options) = format_options { - // Generate: - // ::core::fmt::Arguments::new_v1_formatted( - // lit_pieces, - // args, - // format_options, - // unsafe { ::core::fmt::UnsafeArg::new() } - // ) - ecx.expr_call_global( - macsp, - ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1_formatted]), - vec![ - lit_pieces, - args, - format_options, - ecx.expr_block(P(ast::Block { - stmts: vec![ecx.stmt_expr(ecx.expr_call_global( - macsp, - ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]), - Vec::new(), - ))], - id: ast::DUMMY_NODE_ID, - rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), - span: macsp, - tokens: None, - could_be_bare_literal: false, - })), - ], - ) - } else { - // Generate: - // ::core::fmt::Arguments::new_v1( - // lit_pieces, - // args, - // ) - ecx.expr_call_global( - macsp, - ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1]), - vec![lit_pieces, args], - ) - } -} - -fn may_contain_yield_point(e: &ast::Expr) -> bool { - struct MayContainYieldPoint(bool); - - impl Visitor<'_> for MayContainYieldPoint { - fn visit_expr(&mut self, e: &ast::Expr) { - if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind { - self.0 = true; - } else { - visit::walk_expr(self, e); - } - } - - fn visit_mac_call(&mut self, _: &ast::MacCall) { - self.0 = true; - } - - fn visit_attribute(&mut self, _: &ast::Attribute) { - // Conservatively assume this may be a proc macro attribute in - // expression position. - self.0 = true; - } - - fn visit_item(&mut self, _: &ast::Item) { - // Do not recurse into nested items. - } - } - - let mut visitor = MayContainYieldPoint(false); - visitor.visit_expr(e); - visitor.0 -} diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index f8761653b..41b51bae7 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -9,7 +9,7 @@ use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; pub fn expand( ecx: &mut ExtCtxt<'_>, @@ -47,7 +47,7 @@ pub fn expand( let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect(); // Generate anonymous constant serving as container for the allocator methods. - let const_ty = ecx.ty(ty_span, TyKind::Tup(Vec::new())); + let const_ty = ecx.ty(ty_span, TyKind::Tup(ThinVec::new())); let const_body = ecx.expr_block(ecx.block(span, stmts)); let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body); let const_item = if is_stmt { @@ -70,7 +70,7 @@ struct AllocFnFactory<'a, 'b> { impl AllocFnFactory<'_, '_> { fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt { - let mut abi_args = Vec::new(); + let mut abi_args = ThinVec::new(); let mut i = 0; let mut mk = || { let name = Ident::from_str_and_span(&format!("arg{}", i), self.span); @@ -99,7 +99,7 @@ impl AllocFnFactory<'_, '_> { self.cx.stmt_item(self.ty_span, item) } - fn call_allocator(&self, method: Symbol, mut args: Vec<P<Expr>>) -> P<Expr> { + fn call_allocator(&self, method: Symbol, mut args: ThinVec<P<Expr>>) -> P<Expr> { let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]); let method = self.cx.expr_path(self.cx.path(self.ty_span, method)); let allocator = self.cx.path_ident(self.ty_span, self.global); @@ -117,7 +117,7 @@ impl AllocFnFactory<'_, '_> { fn arg_ty( &self, ty: &AllocatorTy, - args: &mut Vec<Param>, + args: &mut ThinVec<Param>, ident: &mut dyn FnMut() -> Ident, ) -> P<Expr> { match *ty { @@ -134,7 +134,7 @@ impl AllocFnFactory<'_, '_> { let layout_new = self.cx.expr_path(self.cx.path(self.span, layout_new)); let size = self.cx.expr_ident(self.span, size); let align = self.cx.expr_ident(self.span, align); - let layout = self.cx.expr_call(self.span, layout_new, vec![size, align]); + let layout = self.cx.expr_call(self.span, layout_new, thin_vec![size, align]); layout } @@ -168,7 +168,7 @@ impl AllocFnFactory<'_, '_> { (self.ptr_u8(), expr) } - AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr), + AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(ThinVec::new())), expr), AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { panic!("can't convert `AllocatorTy` to an output") diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 75cfac723..8afb6e560 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -21,8 +21,10 @@ extern crate tracing; use crate::deriving::*; +use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; +use rustc_macros::fluent_messages; use rustc_span::symbol::sym; mod alloc_error_handler; @@ -54,6 +56,8 @@ pub mod proc_macro_harness; pub mod standard_library_imports; pub mod test_harness; +fluent_messages! { "../locales/en-US.ftl" } + pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { let mut register = |name, kind| resolver.register_builtin_macro(name, kind); macro register_bang($($name:ident: $f:expr,)*) { diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 21c8caa65..bc513607d 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -11,6 +11,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use smallvec::smallvec; use std::mem; +use thin_vec::{thin_vec, ThinVec}; struct ProcMacroDerive { id: NodeId, @@ -314,11 +315,14 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { cx.expr_call( span, proc_macro_ty_method_path(cx, custom_derive), - vec![ + thin_vec![ cx.expr_str(span, cd.trait_name), cx.expr_array_ref( span, - cd.attrs.iter().map(|&s| cx.expr_str(span, s)).collect::<Vec<_>>(), + cd.attrs + .iter() + .map(|&s| cx.expr_str(span, s)) + .collect::<ThinVec<_>>(), ), local_path(cx, cd.function_name), ], @@ -335,7 +339,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { cx.expr_call( span, proc_macro_ty_method_path(cx, ident), - vec![ + thin_vec![ cx.expr_str(span, ca.function_name.name), local_path(cx, ca.function_name), ], @@ -371,13 +375,13 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { }); let block = cx.expr_block( - cx.block(span, vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]), + cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]), ); let anon_constant = cx.item_const( span, Ident::new(kw::Underscore, span), - cx.ty(span, ast::TyKind::Tup(Vec::new())), + cx.ty(span, ast::TyKind::Tup(ThinVec::new())), block, ); diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index f73f20c84..e67c0dba6 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -62,7 +62,7 @@ pub fn inject( // the one with the prelude. let name = names[0]; - let root = (edition == Edition2015).then(|| kw::PathRoot); + let root = (edition == Edition2015).then_some(kw::PathRoot); let import_path = root .iter() diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 729ae4071..e02c7e6c0 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -10,7 +10,7 @@ use rustc_session::Session; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use std::iter; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; /// #[test_case] is used by custom test authors to mark tests /// When building for test, it needs to make the item public and gensym the name @@ -179,19 +179,19 @@ pub fn expand_test_or_bench( cx.expr_call( sp, cx.expr_path(test_path("StaticBenchFn")), - vec![ + thin_vec![ // |b| self::test::assert_test_result( cx.lambda1( sp, cx.expr_call( sp, cx.expr_path(test_path("assert_test_result")), - vec![ + thin_vec![ // super::$test_fn(b) cx.expr_call( ret_ty_sp, cx.expr_path(cx.path(sp, vec![item.ident])), - vec![cx.expr_ident(sp, b)], + thin_vec![cx.expr_ident(sp, b)], ), ], ), @@ -203,7 +203,7 @@ pub fn expand_test_or_bench( cx.expr_call( sp, cx.expr_path(test_path("StaticTestFn")), - vec![ + thin_vec![ // || { cx.lambda0( sp, @@ -211,12 +211,12 @@ pub fn expand_test_or_bench( cx.expr_call( sp, cx.expr_path(test_path("assert_test_result")), - vec![ + thin_vec![ // $test_fn() cx.expr_call( ret_ty_sp, cx.expr_path(cx.path(sp, vec![item.ident])), - vec![], + ThinVec::new(), ), // ) ], ), // } @@ -249,21 +249,21 @@ pub fn expand_test_or_bench( cx.expr_struct( sp, test_path("TestDescAndFn"), - vec![ + thin_vec![ // desc: test::TestDesc { field( "desc", cx.expr_struct( sp, test_path("TestDesc"), - vec![ + thin_vec![ // name: "path::to::test" field( "name", cx.expr_call( sp, cx.expr_path(test_path("StaticTestName")), - vec![cx.expr_str(sp, test_path_symbol)], + thin_vec![cx.expr_str(sp, test_path_symbol)], ), ), // ignore: true | false @@ -300,7 +300,7 @@ pub fn expand_test_or_bench( ShouldPanic::Yes(Some(sym)) => cx.expr_call( sp, cx.expr_path(should_panic_path("YesWithMessage")), - vec![cx.expr_str(sp, sym)], + thin_vec![cx.expr_str(sp, sym)], ), }, ), diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index ad8871080..d8e3db9e8 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -14,7 +14,8 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::PanicStrategy; use smallvec::{smallvec, SmallVec}; -use thin_vec::thin_vec; +use thin_vec::{thin_vec, ThinVec}; +use tracing::debug; use std::{iter, mem}; @@ -299,7 +300,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> { test_runner.span = sp; let test_main_path_expr = ecx.expr_path(test_runner); - let call_test_main = ecx.expr_call(sp, test_main_path_expr, vec![mk_tests_slice(cx, sp)]); + let call_test_main = ecx.expr_call(sp, test_main_path_expr, thin_vec![mk_tests_slice(cx, sp)]); let call_test_main = ecx.stmt_expr(call_test_main); // extern crate test @@ -312,16 +313,16 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> { let main_attr = ecx.attr_word(sym::rustc_main, sp); // pub fn main() { ... } - let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![])); + let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new())); // If no test runner is provided we need to import the test crate let main_body = if cx.test_runner.is_none() { - ecx.block(sp, vec![test_extern_stmt, call_test_main]) + ecx.block(sp, thin_vec![test_extern_stmt, call_test_main]) } else { - ecx.block(sp, vec![call_test_main]) + ecx.block(sp, thin_vec![call_test_main]) }; - let decl = ecx.fn_decl(vec![], ast::FnRetTy::Ty(main_ret_ty)); + let decl = ecx.fn_decl(ThinVec::new(), ast::FnRetTy::Ty(main_ret_ty)); let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp }; let defaultness = ast::Defaultness::Final; let main = ast::ItemKind::Fn(Box::new(ast::Fn { |