mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #140748 - m-ou-se:super-format-args3, r=jdonszelmann
Allow storing `format_args!()` in variable Fixes https://github.com/rust-lang/rust/issues/92698 Tracking issue for super let: https://github.com/rust-lang/rust/issues/139076 Tracking issue for format_args: https://github.com/rust-lang/rust/issues/99012 This change allows: ```rust let name = "world"; let f = format_args!("hello {name}!"); // New: Store format_args!() for later! println!("{f}"); ``` This will need an FCP. This implementation makes use of `super let`, which is unstable and might not exist in the future in its current form. However, it is entirely reasonable to assume future Rust will always have _a_ way of expressing temporary lifetimes like this, since the (stable) `pin!()` macro needs this too. (This was also the motivation for merging https://github.com/rust-lang/rust/pull/139114.) (This is a second version of https://github.com/rust-lang/rust/pull/139135)
This commit is contained in:
@@ -2289,12 +2289,12 @@ pub(super) fn expr_array_ref(
|
||||
span: Span,
|
||||
elements: &'hir [hir::Expr<'hir>],
|
||||
) -> hir::Expr<'hir> {
|
||||
let addrof = hir::ExprKind::AddrOf(
|
||||
hir::BorrowKind::Ref,
|
||||
hir::Mutability::Not,
|
||||
self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))),
|
||||
);
|
||||
self.expr(span, addrof)
|
||||
let array = self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements)));
|
||||
self.expr_ref(span, array)
|
||||
}
|
||||
|
||||
pub(super) fn expr_ref(&mut self, span: Span, expr: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
|
||||
self.expr(span, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr))
|
||||
}
|
||||
|
||||
pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use core::ops::ControlFlow;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir as hir;
|
||||
@@ -476,77 +474,52 @@ fn expand_format_args<'hir>(
|
||||
return hir::ExprKind::Call(new, new_args);
|
||||
}
|
||||
|
||||
// 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 Argument cannot be kept across yield points.
|
||||
//
|
||||
// This is an optimization, speeding up compilation about 1-2% in some cases.
|
||||
// See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609
|
||||
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 arguments.is_empty() {
|
||||
let (let_statements, args) = if arguments.is_empty() {
|
||||
// Generate:
|
||||
// &<core::fmt::Argument>::none()
|
||||
// []
|
||||
(vec![], ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(&[]))))
|
||||
} else if argmap.len() == 1 && arguments.len() == 1 {
|
||||
// Only one argument, so we don't need to make the `args` tuple.
|
||||
//
|
||||
// Note:
|
||||
// `none()` just returns `[]`. We use `none()` rather than `[]` to limit the lifetime.
|
||||
//
|
||||
// This makes sure that this still fails to compile, even when the argument is inlined:
|
||||
//
|
||||
// ```
|
||||
// let f = format_args!("{}", "a");
|
||||
// println!("{f}"); // error E0716
|
||||
// ```
|
||||
//
|
||||
// Cases where keeping the object around is allowed, such as `format_args!("a")`,
|
||||
// are handled above by the `allow_const` case.
|
||||
let none_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatArgument,
|
||||
sym::none,
|
||||
));
|
||||
let none = ctx.expr_call(macsp, none_fn, &[]);
|
||||
ctx.expr(macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, none))
|
||||
} else if use_simple_array {
|
||||
// Generate:
|
||||
// &[
|
||||
// <core::fmt::Argument>::new_display(&arg0),
|
||||
// <core::fmt::Argument>::new_lower_hex(&arg1),
|
||||
// <core::fmt::Argument>::new_debug(&arg2),
|
||||
// …
|
||||
// ]
|
||||
let elements = ctx.arena.alloc_from_iter(arguments.iter().zip(argmap).map(
|
||||
|(arg, ((_, ty), placeholder_span))| {
|
||||
// super let args = [<core::fmt::Argument>::new_display(&arg)];
|
||||
let args = ctx.arena.alloc_from_iter(argmap.iter().map(
|
||||
|(&(arg_index, ty), &placeholder_span)| {
|
||||
let arg = &arguments[arg_index];
|
||||
let placeholder_span =
|
||||
placeholder_span.unwrap_or(arg.expr.span).with_ctxt(macsp.ctxt());
|
||||
let arg_span = match arg.kind {
|
||||
FormatArgumentKind::Captured(_) => placeholder_span,
|
||||
_ => arg.expr.span.with_ctxt(macsp.ctxt()),
|
||||
};
|
||||
let arg = ctx.lower_expr(&arg.expr);
|
||||
let ref_arg = ctx.arena.alloc(ctx.expr(
|
||||
arg_span,
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg),
|
||||
));
|
||||
let ref_arg = ctx.arena.alloc(ctx.expr_ref(arg.span.with_ctxt(macsp.ctxt()), arg));
|
||||
make_argument(ctx, placeholder_span, ref_arg, ty)
|
||||
},
|
||||
));
|
||||
ctx.expr_array_ref(macsp, elements)
|
||||
} else {
|
||||
// Generate:
|
||||
// &match (&arg0, &arg1, &…) {
|
||||
// args => [
|
||||
// <core::fmt::Argument>::new_display(args.0),
|
||||
// <core::fmt::Argument>::new_lower_hex(args.1),
|
||||
// <core::fmt::Argument>::new_debug(args.0),
|
||||
// …
|
||||
// ]
|
||||
// }
|
||||
let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
|
||||
let args_ident = Ident::new(sym::args, macsp);
|
||||
let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
|
||||
let let_statement = ctx.stmt_super_let_pat(macsp, args_pat, Some(args));
|
||||
(vec![let_statement], ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id)))
|
||||
} else {
|
||||
// Generate:
|
||||
// super let args = (&arg0, &arg1, &…);
|
||||
let args_ident = Ident::new(sym::args, macsp);
|
||||
let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
|
||||
let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| {
|
||||
let arg_expr = ctx.lower_expr(&arg.expr);
|
||||
ctx.expr(
|
||||
arg.expr.span.with_ctxt(macsp.ctxt()),
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr),
|
||||
)
|
||||
}));
|
||||
let args_tuple = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Tup(elements)));
|
||||
let let_statement_1 = ctx.stmt_super_let_pat(macsp, args_pat, Some(args_tuple));
|
||||
|
||||
// Generate:
|
||||
// super let args = [
|
||||
// <core::fmt::Argument>::new_display(args.0),
|
||||
// <core::fmt::Argument>::new_lower_hex(args.1),
|
||||
// <core::fmt::Argument>::new_debug(args.0),
|
||||
// …
|
||||
// ];
|
||||
let args = ctx.arena.alloc_from_iter(argmap.iter().map(
|
||||
|(&(arg_index, ty), &placeholder_span)| {
|
||||
let arg = &arguments[arg_index];
|
||||
@@ -567,58 +540,47 @@ fn expand_format_args<'hir>(
|
||||
make_argument(ctx, placeholder_span, arg, ty)
|
||||
},
|
||||
));
|
||||
let elements = ctx.arena.alloc_from_iter(arguments.iter().map(|arg| {
|
||||
let arg_expr = ctx.lower_expr(&arg.expr);
|
||||
ctx.expr(
|
||||
arg.expr.span.with_ctxt(macsp.ctxt()),
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr),
|
||||
)
|
||||
}));
|
||||
let args_tuple = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Tup(elements)));
|
||||
let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
|
||||
let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]);
|
||||
let match_expr = ctx.arena.alloc(ctx.expr_match(
|
||||
macsp,
|
||||
args_tuple,
|
||||
match_arms,
|
||||
hir::MatchSource::FormatArgs,
|
||||
));
|
||||
ctx.expr(
|
||||
macsp,
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, match_expr),
|
||||
let args = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
|
||||
let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
|
||||
let let_statement_2 = ctx.stmt_super_let_pat(macsp, args_pat, Some(args));
|
||||
(
|
||||
vec![let_statement_1, let_statement_2],
|
||||
ctx.arena.alloc(ctx.expr_ident_mut(macsp, args_ident, args_hir_id)),
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(format_options) = format_options {
|
||||
// Generate:
|
||||
// &args
|
||||
let args = ctx.expr_ref(macsp, args);
|
||||
|
||||
let call = if let Some(format_options) = format_options {
|
||||
// Generate:
|
||||
// <core::fmt::Arguments>::new_v1_formatted(
|
||||
// lit_pieces,
|
||||
// args,
|
||||
// format_options,
|
||||
// unsafe { ::core::fmt::UnsafeArg::new() }
|
||||
// )
|
||||
// unsafe {
|
||||
// <core::fmt::Arguments>::new_v1_formatted(
|
||||
// lit_pieces,
|
||||
// args,
|
||||
// format_options,
|
||||
// )
|
||||
// }
|
||||
let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatArguments,
|
||||
sym::new_v1_formatted,
|
||||
));
|
||||
let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
|
||||
macsp,
|
||||
hir::LangItem::FormatUnsafeArg,
|
||||
sym::new,
|
||||
));
|
||||
let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]);
|
||||
let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options]);
|
||||
let call = ctx.expr_call(macsp, new_v1_formatted, args);
|
||||
let hir_id = ctx.next_id();
|
||||
let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block {
|
||||
stmts: &[],
|
||||
expr: Some(unsafe_arg_new_call),
|
||||
hir_id,
|
||||
rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
|
||||
span: macsp,
|
||||
targeted_by_break: false,
|
||||
}));
|
||||
let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]);
|
||||
hir::ExprKind::Call(new_v1_formatted, args)
|
||||
hir::ExprKind::Block(
|
||||
ctx.arena.alloc(hir::Block {
|
||||
stmts: &[],
|
||||
expr: Some(call),
|
||||
hir_id,
|
||||
rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
|
||||
span: macsp,
|
||||
targeted_by_break: false,
|
||||
}),
|
||||
None,
|
||||
)
|
||||
} else {
|
||||
// Generate:
|
||||
// <core::fmt::Arguments>::new_v1(
|
||||
@@ -632,37 +594,23 @@ fn expand_format_args<'hir>(
|
||||
));
|
||||
let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]);
|
||||
hir::ExprKind::Call(new_v1, new_args)
|
||||
};
|
||||
|
||||
if !let_statements.is_empty() {
|
||||
// Generate:
|
||||
// {
|
||||
// super let …
|
||||
// super let …
|
||||
// <core::fmt::Arguments>::new_…(…)
|
||||
// }
|
||||
let call = ctx.arena.alloc(ctx.expr(macsp, call));
|
||||
let block = ctx.block_all(macsp, ctx.arena.alloc_from_iter(let_statements), Some(call));
|
||||
hir::ExprKind::Block(block, None)
|
||||
} else {
|
||||
call
|
||||
}
|
||||
}
|
||||
|
||||
fn may_contain_yield_point(e: &ast::Expr) -> bool {
|
||||
struct MayContainYieldPoint;
|
||||
|
||||
impl Visitor<'_> for MayContainYieldPoint {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn visit_expr(&mut self, e: &ast::Expr) -> ControlFlow<()> {
|
||||
if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
visit::walk_expr(self, e)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mac_call(&mut self, _: &ast::MacCall) -> ControlFlow<()> {
|
||||
// Macros should be expanded at this point.
|
||||
unreachable!("unexpanded macro in ast lowering");
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, _: &ast::Item) -> ControlFlow<()> {
|
||||
// Do not recurse into nested items.
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
MayContainYieldPoint.visit_expr(e).is_break()
|
||||
}
|
||||
|
||||
fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {
|
||||
for piece in template {
|
||||
let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
|
||||
|
||||
@@ -2292,6 +2292,26 @@ fn stmt_let_pat(
|
||||
self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))
|
||||
}
|
||||
|
||||
fn stmt_super_let_pat(
|
||||
&mut self,
|
||||
span: Span,
|
||||
pat: &'hir hir::Pat<'hir>,
|
||||
init: Option<&'hir hir::Expr<'hir>>,
|
||||
) -> hir::Stmt<'hir> {
|
||||
let hir_id = self.next_id();
|
||||
let local = hir::LetStmt {
|
||||
super_: Some(span),
|
||||
hir_id,
|
||||
init,
|
||||
pat,
|
||||
els: None,
|
||||
source: hir::LocalSource::Normal,
|
||||
span: self.lower_span(span),
|
||||
ty: None,
|
||||
};
|
||||
self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))
|
||||
}
|
||||
|
||||
fn block_expr(&mut self, expr: &'hir hir::Expr<'hir>) -> &'hir hir::Block<'hir> {
|
||||
self.block_all(expr.span, &[], Some(expr))
|
||||
}
|
||||
|
||||
@@ -3201,14 +3201,6 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
let expr_ty: Option<Ty<'_>> =
|
||||
visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs());
|
||||
|
||||
let is_format_arguments_item = if let Some(expr_ty) = expr_ty
|
||||
&& let ty::Adt(adt, _) = expr_ty.kind()
|
||||
{
|
||||
self.infcx.tcx.is_lang_item(adt.did(), LangItem::FormatArguments)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if visitor.found == 0
|
||||
&& stmt.span.contains(proper_span)
|
||||
&& let Some(p) = sm.span_to_margin(stmt.span)
|
||||
@@ -3236,25 +3228,17 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
""
|
||||
};
|
||||
|
||||
if !is_format_arguments_item {
|
||||
let addition = format!(
|
||||
"let {}binding = {};\n{}",
|
||||
mutability,
|
||||
s,
|
||||
" ".repeat(p)
|
||||
);
|
||||
err.multipart_suggestion_verbose(
|
||||
msg,
|
||||
vec![
|
||||
(stmt.span.shrink_to_lo(), addition),
|
||||
(proper_span, "binding".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.note("the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used");
|
||||
err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>");
|
||||
}
|
||||
let addition =
|
||||
format!("let {}binding = {};\n{}", mutability, s, " ".repeat(p));
|
||||
err.multipart_suggestion_verbose(
|
||||
msg,
|
||||
vec![
|
||||
(stmt.span.shrink_to_lo(), addition),
|
||||
(proper_span, "binding".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
suggested = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -183,38 +183,6 @@ pub(super) const fn as_u16(&self) -> Option<u16> {
|
||||
ArgumentType::Placeholder { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by `format_args` when all arguments are gone after inlining,
|
||||
/// when using `&[]` would incorrectly allow for a bigger lifetime.
|
||||
///
|
||||
/// This fails without format argument inlining, and that shouldn't be different
|
||||
/// when the argument is inlined:
|
||||
///
|
||||
/// ```compile_fail,E0716
|
||||
/// let f = format_args!("{}", "a");
|
||||
/// println!("{f}");
|
||||
/// ```
|
||||
#[inline]
|
||||
pub const fn none() -> [Self; 0] {
|
||||
[]
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct represents the unsafety of constructing an `Arguments`.
|
||||
/// It exists, rather than an unsafe function, in order to simplify the expansion
|
||||
/// of `format_args!(..)` and reduce the scope of the `unsafe` block.
|
||||
#[lang = "format_unsafe_arg"]
|
||||
pub struct UnsafeArg {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl UnsafeArg {
|
||||
/// See documentation where `UnsafeArg` is required to know when it is safe to
|
||||
/// create and use `UnsafeArg`.
|
||||
#[inline]
|
||||
pub const unsafe fn new() -> Self {
|
||||
Self { _private: () }
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by the format_args!() macro to create a fmt::Arguments object.
|
||||
@@ -248,8 +216,7 @@ pub fn new_v1<const P: usize, const A: usize>(
|
||||
|
||||
/// Specifies nonstandard formatting parameters.
|
||||
///
|
||||
/// An `rt::UnsafeArg` is required because the following invariants must be held
|
||||
/// in order for this function to be safe:
|
||||
/// SAFETY: the following invariants must be held:
|
||||
/// 1. The `pieces` slice must be at least as long as `fmt`.
|
||||
/// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`.
|
||||
/// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`.
|
||||
@@ -261,11 +228,10 @@ pub fn new_v1<const P: usize, const A: usize>(
|
||||
/// const _: () = if false { panic!("a {:1}", "a") };
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn new_v1_formatted(
|
||||
pub unsafe fn new_v1_formatted(
|
||||
pieces: &'a [&'static str],
|
||||
args: &'a [rt::Argument<'a>],
|
||||
fmt: &'a [rt::Placeholder],
|
||||
_unsafe_arg: rt::UnsafeArg,
|
||||
) -> Arguments<'a> {
|
||||
Arguments { pieces, fmt: Some(fmt), args }
|
||||
}
|
||||
|
||||
@@ -2,6 +2,21 @@
|
||||
mod float;
|
||||
mod num;
|
||||
|
||||
#[test]
|
||||
fn test_lifetime() {
|
||||
// Trigger all different forms of expansion,
|
||||
// and check that each of them can be stored as a variable.
|
||||
let a = format_args!("hello");
|
||||
let a = format_args!("hello {a}");
|
||||
let a = format_args!("hello {a:1}");
|
||||
let a = format_args!("hello {a} {a:?}");
|
||||
assert_eq!(a.to_string(), "hello hello hello hello hello hello hello");
|
||||
|
||||
// Without arguments, it should also work in consts.
|
||||
const A: std::fmt::Arguments<'static> = format_args!("hello");
|
||||
assert_eq!(A.to_string(), "hello");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format_flags() {
|
||||
// No residual flags left by pointer formatting
|
||||
|
||||
@@ -9,28 +9,35 @@ if let StmtKind::Let(local) = stmt.kind
|
||||
&& let ExprKind::Call(func, args) = e.kind
|
||||
&& paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args.len() == 1
|
||||
&& let ExprKind::Call(func1, args1) = args[0].kind
|
||||
&& paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args1.len() == 2
|
||||
&& let ExprKind::Block(block1, None) = args[0].kind
|
||||
&& block1.stmts.len() == 1
|
||||
&& let StmtKind::Let(local1) = block1.stmts[0].kind
|
||||
&& let Some(init1) = local1.init
|
||||
&& let ExprKind::Array(elements) = init1.kind
|
||||
&& elements.len() == 1
|
||||
&& let ExprKind::Call(func1, args1) = elements[0].kind
|
||||
&& paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args1.len() == 1
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
|
||||
&& let ExprKind::Array(elements) = inner.kind
|
||||
&& elements.len() == 2
|
||||
&& let ExprKind::Lit(ref lit) = elements[0].kind
|
||||
&& let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind
|
||||
&& name.as_str() == "args"
|
||||
&& let Some(trailing_expr) = block1.expr
|
||||
&& let ExprKind::Call(func2, args2) = trailing_expr.kind
|
||||
&& paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args2.len() == 2
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
|
||||
&& let ExprKind::Array(elements1) = inner1.kind
|
||||
&& elements1.len() == 2
|
||||
&& let ExprKind::Lit(ref lit) = elements1[0].kind
|
||||
&& let LitKind::Str(s, _) = lit.node
|
||||
&& s.as_str() == ""
|
||||
&& let ExprKind::Lit(ref lit1) = elements[1].kind
|
||||
&& let ExprKind::Lit(ref lit1) = elements1[1].kind
|
||||
&& let LitKind::Str(s1, _) = lit1.node
|
||||
&& s1.as_str() == "\n"
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
|
||||
&& let ExprKind::Array(elements1) = inner1.kind
|
||||
&& elements1.len() == 1
|
||||
&& let ExprKind::Call(func2, args2) = elements1[0].kind
|
||||
&& paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args2.len() == 1
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
|
||||
&& block.expr.is_none()
|
||||
&& let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind
|
||||
&& name.as_str() == "print_text"
|
||||
&& let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
|
||||
&& name1.as_str() == "print_text"
|
||||
{
|
||||
// report your lint here
|
||||
}
|
||||
|
||||
@@ -19,25 +19,32 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
|
||||
&& let ExprKind::Call(func, args) = e1.kind
|
||||
&& paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args.len() == 1
|
||||
&& let ExprKind::Call(func1, args1) = args[0].kind
|
||||
&& paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args1.len() == 2
|
||||
&& let ExprKind::Block(block2, None) = args[0].kind
|
||||
&& block2.stmts.len() == 1
|
||||
&& let StmtKind::Let(local) = block2.stmts[0].kind
|
||||
&& let Some(init) = local.init
|
||||
&& let ExprKind::Array(elements) = init.kind
|
||||
&& elements.len() == 1
|
||||
&& let ExprKind::Call(func1, args1) = elements[0].kind
|
||||
&& paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args1.len() == 1
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
|
||||
&& let ExprKind::Array(elements) = inner.kind
|
||||
&& elements.len() == 2
|
||||
&& let ExprKind::Lit(ref lit2) = elements[0].kind
|
||||
&& let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
|
||||
&& name1.as_str() == "args"
|
||||
&& let Some(trailing_expr) = block2.expr
|
||||
&& let ExprKind::Call(func2, args2) = trailing_expr.kind
|
||||
&& paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args2.len() == 2
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
|
||||
&& let ExprKind::Array(elements1) = inner1.kind
|
||||
&& elements1.len() == 2
|
||||
&& let ExprKind::Lit(ref lit2) = elements1[0].kind
|
||||
&& let LitKind::Str(s, _) = lit2.node
|
||||
&& s.as_str() == ""
|
||||
&& let ExprKind::Lit(ref lit3) = elements[1].kind
|
||||
&& let ExprKind::Lit(ref lit3) = elements1[1].kind
|
||||
&& let LitKind::Str(s1, _) = lit3.node
|
||||
&& s1.as_str() == "\n"
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
|
||||
&& let ExprKind::Array(elements1) = inner1.kind
|
||||
&& elements1.len() == 1
|
||||
&& let ExprKind::Call(func2, args2) = elements1[0].kind
|
||||
&& paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
|
||||
&& args2.len() == 1
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
|
||||
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
|
||||
&& block1.expr.is_none()
|
||||
&& block.expr.is_none()
|
||||
{
|
||||
|
||||
@@ -154,7 +154,6 @@ fn main() {
|
||||
});
|
||||
|
||||
let _ = [0]
|
||||
//~^ suspicious_map
|
||||
.into_iter()
|
||||
.inspect(|&x| {
|
||||
//~^ manual_inspect
|
||||
|
||||
@@ -165,7 +165,6 @@ macro_rules! maybe_ret {
|
||||
});
|
||||
|
||||
let _ = [0]
|
||||
//~^ suspicious_map
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
//~^ manual_inspect
|
||||
|
||||
@@ -157,25 +157,8 @@ LL |
|
||||
LL ~ println!("{}", x);
|
||||
|
|
||||
|
||||
error: this call to `map()` won't have an effect on the call to `count()`
|
||||
--> tests/ui/manual_inspect.rs:167:13
|
||||
|
|
||||
LL | let _ = [0]
|
||||
| _____________^
|
||||
LL | |
|
||||
LL | | .into_iter()
|
||||
LL | | .map(|x| {
|
||||
... |
|
||||
LL | | })
|
||||
LL | | .count();
|
||||
| |________________^
|
||||
|
|
||||
= help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect`
|
||||
= note: `-D clippy::suspicious-map` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]`
|
||||
|
||||
error: using `map` over `inspect`
|
||||
--> tests/ui/manual_inspect.rs:170:10
|
||||
--> tests/ui/manual_inspect.rs:169:10
|
||||
|
|
||||
LL | .map(|x| {
|
||||
| ^^^
|
||||
@@ -188,7 +171,7 @@ LL ~ println!("{}", x);
|
||||
|
|
||||
|
||||
error: using `map` over `inspect`
|
||||
--> tests/ui/manual_inspect.rs:203:30
|
||||
--> tests/ui/manual_inspect.rs:202:30
|
||||
|
|
||||
LL | if let Some(x) = Some(1).map(|x| { println!("{x}");
|
||||
| ^^^
|
||||
@@ -200,5 +183,5 @@ LL | // Do not collapse code into this comment
|
||||
LL ~ }) {
|
||||
|
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
||||
@@ -305,7 +305,6 @@ ui/borrowck/issue-104639-lifetime-order.rs
|
||||
ui/borrowck/issue-10876.rs
|
||||
ui/borrowck/issue-109271-pass-self-into-closure.rs
|
||||
ui/borrowck/issue-111554.rs
|
||||
ui/borrowck/issue-114374-invalid-help-fmt-args.rs
|
||||
ui/borrowck/issue-11493.rs
|
||||
ui/borrowck/issue-115259-suggest-iter-mut.rs
|
||||
ui/borrowck/issue-119915-bad-clone-suggestion.rs
|
||||
|
||||
@@ -11,28 +11,29 @@
|
||||
let _9: ();
|
||||
let _10: ();
|
||||
let mut _11: std::fmt::Arguments<'_>;
|
||||
let mut _12: &[&str; 3];
|
||||
let _13: &[&str; 3];
|
||||
let _14: [&str; 3];
|
||||
let mut _15: &[core::fmt::rt::Argument<'_>; 2];
|
||||
let _16: &[core::fmt::rt::Argument<'_>; 2];
|
||||
let _17: [core::fmt::rt::Argument<'_>; 2];
|
||||
let mut _13: &std::boxed::Box<dyn std::fmt::Display>;
|
||||
let mut _14: &u32;
|
||||
let mut _16: core::fmt::rt::Argument<'_>;
|
||||
let mut _17: &std::boxed::Box<dyn std::fmt::Display>;
|
||||
let mut _18: core::fmt::rt::Argument<'_>;
|
||||
let mut _19: &std::boxed::Box<dyn std::fmt::Display>;
|
||||
let _20: &std::boxed::Box<dyn std::fmt::Display>;
|
||||
let mut _21: core::fmt::rt::Argument<'_>;
|
||||
let mut _22: &u32;
|
||||
let _23: &u32;
|
||||
let mut _25: bool;
|
||||
let mut _26: isize;
|
||||
let mut _27: isize;
|
||||
let mut _28: isize;
|
||||
+ let _29: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
|
||||
+ let _30: u32;
|
||||
let mut _19: &u32;
|
||||
let mut _20: &[&str; 3];
|
||||
let _21: &[&str; 3];
|
||||
let _22: [&str; 3];
|
||||
let mut _23: &[core::fmt::rt::Argument<'_>; 2];
|
||||
let _24: &[core::fmt::rt::Argument<'_>; 2];
|
||||
let mut _26: &std::boxed::Box<dyn std::fmt::Display>;
|
||||
let mut _27: &u32;
|
||||
let mut _28: bool;
|
||||
let mut _29: isize;
|
||||
let mut _30: isize;
|
||||
let mut _31: isize;
|
||||
+ let _32: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
|
||||
+ let _33: u32;
|
||||
scope 1 {
|
||||
- debug foo => _1;
|
||||
+ debug ((foo: Foo<T>).0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>) => _29;
|
||||
+ debug ((foo: Foo<T>).1: u32) => _30;
|
||||
+ debug ((foo: Foo<T>).0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>) => _32;
|
||||
+ debug ((foo: Foo<T>).1: u32) => _33;
|
||||
let _5: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>;
|
||||
scope 2 {
|
||||
debug x => _5;
|
||||
@@ -42,17 +43,29 @@
|
||||
scope 4 {
|
||||
debug x => _8;
|
||||
let _8: std::boxed::Box<dyn std::fmt::Display>;
|
||||
let mut _24: &[&str; 3];
|
||||
let _12: (&std::boxed::Box<dyn std::fmt::Display>, &u32);
|
||||
+ let _34: &std::boxed::Box<dyn std::fmt::Display>;
|
||||
+ let _35: &u32;
|
||||
scope 5 {
|
||||
- debug args => _12;
|
||||
+ debug ((args: (&Box<dyn std::fmt::Display>, &u32)).0: &std::boxed::Box<dyn std::fmt::Display>) => _34;
|
||||
+ debug ((args: (&Box<dyn std::fmt::Display>, &u32)).1: &u32) => _35;
|
||||
let _15: [core::fmt::rt::Argument<'_>; 2];
|
||||
scope 6 {
|
||||
debug args => _15;
|
||||
let mut _25: &[&str; 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bb0: {
|
||||
_25 = const false;
|
||||
_28 = const false;
|
||||
- StorageLive(_1);
|
||||
+ StorageLive(_29);
|
||||
+ StorageLive(_30);
|
||||
+ StorageLive(_32);
|
||||
+ StorageLive(_33);
|
||||
+ nop;
|
||||
StorageLive(_2);
|
||||
StorageLive(_3);
|
||||
@@ -66,77 +79,93 @@
|
||||
_2 = Result::<Box<dyn std::fmt::Display>, <T as Err>::Err>::Ok(move _3);
|
||||
StorageDead(_3);
|
||||
- _1 = Foo::<T> { x: move _2, y: const 7_u32 };
|
||||
+ _29 = move _2;
|
||||
+ _30 = const 7_u32;
|
||||
+ _32 = move _2;
|
||||
+ _33 = const 7_u32;
|
||||
+ nop;
|
||||
StorageDead(_2);
|
||||
StorageLive(_5);
|
||||
_25 = const true;
|
||||
_28 = const true;
|
||||
- _5 = move (_1.0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>);
|
||||
+ _5 = move _29;
|
||||
+ _5 = move _32;
|
||||
StorageLive(_6);
|
||||
- _6 = copy (_1.1: u32);
|
||||
+ _6 = copy _30;
|
||||
+ _6 = copy _33;
|
||||
_7 = discriminant(_5);
|
||||
switchInt(move _7) -> [0: bb2, otherwise: bb7];
|
||||
}
|
||||
|
||||
bb2: {
|
||||
StorageLive(_8);
|
||||
_25 = const false;
|
||||
_28 = const false;
|
||||
_8 = move ((_5 as Ok).0: std::boxed::Box<dyn std::fmt::Display>);
|
||||
StorageLive(_9);
|
||||
StorageLive(_10);
|
||||
StorageLive(_11);
|
||||
StorageLive(_12);
|
||||
- StorageLive(_12);
|
||||
+ StorageLive(_34);
|
||||
+ StorageLive(_35);
|
||||
+ nop;
|
||||
StorageLive(_13);
|
||||
_24 = const foo::<T>::promoted[0];
|
||||
_13 = &(*_24);
|
||||
_12 = &(*_13);
|
||||
_13 = &_8;
|
||||
StorageLive(_14);
|
||||
_14 = &_6;
|
||||
- _12 = (move _13, move _14);
|
||||
+ _34 = move _13;
|
||||
+ _35 = move _14;
|
||||
+ nop;
|
||||
StorageDead(_14);
|
||||
StorageDead(_13);
|
||||
StorageLive(_15);
|
||||
StorageLive(_16);
|
||||
StorageLive(_17);
|
||||
StorageLive(_18);
|
||||
StorageLive(_19);
|
||||
StorageLive(_20);
|
||||
_20 = &_8;
|
||||
_19 = &(*_20);
|
||||
_18 = core::fmt::rt::Argument::<'_>::new_display::<Box<dyn std::fmt::Display>>(move _19) -> [return: bb3, unwind unreachable];
|
||||
- _26 = deref_copy (_12.0: &std::boxed::Box<dyn std::fmt::Display>);
|
||||
+ _26 = deref_copy _34;
|
||||
_17 = &(*_26);
|
||||
_16 = core::fmt::rt::Argument::<'_>::new_display::<Box<dyn std::fmt::Display>>(move _17) -> [return: bb3, unwind unreachable];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
StorageDead(_19);
|
||||
StorageLive(_21);
|
||||
StorageLive(_22);
|
||||
StorageLive(_23);
|
||||
_23 = &_6;
|
||||
_22 = &(*_23);
|
||||
_21 = core::fmt::rt::Argument::<'_>::new_display::<u32>(move _22) -> [return: bb4, unwind unreachable];
|
||||
StorageDead(_17);
|
||||
StorageLive(_18);
|
||||
StorageLive(_19);
|
||||
- _27 = deref_copy (_12.1: &u32);
|
||||
+ _27 = deref_copy _35;
|
||||
_19 = &(*_27);
|
||||
_18 = core::fmt::rt::Argument::<'_>::new_display::<u32>(move _19) -> [return: bb4, unwind unreachable];
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageDead(_22);
|
||||
_17 = [move _18, move _21];
|
||||
StorageDead(_21);
|
||||
StorageDead(_19);
|
||||
_15 = [move _16, move _18];
|
||||
StorageDead(_18);
|
||||
_16 = &_17;
|
||||
_15 = &(*_16);
|
||||
_11 = core::fmt::rt::<impl Arguments<'_>>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable];
|
||||
StorageDead(_16);
|
||||
StorageLive(_20);
|
||||
StorageLive(_21);
|
||||
_25 = const foo::<T>::promoted[0];
|
||||
_21 = &(*_25);
|
||||
_20 = &(*_21);
|
||||
StorageLive(_23);
|
||||
StorageLive(_24);
|
||||
_24 = &_15;
|
||||
_23 = &(*_24);
|
||||
_11 = core::fmt::rt::<impl Arguments<'_>>::new_v1::<3, 2>(move _20, move _23) -> [return: bb5, unwind unreachable];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
StorageDead(_15);
|
||||
StorageDead(_12);
|
||||
StorageDead(_24);
|
||||
StorageDead(_23);
|
||||
StorageDead(_21);
|
||||
StorageDead(_20);
|
||||
_10 = _eprint(move _11) -> [return: bb6, unwind unreachable];
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageDead(_11);
|
||||
StorageDead(_23);
|
||||
StorageDead(_20);
|
||||
StorageDead(_17);
|
||||
StorageDead(_16);
|
||||
StorageDead(_13);
|
||||
StorageDead(_15);
|
||||
- StorageDead(_12);
|
||||
+ StorageDead(_34);
|
||||
+ StorageDead(_35);
|
||||
+ nop;
|
||||
StorageDead(_10);
|
||||
_9 = const ();
|
||||
StorageDead(_9);
|
||||
@@ -156,22 +185,22 @@
|
||||
|
||||
bb9: {
|
||||
StorageDead(_6);
|
||||
_26 = discriminant(_5);
|
||||
switchInt(move _26) -> [0: bb11, otherwise: bb13];
|
||||
_29 = discriminant(_5);
|
||||
switchInt(move _29) -> [0: bb11, otherwise: bb13];
|
||||
}
|
||||
|
||||
bb10: {
|
||||
_25 = const false;
|
||||
_28 = const false;
|
||||
StorageDead(_5);
|
||||
- StorageDead(_1);
|
||||
+ StorageDead(_29);
|
||||
+ StorageDead(_30);
|
||||
+ StorageDead(_32);
|
||||
+ StorageDead(_33);
|
||||
+ nop;
|
||||
return;
|
||||
}
|
||||
|
||||
bb11: {
|
||||
switchInt(copy _25) -> [0: bb10, otherwise: bb12];
|
||||
switchInt(copy _28) -> [0: bb10, otherwise: bb12];
|
||||
}
|
||||
|
||||
bb12: {
|
||||
|
||||
@@ -30,7 +30,7 @@ LL | drop(x);
|
||||
| ^ move out of `x` occurs here
|
||||
LL |
|
||||
LL | println!("{b}");
|
||||
| --- borrow later used here
|
||||
| - borrow later used here
|
||||
|
|
||||
help: if `T` implemented `Clone`, you could clone the value
|
||||
--> $DIR/clone-on-ref.rs:11:8
|
||||
@@ -57,7 +57,7 @@ LL | drop(x);
|
||||
| ^ move out of `x` occurs here
|
||||
LL |
|
||||
LL | println!("{b:?}");
|
||||
| ----- borrow later used here
|
||||
| - borrow later used here
|
||||
|
|
||||
note: if `A` implemented `Clone`, you could clone the value
|
||||
--> $DIR/clone-on-ref.rs:19:1
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn bar<'a>(_: std::fmt::Arguments<'a>) {}
|
||||
fn main() {
|
||||
let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
|
||||
//~^ ERROR temporary value dropped while borrowed
|
||||
|
||||
bar(x);
|
||||
|
||||
let foo = format_args!("{}", "hi");
|
||||
//~^ ERROR temporary value dropped while borrowed
|
||||
bar(foo);
|
||||
|
||||
let foo = format_args!("hi"); // no placeholder in arguments, so no error
|
||||
bar(foo);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/issue-114374-invalid-help-fmt-args.rs:5:13
|
||||
|
|
||||
LL | let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
|
||||
| |
|
||||
| creates a temporary value which is freed while still in use
|
||||
...
|
||||
LL | bar(x);
|
||||
| - borrow later used here
|
||||
|
|
||||
= note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/issue-114374-invalid-help-fmt-args.rs:10:15
|
||||
|
|
||||
LL | let foo = format_args!("{}", "hi");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
|
||||
| |
|
||||
| creates a temporary value which is freed while still in use
|
||||
LL |
|
||||
LL | bar(foo);
|
||||
| --- borrow later used here
|
||||
|
|
||||
= note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used
|
||||
= note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0716`.
|
||||
@@ -1,11 +1,12 @@
|
||||
error: queries overflow the depth limit!
|
||||
--> $DIR/recursive-const-in-impl.rs:11:14
|
||||
--> $DIR/recursive-const-in-impl.rs:11:20
|
||||
|
|
||||
LL | println!("{}", Thing::<i32>::X);
|
||||
| ^^^^
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "14"]` attribute to your crate (`recursive_const_in_impl`)
|
||||
= note: query depth increased by 9 when simplifying constant for the type system `main::promoted[1]`
|
||||
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ LL | x.push(0);
|
||||
| ^^^^^^^^^ mutable borrow occurs here
|
||||
...
|
||||
LL | println!("{h}");
|
||||
| --- immutable borrow later used here
|
||||
| - immutable borrow later used here
|
||||
|
|
||||
note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
|
||||
--> $DIR/foreign-2021.rs:7:13
|
||||
|
||||
@@ -23,7 +23,7 @@ LL | x.push(1);
|
||||
| ^^^^^^^^^ mutable borrow occurs here
|
||||
...
|
||||
LL | println!("{a}");
|
||||
| --- immutable borrow later used here
|
||||
| - immutable borrow later used here
|
||||
|
|
||||
note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
|
||||
--> $DIR/migration-note.rs:16:13
|
||||
@@ -99,7 +99,7 @@ LL | x.push(1);
|
||||
| ^ second mutable borrow occurs here
|
||||
...
|
||||
LL | println!("{a}");
|
||||
| --- first borrow later used here
|
||||
| - first borrow later used here
|
||||
|
|
||||
note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
|
||||
--> $DIR/migration-note.rs:63:13
|
||||
@@ -175,7 +175,7 @@ LL | s.f = 1;
|
||||
| ^^^^^^^ `s.f` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | println!("{a}");
|
||||
| --- borrow later used here
|
||||
| - borrow later used here
|
||||
|
|
||||
note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
|
||||
--> $DIR/migration-note.rs:112:13
|
||||
@@ -197,7 +197,7 @@ LL | s.f = 1;
|
||||
| ^^^^^^^ `s.f` is assigned to here but it was already borrowed
|
||||
...
|
||||
LL | println!("{a}");
|
||||
| --- borrow later used here
|
||||
| - borrow later used here
|
||||
|
|
||||
note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
|
||||
--> $DIR/migration-note.rs:128:13
|
||||
@@ -219,7 +219,7 @@ LL | s.f;
|
||||
| ^^^ use of borrowed `s.f`
|
||||
...
|
||||
LL | println!("{a}");
|
||||
| --- borrow later used here
|
||||
| - borrow later used here
|
||||
|
|
||||
note: this call may capture more lifetimes than intended, because Rust 2024 has adjusted the `impl Trait` lifetime capture rules
|
||||
--> $DIR/migration-note.rs:140:13
|
||||
|
||||
@@ -6,7 +6,7 @@ LL | let g = some(&temp());
|
||||
| |
|
||||
| creates a temporary value which is freed while still in use
|
||||
LL | println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?}");
|
||||
| ----- borrow later used here
|
||||
| - borrow later used here
|
||||
|
|
||||
help: consider using a `let` binding to create a longer lived value
|
||||
|
|
||||
|
||||
@@ -13,11 +13,6 @@ LL | };
|
||||
| -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
|
||||
| |
|
||||
| `mutex` dropped here while still borrowed
|
||||
|
|
||||
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
|
||||
|
|
||||
LL | write!(Out, "{}", mutex.lock()); /* no semicolon */
|
||||
| +
|
||||
|
||||
error[E0597]: `mutex` does not live long enough
|
||||
--> $DIR/format-args-temporaries-in-write.rs:47:29
|
||||
@@ -34,11 +29,6 @@ LL | };
|
||||
| -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
|
||||
| |
|
||||
| `mutex` dropped here while still borrowed
|
||||
|
|
||||
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
|
||||
|
|
||||
LL | writeln!(Out, "{}", mutex.lock()); /* no semicolon */
|
||||
| +
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fn main() {
|
||||
let x = *""; //~ ERROR E0277
|
||||
println!("{}", x);
|
||||
println!("{}", x);
|
||||
drop(x);
|
||||
drop(x);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error[E0277]: `<impl IntoIterator as IntoIterator>::Item` doesn't implement `std::fmt::Display`
|
||||
--> $DIR/issue-97760.rs:4:19
|
||||
--> $DIR/issue-97760.rs:4:20
|
||||
|
|
||||
LL | println!("{x}");
|
||||
| ^^^ `<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter
|
||||
| ^ `<impl IntoIterator as IntoIterator>::Item` cannot be formatted with the default formatter
|
||||
|
|
||||
= help: the trait `std::fmt::Display` is not implemented for `<impl IntoIterator as IntoIterator>::Item`
|
||||
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||
|
||||
@@ -405,8 +405,10 @@ mod expressions {
|
||||
fn expr_format_args() {
|
||||
let expr;
|
||||
format_arguments::new_const(&[]);
|
||||
format_arguments::new_v1(&[""],
|
||||
&[format_argument::new_display(&expr)]);
|
||||
{
|
||||
super let args = [format_argument::new_display(&expr)];
|
||||
format_arguments::new_v1(&[""], &args)
|
||||
};
|
||||
}
|
||||
}
|
||||
mod items {
|
||||
|
||||
@@ -10,7 +10,9 @@ fn main() {
|
||||
let x = 1;
|
||||
// Should flatten to println!("a 123 b {x} xyz\n"):
|
||||
{
|
||||
::std::io::_print(format_arguments::new_v1(&["a 123 b ", " xyz\n"],
|
||||
&[format_argument::new_display(&x)]));
|
||||
::std::io::_print({
|
||||
super let args = [format_argument::new_display(&x)];
|
||||
format_arguments::new_v1(&["a 123 b ", " xyz\n"], &args)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user