summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_builtin_macros
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_builtin_macros')
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml6
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl14
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs30
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs18
-rw-r--r--compiler/rustc_builtin_macros/src/concat.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs51
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs206
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/ty.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs131
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs30
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs24
21 files changed, 390 insertions, 210 deletions
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index 44012e802..21b87be4b 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
doctest = false
[dependencies]
+# tidy-alphabetical-start
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
@@ -14,16 +15,17 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_expand = { path = "../rustc_expand" }
rustc_feature = { path = "../rustc_feature" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
-rustc_fluent_macro = { path = "../rustc_fluent_macro" }
-rustc_parse_format = { path = "../rustc_parse_format" }
rustc_parse = { path = "../rustc_parse" }
+rustc_parse_format = { path = "../rustc_parse_format" }
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.12"
tracing = "0.1"
+# tidy-alphabetical-end
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 207ae8ad8..dda466b02 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -137,6 +137,20 @@ builtin_macros_format_positional_after_named = positional arguments cannot follo
.label = positional arguments must be before named arguments
.named_args = named argument
+builtin_macros_format_redundant_args = redundant {$n ->
+ [one] argument
+ *[more] arguments
+ }
+ .help = {$n ->
+ [one] the formatting string already captures the binding directly, it doesn't need to be included in the argument list
+ *[more] the formatting strings already captures the bindings directly, they don't need to be included in the argument list
+ }
+ .note = {$n ->
+ [one] the formatting specifier is referencing the binding already
+ *[more] the formatting specifiers are referencing the bindings already
+ }
+ .suggestion = this can be removed
+
builtin_macros_format_remove_raw_ident = remove the `r#`
builtin_macros_format_requires_string = requires at least a format string argument
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index 82bae9157..070d50708 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -21,20 +21,22 @@ pub fn expand(
// Allow using `#[alloc_error_handler]` on an item statement
// FIXME - if we get deref patterns, use them to reduce duplication here
- let (item, is_stmt, sig_span) =
- if let Annotatable::Item(item) = &item
- && let ItemKind::Fn(fn_kind) = &item.kind
- {
- (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span))
- } else if let Annotatable::Stmt(stmt) = &item
- && let StmtKind::Item(item) = &stmt.kind
- && let ItemKind::Fn(fn_kind) = &item.kind
- {
- (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
- } else {
- ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() });
- return vec![orig_item];
- };
+ let (item, is_stmt, sig_span) = if let Annotatable::Item(item) = &item
+ && let ItemKind::Fn(fn_kind) = &item.kind
+ {
+ (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span))
+ } else if let Annotatable::Stmt(stmt) = &item
+ && let StmtKind::Item(item) = &stmt.kind
+ && let ItemKind::Fn(fn_kind) = &item.kind
+ {
+ (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
+ } else {
+ ecx.sess
+ .parse_sess
+ .span_diagnostic
+ .emit_err(errors::AllocErrorMustBeFn { span: item.span() });
+ return vec![orig_item];
+ };
// Generate a bunch of new items using the AllocFnFactory
let span = ecx.with_def_site_ctxt(item.span);
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 9302db104..7abfcc8c5 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -85,7 +85,7 @@ pub fn expand_assert<'cx>(
DUMMY_SP,
Symbol::intern(&format!(
"assertion failed: {}",
- pprust::expr_to_string(&cond_expr).escape_debug()
+ pprust::expr_to_string(&cond_expr)
)),
)],
);
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index 0682d48ac..2a4bfe9e2 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -193,10 +193,9 @@ impl<'cx, 'a> Context<'cx, 'a> {
fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
match &mut expr.kind {
ExprKind::AddrOf(_, mutability, local_expr) => {
- self.with_is_consumed_management(
- matches!(mutability, Mutability::Mut),
- |this| this.manage_cond_expr(local_expr)
- );
+ self.with_is_consumed_management(matches!(mutability, Mutability::Mut), |this| {
+ this.manage_cond_expr(local_expr)
+ });
}
ExprKind::Array(local_exprs) => {
for local_expr in local_exprs {
@@ -223,7 +222,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
|this| {
this.manage_cond_expr(lhs);
this.manage_cond_expr(rhs);
- }
+ },
);
}
ExprKind::Call(_, local_exprs) => {
@@ -285,10 +284,9 @@ impl<'cx, 'a> Context<'cx, 'a> {
}
}
ExprKind::Unary(un_op, local_expr) => {
- self.with_is_consumed_management(
- matches!(un_op, UnOp::Neg | UnOp::Not),
- |this| this.manage_cond_expr(local_expr)
- );
+ self.with_is_consumed_management(matches!(un_op, UnOp::Neg | UnOp::Not), |this| {
+ this.manage_cond_expr(local_expr)
+ });
}
// Expressions that are not worth or can not be captured.
//
@@ -296,7 +294,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
// sync with the `rfc-2011-nicer-assert-messages/all-expr-kinds.rs` test.
ExprKind::Assign(_, _, _)
| ExprKind::AssignOp(_, _, _)
- | ExprKind::Async(_, _)
+ | ExprKind::Gen(_, _, _)
| ExprKind::Await(_, _)
| ExprKind::Block(_, _)
| ExprKind::Break(_, _)
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index 9695fb4fe..6b8330bfd 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -33,7 +33,7 @@ pub fn expand_concat(
accumulator.push_str(&b.to_string());
}
Ok(ast::LitKind::CStr(..)) => {
- cx.emit_err(errors::ConcatCStrLit{ span: e.span});
+ cx.emit_err(errors::ConcatCStrLit { span: e.span });
has_errors = true;
}
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
@@ -49,7 +49,9 @@ pub fn expand_concat(
}
},
// We also want to allow negative numeric literals.
- ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) if let ast::ExprKind::Lit(token_lit) = expr.kind => {
+ ast::ExprKind::Unary(ast::UnOp::Neg, ref expr)
+ if let ast::ExprKind::Lit(token_lit) = expr.kind =>
+ {
match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")),
Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")),
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index 6a1586f07..c4f5af384 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -140,8 +140,8 @@ pub fn expand_concat_bytes(
}
ast::ExprKind::Repeat(expr, count) => {
if let ast::ExprKind::Lit(token_lit) = count.value.kind
- && let Ok(ast::LitKind::Int(count_val, _)) =
- ast::LitKind::from_token_lit(token_lit)
+ && let Ok(ast::LitKind::Int(count_val, _)) =
+ ast::LitKind::from_token_lit(token_lit)
{
if let Some(elem) =
handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
@@ -151,7 +151,7 @@ pub fn expand_concat_bytes(
}
}
} else {
- cx.emit_err(errors::ConcatBytesBadRepeat {span: count.value.span });
+ cx.emit_err(errors::ConcatBytesBadRepeat { span: count.value.span });
}
}
&ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index b468abe32..1649cc76c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -106,7 +106,9 @@ fn cs_clone_simple(
// This basic redundancy checking only prevents duplication of
// assertions like `AssertParamIsClone<Foo>` where the type is a
// simple name. That's enough to get a lot of cases, though.
- if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
+ if let Some(name) = field.ty.kind.is_simple_path()
+ && !seen_type_names.insert(name)
+ {
// Already produced an assertion for this type.
} else {
// let _: AssertParamIsClone<FieldTy>;
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index a000e4895..8a6d21937 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -73,7 +73,9 @@ fn cs_total_eq_assert(
// This basic redundancy checking only prevents duplication of
// assertions like `AssertParamIsEq<Foo>` where the type is a
// simple name. That's enough to get a lot of cases, though.
- if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
+ if let Some(name) = field.ty.kind.is_simple_path()
+ && !seen_type_names.insert(name)
+ {
// Already produced an assertion for this type.
} else {
// let _: AssertParamIsEq<FieldTy>;
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 a5b3a504e..f3164bd2c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -21,25 +21,26 @@ pub fn expand_deriving_partial_ord(
// 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
- }
- })
+ && 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
- };
+ }),
+ }
+ } else {
+ true
+ };
let partial_cmp_def = MethodDef {
name: sym::partial_cmp,
generics: Bounds::empty(),
@@ -133,12 +134,16 @@ fn cs_partial_cmp(
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
+ && 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 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])
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 809f9838d..30c9b35bb 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -33,7 +33,7 @@ pub fn expand_deriving_debug(
explicit_self: true,
nonself_args: vec![(fmtr, sym::f)],
ret_ty: Path(path_std!(fmt::Result)),
- attributes: ast::AttrVec::new(),
+ attributes: thin_vec![cx.attr_word(sym::inline, span)],
fieldless_variants_strategy:
FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 7252658d4..aa1ce1b92 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -37,8 +37,9 @@
//! following snippet
//!
//! ```rust
-//! # #![allow(dead_code)]
-//! struct A { x : i32 }
+//! struct A {
+//! x: i32,
+//! }
//!
//! struct B(i32);
//!
@@ -74,6 +75,7 @@
//! trait PartialEq {
//! fn eq(&self, other: &Self) -> bool;
//! }
+//!
//! impl PartialEq for i32 {
//! fn eq(&self, other: &i32) -> bool {
//! *self == *other
@@ -90,22 +92,22 @@
//!
//! ```text
//! Struct(vec![FieldInfo {
-//! span: <span of x>
-//! name: Some(<ident of x>),
-//! self_: <expr for &self.x>,
-//! other: vec![<expr for &other.x]
-//! }])
+//! span: <span of x>,
+//! name: Some(<ident of x>),
+//! self_: <expr for &self.x>,
+//! other: vec![<expr for &other.x>],
+//! }])
//! ```
//!
//! For the `B` impl, called with `B(a)` and `B(b)`,
//!
//! ```text
//! Struct(vec![FieldInfo {
-//! span: <span of `i32`>,
-//! name: None,
-//! self_: <expr for &a>
-//! other: vec![<expr for &b>]
-//! }])
+//! span: <span of i32>,
+//! name: None,
+//! self_: <expr for &a>,
+//! other: vec![<expr for &b>],
+//! }])
//! ```
//!
//! ## Enums
@@ -114,33 +116,42 @@
//! == C0(b)`, the SubstructureFields is
//!
//! ```text
-//! EnumMatching(0, <ast::Variant for C0>,
-//! vec![FieldInfo {
-//! span: <span of i32>
-//! name: None,
-//! self_: <expr for &a>,
-//! other: vec![<expr for &b>]
-//! }])
+//! EnumMatching(
+//! 0,
+//! <ast::Variant for C0>,
+//! vec![FieldInfo {
+//! span: <span of i32>,
+//! name: None,
+//! self_: <expr for &a>,
+//! other: vec![<expr for &b>],
+//! }],
+//! )
//! ```
//!
//! For `C1 {x}` and `C1 {x}`,
//!
//! ```text
-//! EnumMatching(1, <ast::Variant for C1>,
-//! vec![FieldInfo {
-//! span: <span of x>
-//! name: Some(<ident of x>),
-//! self_: <expr for &self.x>,
-//! other: vec![<expr for &other.x>]
-//! }])
+//! EnumMatching(
+//! 1,
+//! <ast::Variant for C1>,
+//! vec![FieldInfo {
+//! span: <span of x>,
+//! name: Some(<ident of x>),
+//! self_: <expr for &self.x>,
+//! other: vec![<expr for &other.x>],
+//! }],
+//! )
//! ```
//!
//! For the tags,
//!
//! ```text
//! EnumTag(
-//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
+//! &[<ident of self tag>, <ident of other tag>],
+//! <expr to combine with>,
+//! )
//! ```
+//!
//! Note that this setup doesn't allow for the brute-force "match every variant
//! against every other variant" approach, which is bad because it produces a
//! quadratic amount of code (see #15375).
@@ -154,9 +165,13 @@
//!
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
//!
-//! StaticEnum(<ast::EnumDef of C>,
-//! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
-//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
+//! StaticEnum(
+//! <ast::EnumDef of C>,
+//! vec![
+//! (<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
+//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)])),
+//! ],
+//! )
//! ```
pub use StaticFields::*;
@@ -522,7 +537,10 @@ impl<'a> TraitDef<'a> {
/// Given that we are deriving a trait `DerivedTrait` for a type like:
///
/// ```ignore (only-for-syntax-highlight)
- /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z> where C: WhereTrait {
+ /// struct Struct<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
+ /// where
+ /// C: WhereTrait,
+ /// {
/// a: A,
/// b: B::Item,
/// b1: <B as DeclaredTrait>::Item,
@@ -535,12 +553,13 @@ impl<'a> TraitDef<'a> {
/// create an impl like:
///
/// ```ignore (only-for-syntax-highlight)
- /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ... Z> where
- /// C: WhereTrait,
+ /// impl<'a, ..., 'z, A, B: DeclaredTrait, C, ..., Z>
+ /// where
+ /// C: WhereTrait,
/// A: DerivedTrait + B1 + ... + BN,
/// B: DerivedTrait + B1 + ... + BN,
/// C: DerivedTrait + B1 + ... + BN,
- /// B::Item: DerivedTrait + B1 + ... + BN,
+ /// B::Item: DerivedTrait + B1 + ... + BN,
/// <C as WhereTrait>::Item: DerivedTrait + B1 + ... + BN,
/// ...
/// {
@@ -676,65 +695,59 @@ impl<'a> TraitDef<'a> {
}
}));
- {
- // Extra scope required here so ty_params goes out of scope before params is moved
-
- let mut ty_params = params
- .iter()
- .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
- .peekable();
-
- if ty_params.peek().is_some() {
- let ty_param_names: Vec<Symbol> =
- ty_params.map(|ty_param| ty_param.ident.name).collect();
-
- for field_ty in field_tys {
- let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
-
- for field_ty_param in field_ty_params {
- // if we have already handled this type, skip it
- if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
- && let [sole_segment] = &*p.segments
- && ty_param_names.contains(&sole_segment.ident.name)
- {
- continue;
- }
- let mut bounds: Vec<_> = self
- .additional_bounds
- .iter()
- .map(|p| {
- cx.trait_bound(
- p.to_path(cx, self.span, type_ident, generics),
- self.is_const,
- )
- })
- .collect();
-
- // Require the current trait.
- if !self.skip_path_as_bound {
- bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
- }
+ let ty_param_names: Vec<Symbol> = params
+ .iter()
+ .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
+ .map(|ty_param| ty_param.ident.name)
+ .collect();
- // 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(
+ if !ty_param_names.is_empty() {
+ for field_ty in field_tys {
+ let field_ty_params = find_type_parameters(&field_ty, &ty_param_names, cx);
+
+ for field_ty_param in field_ty_params {
+ // if we have already handled this type, skip it
+ if let ast::TyKind::Path(_, p) = &field_ty_param.ty.kind
+ && let [sole_segment] = &*p.segments
+ && ty_param_names.contains(&sole_segment.ident.name)
+ {
+ continue;
+ }
+ let mut bounds: Vec<_> = self
+ .additional_bounds
+ .iter()
+ .map(|p| {
+ cx.trait_bound(
p.to_path(cx, self.span, type_ident, generics),
self.is_const,
- ));
- }
+ )
+ })
+ .collect();
- if !bounds.is_empty() {
- let predicate = ast::WhereBoundPredicate {
- span: self.span,
- bound_generic_params: field_ty_param.bound_generic_params,
- bounded_ty: field_ty_param.ty,
- bounds,
- };
+ // Require the current trait.
+ if !self.skip_path_as_bound {
+ bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
+ }
- let predicate = ast::WherePredicate::BoundPredicate(predicate);
- where_clause.predicates.push(predicate);
- }
+ // 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,
+ ));
+ }
+
+ if !bounds.is_empty() {
+ let predicate = ast::WhereBoundPredicate {
+ span: self.span,
+ bound_generic_params: field_ty_param.bound_generic_params,
+ bounded_ty: field_ty_param.ty,
+ bounds,
+ };
+
+ let predicate = ast::WherePredicate::BoundPredicate(predicate);
+ where_clause.predicates.push(predicate);
}
}
}
@@ -1026,6 +1039,7 @@ impl<'a> MethodDef<'a> {
}
/// The normal case uses field access.
+ ///
/// ```
/// #[derive(PartialEq)]
/// # struct Dummy;
@@ -1038,10 +1052,12 @@ 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, we use a local block to force a copy.
/// This requires that the field impl `Copy`.
+ ///
/// ```rust,ignore (example)
/// # struct A { x: u8, y: u8 }
/// impl PartialEq for A {
@@ -1053,7 +1069,7 @@ impl<'a> MethodDef<'a> {
/// impl Hash for A {
/// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
/// ::core::hash::Hash::hash(&{ self.x }, state);
- /// ::core::hash::Hash::hash(&{ self.y }, state)
+ /// ::core::hash::Hash::hash(&{ self.y }, state);
/// }
/// }
/// ```
@@ -1107,7 +1123,9 @@ impl<'a> MethodDef<'a> {
/// A2(i32)
/// }
/// ```
+ ///
/// is equivalent to:
+ ///
/// ```
/// #![feature(core_intrinsics)]
/// enum A {
@@ -1119,15 +1137,15 @@ impl<'a> MethodDef<'a> {
/// fn eq(&self, other: &A) -> bool {
/// let __self_tag = ::core::intrinsics::discriminant_value(self);
/// let __arg1_tag = ::core::intrinsics::discriminant_value(other);
- /// __self_tag == __arg1_tag &&
- /// match (self, other) {
- /// (A::A2(__self_0), A::A2(__arg1_0)) =>
- /// *__self_0 == *__arg1_0,
+ /// __self_tag == __arg1_tag
+ /// && match (self, other) {
+ /// (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0,
/// _ => true,
/// }
/// }
/// }
/// ```
+ ///
/// Creates a tag check combined with a match for a tuple of all
/// `selflike_args`, with an arm for each variant with fields, possibly an
/// arm for each fieldless variant (if `unify_fieldless_variants` is not
@@ -1349,7 +1367,7 @@ impl<'a> MethodDef<'a> {
// (Variant1, Variant1, ...) => Body1
// (Variant2, Variant2, ...) => Body2,
// ...
- // _ => ::core::intrinsics::unreachable()
+ // _ => ::core::intrinsics::unreachable(),
// }
let get_match_expr = |mut selflike_args: ThinVec<P<Expr>>| {
let match_arg = if selflike_args.len() == 1 {
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index 26f91b714..2d5043112 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -6,9 +6,10 @@ pub use Ty::*;
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind};
use rustc_expand::base::ExtCtxt;
-use rustc_span::source_map::{respan, DUMMY_SP};
+use rustc_span::source_map::respan;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
+use rustc_span::DUMMY_SP;
use thin_vec::ThinVec;
/// A path, e.g., `::std::option::Option::<i32>` (global). Has support
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index 92da0c069..8c2fa6ee9 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -108,7 +108,7 @@ pub fn expand_env<'cx>(
return DummyResult::any(sp);
}
- Some(value) => cx.expr_str(sp, value),
+ Some(value) => cx.expr_str(span, value),
};
MacEager::expr(e)
}
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 1238773d5..fde427033 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -647,6 +647,27 @@ pub(crate) struct FormatPositionalMismatch {
}
#[derive(Diagnostic)]
+#[diag(builtin_macros_format_redundant_args)]
+pub(crate) struct FormatRedundantArgs {
+ #[primary_span]
+ pub(crate) span: MultiSpan,
+ pub(crate) n: usize,
+
+ #[note]
+ pub(crate) note: MultiSpan,
+
+ #[subdiagnostic]
+ pub(crate) sugg: Option<FormatRedundantArgsSugg>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(builtin_macros_suggestion, applicability = "machine-applicable")]
+pub(crate) struct FormatRedundantArgsSugg {
+ #[suggestion_part(code = "")]
+ pub(crate) spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
#[diag(builtin_macros_test_case_non_item)]
pub(crate) struct TestCaseNonItem {
#[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 8397b5e42..214fed8e2 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -1,3 +1,4 @@
+use parse::Position::ArgumentNamed;
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{token, StmtKind};
@@ -7,7 +8,9 @@ use rustc_ast::{
FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
};
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, MultiSpan, PResult, SingleLabelManySpans};
+use rustc_errors::{
+ Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, PResult, SingleLabelManySpans,
+};
use rustc_expand::base::{self, *};
use rustc_parse_format as parse;
use rustc_span::symbol::{Ident, Symbol};
@@ -73,7 +76,9 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
let first_token = &p.token;
- let fmtstr = if let token::Literal(lit) = first_token.kind && matches!(lit.kind, token::Str | token::StrRaw(_)) {
+ let fmtstr = if let token::Literal(lit) = first_token.kind
+ && matches!(lit.kind, token::Str | token::StrRaw(_))
+ {
// This allows us to properly handle cases when the first comma
// after the format string is mistakenly replaced with any operator,
// which cause the expression parser to eat too much tokens.
@@ -176,7 +181,7 @@ fn make_format_args(
&& block.stmts.len() == 1
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
&& let ExprKind::Path(None, path) = &expr.kind
- && path.is_potential_trivial_const_arg()
+ && path.is_potential_trivial_const_arg()
{
err.multipart_suggestion(
"quote your inlined format argument to use as string literal",
@@ -184,7 +189,7 @@ fn make_format_args(
(unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
(unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
],
- Applicability::MaybeIncorrect,
+ Applicability::MaybeIncorrect,
);
} else {
let sugg_fmt = match args.explicit_args().len() {
@@ -257,8 +262,13 @@ fn make_format_args(
if let Some(note) = err.note {
e.note_ = Some(errors::InvalidFormatStringNote { note });
}
- if let Some((label, span)) = err.secondary_label && is_source_literal {
- e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } );
+ if let Some((label, span)) = err.secondary_label
+ && is_source_literal
+ {
+ e.label_ = Some(errors::InvalidFormatStringLabel {
+ span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)),
+ label,
+ });
}
match err.suggestion {
parse::Suggestion::None => {}
@@ -357,8 +367,8 @@ fn make_format_args(
let mut unfinished_literal = String::new();
let mut placeholder_index = 0;
- for piece in pieces {
- match piece {
+ for piece in &pieces {
+ match *piece {
parse::Piece::String(s) => {
unfinished_literal.push_str(s);
}
@@ -506,7 +516,17 @@ fn make_format_args(
// If there's a lot of unused arguments,
// let's check if this format arguments looks like another syntax (printf / shell).
let detect_foreign_fmt = unused.len() > args.explicit_args().len() / 2;
- report_missing_placeholders(ecx, unused, detect_foreign_fmt, str_style, fmt_str, fmt_span);
+ report_missing_placeholders(
+ ecx,
+ unused,
+ &used,
+ &args,
+ &pieces,
+ detect_foreign_fmt,
+ str_style,
+ fmt_str,
+ fmt_span,
+ );
}
// Only check for unused named argument names if there are no other errors to avoid causing
@@ -573,6 +593,9 @@ fn invalid_placeholder_type_error(
fn report_missing_placeholders(
ecx: &mut ExtCtxt<'_>,
unused: Vec<(Span, bool)>,
+ used: &[bool],
+ args: &FormatArguments,
+ pieces: &[parse::Piece<'_>],
detect_foreign_fmt: bool,
str_style: Option<usize>,
fmt_str: &str,
@@ -591,6 +614,26 @@ fn report_missing_placeholders(
})
};
+ let placeholders = pieces
+ .iter()
+ .filter_map(|piece| {
+ if let parse::Piece::NextArgument(argument) = piece && let ArgumentNamed(binding) = argument.position {
+ let span = fmt_span.from_inner(InnerSpan::new(argument.position_span.start, argument.position_span.end));
+ Some((span, binding))
+ } else { None }
+ })
+ .collect::<Vec<_>>();
+
+ if !placeholders.is_empty() {
+ if let Some(mut new_diag) =
+ report_redundant_format_arguments(ecx, &args, used, placeholders)
+ {
+ diag.cancel();
+ new_diag.emit();
+ return;
+ }
+ }
+
// Used to ensure we only report translations for *one* kind of foreign format.
let mut found_foreign = false;
@@ -678,6 +721,76 @@ fn report_missing_placeholders(
diag.emit();
}
+/// This function detects and reports unused format!() arguments that are
+/// redundant due to implicit captures (e.g. `format!("{x}", x)`).
+fn report_redundant_format_arguments<'a>(
+ ecx: &mut ExtCtxt<'a>,
+ args: &FormatArguments,
+ used: &[bool],
+ placeholders: Vec<(Span, &str)>,
+) -> Option<DiagnosticBuilder<'a, ErrorGuaranteed>> {
+ let mut fmt_arg_indices = vec![];
+ let mut args_spans = vec![];
+ let mut fmt_spans = vec![];
+
+ for (i, unnamed_arg) in args.unnamed_args().iter().enumerate().rev() {
+ let Some(ty) = unnamed_arg.expr.to_ty() else { continue };
+ let Some(argument_binding) = ty.kind.is_simple_path() else { continue };
+ let argument_binding = argument_binding.as_str();
+
+ if used[i] {
+ continue;
+ }
+
+ let matching_placeholders = placeholders
+ .iter()
+ .filter(|(_, inline_binding)| argument_binding == *inline_binding)
+ .map(|(span, _)| span)
+ .collect::<Vec<_>>();
+
+ if !matching_placeholders.is_empty() {
+ fmt_arg_indices.push(i);
+ args_spans.push(unnamed_arg.expr.span);
+ for span in &matching_placeholders {
+ if fmt_spans.contains(*span) {
+ continue;
+ }
+ fmt_spans.push(**span);
+ }
+ }
+ }
+
+ if !args_spans.is_empty() {
+ let multispan = MultiSpan::from(fmt_spans);
+ let mut suggestion_spans = vec![];
+
+ for (arg_span, fmt_arg_idx) in args_spans.iter().zip(fmt_arg_indices.iter()) {
+ let span = if fmt_arg_idx + 1 == args.explicit_args().len() {
+ *arg_span
+ } else {
+ arg_span.until(args.explicit_args()[*fmt_arg_idx + 1].expr.span)
+ };
+
+ suggestion_spans.push(span);
+ }
+
+ let sugg = if args.named_args().len() == 0 {
+ Some(errors::FormatRedundantArgsSugg { spans: suggestion_spans })
+ } else {
+ None
+ };
+
+ return Some(ecx.create_err(errors::FormatRedundantArgs {
+ n: args_spans.len(),
+ span: MultiSpan::from(args_spans),
+ note: multispan,
+ sugg,
+ }));
+ }
+
+ None
+}
+
/// Handle invalid references to positional arguments. Output different
/// errors for the case where all arguments are positional and for when
/// there are named arguments or numbered positional arguments in the
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 1bec00add..33392edf0 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -24,20 +24,22 @@ pub fn expand(
// Allow using `#[global_allocator]` on an item statement
// FIXME - if we get deref patterns, use them to reduce duplication here
- let (item, is_stmt, ty_span) =
- if let Annotatable::Item(item) = &item
- && let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind
- {
- (item, false, ecx.with_def_site_ctxt(ty.span))
- } else if let Annotatable::Stmt(stmt) = &item
- && let StmtKind::Item(item) = &stmt.kind
- && let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind
- {
- (item, true, ecx.with_def_site_ctxt(ty.span))
- } else {
- ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocMustStatics{span: item.span()});
- return vec![orig_item];
- };
+ let (item, is_stmt, ty_span) = if let Annotatable::Item(item) = &item
+ && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind
+ {
+ (item, false, ecx.with_def_site_ctxt(ty.span))
+ } else if let Annotatable::Stmt(stmt) = &item
+ && let StmtKind::Item(item) = &stmt.kind
+ && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind
+ {
+ (item, true, ecx.with_def_site_ctxt(ty.span))
+ } else {
+ ecx.sess
+ .parse_sess
+ .span_diagnostic
+ .emit_err(errors::AllocMustStatics { span: item.span() });
+ return vec![orig_item];
+ };
// Generate a bunch of new items using the AllocFnFactory
let span = ecx.with_def_site_ctxt(item.span);
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index ebf1448f5..d84742c9b 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -1,6 +1,9 @@
//! This crate contains implementations of built-in macros and other code generating facilities
//! injecting code into the crate before it is lowered to HIR.
+#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
#![feature(box_patterns)]
@@ -71,33 +74,35 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
}
register_bang! {
+ // tidy-alphabetical-start
asm: asm::expand_asm,
assert: assert::expand_assert,
cfg: cfg::expand_cfg,
column: source_util::expand_column,
compile_error: compile_error::expand_compile_error,
+ concat: concat::expand_concat,
concat_bytes: concat_bytes::expand_concat_bytes,
concat_idents: concat_idents::expand_concat_idents,
- concat: concat::expand_concat,
+ const_format_args: format::expand_format_args,
+ core_panic: edition_panic::expand_panic,
env: env::expand_env,
file: source_util::expand_file,
- format_args_nl: format::expand_format_args_nl,
format_args: format::expand_format_args,
- const_format_args: format::expand_format_args,
+ format_args_nl: format::expand_format_args_nl,
global_asm: asm::expand_global_asm,
+ include: source_util::expand_include,
include_bytes: source_util::expand_include_bytes,
include_str: source_util::expand_include_str,
- include: source_util::expand_include,
line: source_util::expand_line,
log_syntax: log_syntax::expand_log_syntax,
module_path: source_util::expand_mod,
option_env: env::expand_option_env,
- core_panic: edition_panic::expand_panic,
std_panic: edition_panic::expand_panic,
- unreachable: edition_panic::expand_unreachable,
stringify: source_util::expand_stringify,
trace_macros: trace_macros::expand_trace_macros,
type_ascribe: type_ascribe::expand_type_ascribe,
+ unreachable: edition_panic::expand_unreachable,
+ // tidy-alphabetical-end
}
register_attr! {
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 953d957a4..f7bafa285 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -61,9 +61,14 @@ pub fn expand_file(
let topmost = cx.expansion_cause().unwrap_or(sp);
let loc = cx.source_map().lookup_char_pos(topmost.lo());
- base::MacEager::expr(
- cx.expr_str(topmost, Symbol::intern(&loc.file.name.prefer_remapped().to_string_lossy())),
- )
+
+ use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
+ base::MacEager::expr(cx.expr_str(
+ topmost,
+ Symbol::intern(
+ &loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
+ ),
+ ))
}
pub fn expand_stringify(
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 1580a6f6d..6d55603c7 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -35,11 +35,13 @@ pub fn expand_test_case(
let sp = ecx.with_def_site_ctxt(attr_sp);
let (mut item, is_stmt) = match anno_item {
Annotatable::Item(item) => (item, false),
- Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
- (i, true)
- } else {
- unreachable!()
- },
+ Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => {
+ if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
+ (i, true)
+ } else {
+ unreachable!()
+ }
+ }
_ => {
ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() });
return vec![];
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 53ff089d7..c7999a226 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -169,31 +169,17 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> {
}
}
-// Beware, this is duplicated in librustc_passes/entry.rs (with
-// `rustc_hir::Item`), so make sure to keep them in sync.
-fn entry_point_type(item: &ast::Item, depth: usize) -> EntryPointType {
+fn entry_point_type(item: &ast::Item, at_root: bool) -> EntryPointType {
match item.kind {
ast::ItemKind::Fn(..) => {
- if attr::contains_name(&item.attrs, sym::start) {
- EntryPointType::Start
- } else if attr::contains_name(&item.attrs, sym::rustc_main) {
- EntryPointType::RustcMainAttr
- } else if item.ident.name == sym::main {
- if depth == 0 {
- // This is a top-level function so can be 'main'
- EntryPointType::MainNamed
- } else {
- EntryPointType::OtherMain
- }
- } else {
- EntryPointType::None
- }
+ rustc_ast::entry::entry_point_type(&item.attrs, at_root, Some(item.ident.name))
}
_ => EntryPointType::None,
}
}
+
/// A folder used to remove any entry points (like fn main) because the harness
-/// generator will provide its own
+/// coroutine will provide its own
struct EntryPointCleaner<'a> {
// Current depth in the ast
sess: &'a Session,
@@ -210,7 +196,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
// Remove any #[rustc_main] or #[start] from the AST so it doesn't
// clash with the one we're going to add, but mark it as
// #[allow(dead_code)] to avoid printing warnings.
- let item = match entry_point_type(&item, self.depth) {
+ let item = match entry_point_type(&item, self.depth == 0) {
EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
let allow_dead_code = attr::mk_attr_nested_word(