summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_builtin_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_builtin_macros/src')
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs25
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs85
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs62
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs33
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs221
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/ty.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs7
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs44
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs33
-rw-r--r--compiler/rustc_builtin_macros/src/format/ast.rs240
-rw-r--r--compiler/rustc_builtin_macros/src/format/expand.rs353
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs14
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs14
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs22
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs13
28 files changed, 454 insertions, 825 deletions
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 &param.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/ast.rs b/compiler/rustc_builtin_macros/src/format/ast.rs
deleted file mode 100644
index 01dbffa21..000000000
--- a/compiler/rustc_builtin_macros/src/format/ast.rs
+++ /dev/null
@@ -1,240 +0,0 @@
-use rustc_ast::ptr::P;
-use rustc_ast::Expr;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::Span;
-
-// Definitions:
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-// └──────────────────────────────────────────────┘
-// FormatArgs
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-// └─────────┘
-// argument
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-// └───────────────────┘
-// template
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-// └────┘└─────────┘└┘
-// pieces
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-// └────┘ └┘
-// literal pieces
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-// └─────────┘
-// placeholder
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-// └─┘ └─┘
-// positions (could be names, numbers, empty, or `*`)
-
-/// (Parsed) format args.
-///
-/// Basically the "AST" for a complete `format_args!()`.
-///
-/// E.g., `format_args!("hello {name}");`.
-#[derive(Clone, Debug)]
-pub struct FormatArgs {
- pub span: Span,
- pub template: Vec<FormatArgsPiece>,
- pub arguments: FormatArguments,
-}
-
-/// A piece of a format template string.
-///
-/// E.g. "hello" or "{name}".
-#[derive(Clone, Debug)]
-pub enum FormatArgsPiece {
- Literal(Symbol),
- Placeholder(FormatPlaceholder),
-}
-
-/// The arguments to format_args!().
-///
-/// E.g. `1, 2, name="ferris", n=3`,
-/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
-#[derive(Clone, Debug)]
-pub struct FormatArguments {
- arguments: Vec<FormatArgument>,
- num_unnamed_args: usize,
- num_explicit_args: usize,
- names: FxHashMap<Symbol, usize>,
-}
-
-impl FormatArguments {
- pub fn new() -> Self {
- Self {
- arguments: Vec::new(),
- names: FxHashMap::default(),
- num_unnamed_args: 0,
- num_explicit_args: 0,
- }
- }
-
- pub fn add(&mut self, arg: FormatArgument) -> usize {
- let index = self.arguments.len();
- if let Some(name) = arg.kind.ident() {
- self.names.insert(name.name, index);
- } else if self.names.is_empty() {
- // Only count the unnamed args before the first named arg.
- // (Any later ones are errors.)
- self.num_unnamed_args += 1;
- }
- if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
- // This is an explicit argument.
- // Make sure that all arguments so far are explcit.
- assert_eq!(
- self.num_explicit_args,
- self.arguments.len(),
- "captured arguments must be added last"
- );
- self.num_explicit_args += 1;
- }
- self.arguments.push(arg);
- index
- }
-
- pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
- let i = *self.names.get(&name)?;
- Some((i, &self.arguments[i]))
- }
-
- pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
- (i < self.num_explicit_args).then(|| &self.arguments[i])
- }
-
- pub fn unnamed_args(&self) -> &[FormatArgument] {
- &self.arguments[..self.num_unnamed_args]
- }
-
- pub fn named_args(&self) -> &[FormatArgument] {
- &self.arguments[self.num_unnamed_args..self.num_explicit_args]
- }
-
- pub fn explicit_args(&self) -> &[FormatArgument] {
- &self.arguments[..self.num_explicit_args]
- }
-
- pub fn into_vec(self) -> Vec<FormatArgument> {
- self.arguments
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct FormatArgument {
- pub kind: FormatArgumentKind,
- pub expr: P<Expr>,
-}
-
-#[derive(Clone, Debug)]
-pub enum FormatArgumentKind {
- /// `format_args(…, arg)`
- Normal,
- /// `format_args(…, arg = 1)`
- Named(Ident),
- /// `format_args("… {arg} …")`
- Captured(Ident),
-}
-
-impl FormatArgumentKind {
- pub fn ident(&self) -> Option<Ident> {
- match self {
- &Self::Normal => None,
- &Self::Named(id) => Some(id),
- &Self::Captured(id) => Some(id),
- }
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct FormatPlaceholder {
- /// Index into [`FormatArgs::arguments`].
- pub argument: FormatArgPosition,
- /// The span inside the format string for the full `{…}` placeholder.
- pub span: Option<Span>,
- /// `{}`, `{:?}`, or `{:x}`, etc.
- pub format_trait: FormatTrait,
- /// `{}` or `{:.5}` or `{:-^20}`, etc.
- pub format_options: FormatOptions,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct FormatArgPosition {
- /// Which argument this position refers to (Ok),
- /// or would've referred to if it existed (Err).
- pub index: Result<usize, usize>,
- /// What kind of position this is. See [`FormatArgPositionKind`].
- pub kind: FormatArgPositionKind,
- /// The span of the name or number.
- pub span: Option<Span>,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum FormatArgPositionKind {
- /// `{}` or `{:.*}`
- Implicit,
- /// `{1}` or `{:1$}` or `{:.1$}`
- Number,
- /// `{a}` or `{:a$}` or `{:.a$}`
- Named,
-}
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum FormatTrait {
- /// `{}`
- Display,
- /// `{:?}`
- Debug,
- /// `{:e}`
- LowerExp,
- /// `{:E}`
- UpperExp,
- /// `{:o}`
- Octal,
- /// `{:p}`
- Pointer,
- /// `{:b}`
- Binary,
- /// `{:x}`
- LowerHex,
- /// `{:X}`
- UpperHex,
-}
-
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct FormatOptions {
- /// The width. E.g. `{:5}` or `{:width$}`.
- pub width: Option<FormatCount>,
- /// The precision. E.g. `{:.5}` or `{:.precision$}`.
- pub precision: Option<FormatCount>,
- /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
- 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,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum FormatAlignment {
- /// `{:<}`
- Left,
- /// `{:>}`
- Right,
- /// `{:^}`
- Center,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum FormatCount {
- /// `{:5}` or `{:.5}`
- Literal(usize),
- /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
- Argument(FormatArgPosition),
-}
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 {