mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #154725 - cuviper:beta-next, r=cuviper
[beta] backports - stdarch subtree update rust-lang/rust#153336 (partial) - aarch64: fix UB in non-power-of-two reads and writes rust-lang/stdarch#2042 - add neon load/store assembly test rust-lang/rust#154094 - don't drop arguments' temporaries in `dbg!` rust-lang/rust#154074 - Init self_decl with a correct vis rust-lang/rust#154313 - Update LLVM to 22.1.2 rust-lang/rust#154344 - [perf] Revert FastISel patch rust-lang/rust#154511 - core: Destabilize beta-stable `RangeInclusiveIter::remainder` rust-lang/rust#154459 - Revert "Fix: On wasm targets, call `panic_in_cleanup` if panic occurs in cleanup" rust-lang/rust#154700 - core: Update the feature gate on `TryFrom<integer> for bool` rust-lang/rust#154691 r? cuviper
This commit is contained in:
@@ -545,8 +545,6 @@ fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
|
||||
}
|
||||
|
||||
// for dbg!(x) which may take ownership, suggest dbg!(&x) instead
|
||||
// but here we actually do not check whether the macro name is `dbg!`
|
||||
// so that we may extend the scope a bit larger to cover more cases
|
||||
fn suggest_ref_for_dbg_args(
|
||||
&self,
|
||||
body: &hir::Expr<'_>,
|
||||
@@ -560,29 +558,41 @@ fn suggest_ref_for_dbg_args(
|
||||
});
|
||||
let Some(var_info) = var_info else { return };
|
||||
let arg_name = var_info.name;
|
||||
struct MatchArgFinder {
|
||||
expr_span: Span,
|
||||
match_arg_span: Option<Span>,
|
||||
struct MatchArgFinder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
move_span: Span,
|
||||
arg_name: Symbol,
|
||||
match_arg_span: Option<Span> = None,
|
||||
}
|
||||
impl Visitor<'_> for MatchArgFinder {
|
||||
impl Visitor<'_> for MatchArgFinder<'_> {
|
||||
fn visit_expr(&mut self, e: &hir::Expr<'_>) {
|
||||
// dbg! is expanded into a match pattern, we need to find the right argument span
|
||||
if let hir::ExprKind::Match(expr, ..) = &e.kind
|
||||
&& let hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
path @ Path { segments: [seg], .. },
|
||||
)) = &expr.kind
|
||||
&& seg.ident.name == self.arg_name
|
||||
&& self.expr_span.source_callsite().contains(expr.span)
|
||||
if let hir::ExprKind::Match(scrutinee, ..) = &e.kind
|
||||
&& let hir::ExprKind::Tup(args) = scrutinee.kind
|
||||
&& e.span.macro_backtrace().any(|expn| {
|
||||
expn.macro_def_id.is_some_and(|macro_def_id| {
|
||||
self.tcx.is_diagnostic_item(sym::dbg_macro, macro_def_id)
|
||||
})
|
||||
})
|
||||
{
|
||||
self.match_arg_span = Some(path.span);
|
||||
for arg in args {
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
path @ Path { segments: [seg], .. },
|
||||
)) = &arg.kind
|
||||
&& seg.ident.name == self.arg_name
|
||||
&& self.move_span.source_equal(arg.span)
|
||||
{
|
||||
self.match_arg_span = Some(path.span);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::intravisit::walk_expr(self, e);
|
||||
}
|
||||
}
|
||||
|
||||
let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
|
||||
let mut finder = MatchArgFinder { tcx: self.infcx.tcx, move_span, arg_name, .. };
|
||||
finder.visit_expr(body);
|
||||
if let Some(macro_arg_span) = finder.match_arg_span {
|
||||
err.span_suggestion_verbose(
|
||||
|
||||
@@ -1655,10 +1655,6 @@ fn catch_switch(
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn get_funclet_cleanuppad(&self, _funclet: &Funclet) -> RValue<'gcc> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
// Atomic Operations
|
||||
fn atomic_cmpxchg(
|
||||
&mut self,
|
||||
|
||||
@@ -1296,10 +1296,6 @@ fn catch_switch(
|
||||
ret
|
||||
}
|
||||
|
||||
fn get_funclet_cleanuppad(&self, funclet: &Funclet<'ll>) -> &'ll Value {
|
||||
funclet.cleanuppad()
|
||||
}
|
||||
|
||||
// Atomic Operations
|
||||
fn atomic_cmpxchg(
|
||||
&mut self,
|
||||
|
||||
@@ -215,18 +215,19 @@ fn do_call<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
mir::UnwindAction::Continue => None,
|
||||
mir::UnwindAction::Unreachable => None,
|
||||
mir::UnwindAction::Terminate(reason) => {
|
||||
if fx.mir[self.bb].is_cleanup && base::wants_wasm_eh(fx.cx.tcx().sess) {
|
||||
// For wasm, we need to generate a nested `cleanuppad within %outer_pad`
|
||||
// to catch exceptions during cleanup and call `panic_in_cleanup`.
|
||||
Some(fx.terminate_block(reason, Some(self.bb)))
|
||||
} else if fx.mir[self.bb].is_cleanup
|
||||
&& base::wants_new_eh_instructions(fx.cx.tcx().sess)
|
||||
{
|
||||
if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) {
|
||||
// MSVC SEH will abort automatically if an exception tries to
|
||||
// propagate out from cleanup.
|
||||
|
||||
// FIXME(@mirkootter): For wasm, we currently do not support terminate during
|
||||
// cleanup, because this requires a few more changes: The current code
|
||||
// caches the `terminate_block` for each function; funclet based code - however -
|
||||
// requires a different terminate_block for each funclet
|
||||
// Until this is implemented, we just do not unwind inside cleanup blocks
|
||||
|
||||
None
|
||||
} else {
|
||||
Some(fx.terminate_block(reason, None))
|
||||
Some(fx.terminate_block(reason))
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -238,7 +239,7 @@ fn do_call<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
||||
if let Some(unwind_block) = unwind_block {
|
||||
let ret_llbb = if let Some((_, target)) = destination {
|
||||
self.llbb_with_cleanup(fx, target)
|
||||
fx.llbb(target)
|
||||
} else {
|
||||
fx.unreachable_block()
|
||||
};
|
||||
@@ -309,7 +310,7 @@ fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
) -> MergingSucc {
|
||||
let unwind_target = match unwind {
|
||||
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
|
||||
mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason, None)),
|
||||
mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)),
|
||||
mir::UnwindAction::Continue => None,
|
||||
mir::UnwindAction::Unreachable => None,
|
||||
};
|
||||
@@ -317,7 +318,7 @@ fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) {
|
||||
assert!(unwind_target.is_none());
|
||||
let ret_llbb = if let Some(target) = destination {
|
||||
self.llbb_with_cleanup(fx, target)
|
||||
fx.llbb(target)
|
||||
} else {
|
||||
fx.unreachable_block()
|
||||
};
|
||||
@@ -334,7 +335,7 @@ fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
MergingSucc::False
|
||||
} else if let Some(cleanup) = unwind_target {
|
||||
let ret_llbb = if let Some(target) = destination {
|
||||
self.llbb_with_cleanup(fx, target)
|
||||
fx.llbb(target)
|
||||
} else {
|
||||
fx.unreachable_block()
|
||||
};
|
||||
@@ -1915,39 +1916,8 @@ fn unreachable_block(&mut self) -> Bx::BasicBlock {
|
||||
})
|
||||
}
|
||||
|
||||
fn terminate_block(
|
||||
&mut self,
|
||||
reason: UnwindTerminateReason,
|
||||
outer_catchpad_bb: Option<mir::BasicBlock>,
|
||||
) -> Bx::BasicBlock {
|
||||
// mb_funclet_bb should be present if and only if the target is wasm and
|
||||
// we're terminating because of an unwind in a cleanup block. In that
|
||||
// case we have nested funclets and the inner catch_switch needs to know
|
||||
// what outer catch_pad it is contained in.
|
||||
debug_assert!(
|
||||
outer_catchpad_bb.is_some()
|
||||
== (base::wants_wasm_eh(self.cx.tcx().sess)
|
||||
&& reason == UnwindTerminateReason::InCleanup)
|
||||
);
|
||||
|
||||
// When we aren't in a wasm InCleanup block, there's only one terminate
|
||||
// block needed so we cache at START_BLOCK index.
|
||||
let mut cache_bb = mir::START_BLOCK;
|
||||
// In wasm eh InCleanup, use the outer funclet's cleanup BB as the cache
|
||||
// key.
|
||||
if let Some(outer_bb) = outer_catchpad_bb {
|
||||
let cleanup_kinds =
|
||||
self.cleanup_kinds.as_ref().expect("cleanup_kinds required for funclets");
|
||||
cache_bb = cleanup_kinds[outer_bb]
|
||||
.funclet_bb(outer_bb)
|
||||
.expect("funclet_bb should be in a funclet");
|
||||
|
||||
// Ensure the outer funclet is created first
|
||||
if self.funclets[cache_bb].is_none() {
|
||||
self.landing_pad_for(cache_bb);
|
||||
}
|
||||
}
|
||||
if let Some((cached_bb, cached_reason)) = self.terminate_blocks[cache_bb]
|
||||
fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock {
|
||||
if let Some((cached_bb, cached_reason)) = self.terminate_block
|
||||
&& reason == cached_reason
|
||||
{
|
||||
return cached_bb;
|
||||
@@ -1985,35 +1955,12 @@ fn terminate_block(
|
||||
// cp_terminate:
|
||||
// %cp = catchpad within %cs [null, i32 64, null]
|
||||
// ...
|
||||
//
|
||||
// By contrast, on WebAssembly targets, we specifically _do_ want to
|
||||
// catch foreign exceptions. The situation with MSVC is a
|
||||
// regrettable hack which we don't want to extend to other targets
|
||||
// unless necessary. For WebAssembly, to generate catch(...) and
|
||||
// catch only C++ exception instead of generating a catch_all, we
|
||||
// need to call the intrinsics @llvm.wasm.get.exception and
|
||||
// @llvm.wasm.get.ehselector in the catch pad. Since we don't do
|
||||
// this, we generate a catch_all. We originally got this behavior
|
||||
// by accident but it luckily matches our intention.
|
||||
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
|
||||
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
|
||||
|
||||
let mut cs_bx = Bx::build(self.cx, llbb);
|
||||
|
||||
// For wasm InCleanup blocks, our catch_switch is nested within the
|
||||
// outer catchpad, so we need to provide it as the parent value to
|
||||
// catch_switch.
|
||||
let mut outer_cleanuppad = None;
|
||||
if outer_catchpad_bb.is_some() {
|
||||
// Get the outer funclet's catchpad
|
||||
let outer_funclet = self.funclets[cache_bb]
|
||||
.as_ref()
|
||||
.expect("landing_pad_for didn't create funclet");
|
||||
outer_cleanuppad = Some(cs_bx.get_funclet_cleanuppad(outer_funclet));
|
||||
}
|
||||
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
|
||||
let cs = cs_bx.catch_switch(outer_cleanuppad, None, &[cp_llbb]);
|
||||
drop(cs_bx);
|
||||
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
|
||||
|
||||
bx = Bx::build(self.cx, cp_llbb);
|
||||
let null =
|
||||
@@ -2034,18 +1981,13 @@ fn terminate_block(
|
||||
} else {
|
||||
// Specifying more arguments than necessary usually doesn't
|
||||
// hurt, but the `WasmEHPrepare` LLVM pass does not recognize
|
||||
// anything other than a single `null` as a `catch_all` block,
|
||||
// anything other than a single `null` as a `catch (...)` block,
|
||||
// leading to problems down the line during instruction
|
||||
// selection.
|
||||
&[null] as &[_]
|
||||
};
|
||||
|
||||
funclet = Some(bx.catch_pad(cs, args));
|
||||
// On wasm, if we wanted to generate a catch(...) and only catch C++
|
||||
// exceptions, we'd call @llvm.wasm.get.exception and
|
||||
// @llvm.wasm.get.ehselector selectors here. We want a catch_all so
|
||||
// we leave them out. This is intentionally diverging from the MSVC
|
||||
// behavior.
|
||||
} else {
|
||||
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
|
||||
bx = Bx::build(self.cx, llbb);
|
||||
@@ -2071,7 +2013,7 @@ fn terminate_block(
|
||||
|
||||
bx.unreachable();
|
||||
|
||||
self.terminate_blocks[cache_bb] = Some((llbb, reason));
|
||||
self.terminate_block = Some((llbb, reason));
|
||||
llbb
|
||||
}
|
||||
|
||||
|
||||
@@ -90,11 +90,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
||||
/// Cached unreachable block
|
||||
unreachable_block: Option<Bx::BasicBlock>,
|
||||
|
||||
/// Cached terminate upon unwinding block and its reason. For non-wasm
|
||||
/// targets, there is at most one such block per function, stored at index
|
||||
/// `START_BLOCK`. For wasm targets, each funclet needs its own terminate
|
||||
/// block, indexed by the cleanup block that is the funclet's head.
|
||||
terminate_blocks: IndexVec<mir::BasicBlock, Option<(Bx::BasicBlock, UnwindTerminateReason)>>,
|
||||
/// Cached terminate upon unwinding block and its reason
|
||||
terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>,
|
||||
|
||||
/// A bool flag for each basic block indicating whether it is a cold block.
|
||||
/// A cold block is a block that is unlikely to be executed at runtime.
|
||||
@@ -230,7 +227,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
personality_slot: None,
|
||||
cached_llbbs,
|
||||
unreachable_block: None,
|
||||
terminate_blocks: IndexVec::from_elem(None, &mir.basic_blocks),
|
||||
terminate_block: None,
|
||||
cleanup_kinds,
|
||||
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
|
||||
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
|
||||
|
||||
@@ -552,12 +552,12 @@ fn select(
|
||||
|
||||
fn set_personality_fn(&mut self, personality: Self::Function);
|
||||
|
||||
// These are used by everyone except msvc and wasm EH
|
||||
// These are used by everyone except msvc
|
||||
fn cleanup_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value);
|
||||
fn filter_landing_pad(&mut self, pers_fn: Self::Function);
|
||||
fn resume(&mut self, exn0: Self::Value, exn1: Self::Value);
|
||||
|
||||
// These are used by msvc and wasm EH
|
||||
// These are used only by msvc
|
||||
fn cleanup_pad(&mut self, parent: Option<Self::Value>, args: &[Self::Value]) -> Self::Funclet;
|
||||
fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option<Self::BasicBlock>);
|
||||
fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet;
|
||||
@@ -567,7 +567,6 @@ fn catch_switch(
|
||||
unwind: Option<Self::BasicBlock>,
|
||||
handlers: &[Self::BasicBlock],
|
||||
) -> Self::Value;
|
||||
fn get_funclet_cleanuppad(&self, funclet: &Self::Funclet) -> Self::Value;
|
||||
|
||||
fn atomic_cmpxchg(
|
||||
&mut self,
|
||||
|
||||
@@ -544,6 +544,13 @@ fn name(&self) -> Option<Symbol> {
|
||||
ModuleKind::Def(.., name) => name,
|
||||
}
|
||||
}
|
||||
|
||||
fn opt_def_id(&self) -> Option<DefId> {
|
||||
match self {
|
||||
ModuleKind::Def(_, def_id, _) => Some(*def_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Combination of a symbol and its macros 2.0 normalized hygiene context.
|
||||
@@ -781,10 +788,7 @@ fn def_id(self) -> DefId {
|
||||
}
|
||||
|
||||
fn opt_def_id(self) -> Option<DefId> {
|
||||
match self.kind {
|
||||
ModuleKind::Def(_, def_id, _) => Some(def_id),
|
||||
_ => None,
|
||||
}
|
||||
self.kind.opt_def_id()
|
||||
}
|
||||
|
||||
// `self` resolves to the first module ancestor that `is_normal`.
|
||||
@@ -1421,14 +1425,19 @@ fn new_module(
|
||||
&'ra self,
|
||||
parent: Option<Module<'ra>>,
|
||||
kind: ModuleKind,
|
||||
vis: Visibility<DefId>,
|
||||
expn_id: ExpnId,
|
||||
span: Span,
|
||||
no_implicit_prelude: bool,
|
||||
) -> Module<'ra> {
|
||||
let self_decl = match kind {
|
||||
ModuleKind::Def(def_kind, def_id, _) => {
|
||||
Some(self.new_pub_def_decl(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT))
|
||||
}
|
||||
ModuleKind::Def(def_kind, def_id, _) => Some(self.new_def_decl(
|
||||
Res::Def(def_kind, def_id),
|
||||
vis,
|
||||
span,
|
||||
LocalExpnId::ROOT,
|
||||
None,
|
||||
)),
|
||||
ModuleKind::Block => None,
|
||||
};
|
||||
Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new(
|
||||
@@ -1610,6 +1619,7 @@ pub fn new(
|
||||
let graph_root = arenas.new_module(
|
||||
None,
|
||||
ModuleKind::Def(DefKind::Mod, root_def_id, None),
|
||||
Visibility::Public,
|
||||
ExpnId::root(),
|
||||
crate_span,
|
||||
attr::contains_name(attrs, sym::no_implicit_prelude),
|
||||
@@ -1619,6 +1629,7 @@ pub fn new(
|
||||
let empty_module = arenas.new_module(
|
||||
None,
|
||||
ModuleKind::Def(DefKind::Mod, root_def_id, None),
|
||||
Visibility::Public,
|
||||
ExpnId::root(),
|
||||
DUMMY_SP,
|
||||
true,
|
||||
@@ -1748,7 +1759,9 @@ fn new_local_module(
|
||||
span: Span,
|
||||
no_implicit_prelude: bool,
|
||||
) -> Module<'ra> {
|
||||
let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
|
||||
let vis =
|
||||
kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id));
|
||||
let module = self.arenas.new_module(parent, kind, vis, expn_id, span, no_implicit_prelude);
|
||||
self.local_modules.push(module);
|
||||
if let Some(def_id) = module.opt_def_id() {
|
||||
self.local_module_map.insert(def_id.expect_local(), module);
|
||||
@@ -1764,7 +1777,9 @@ fn new_extern_module(
|
||||
span: Span,
|
||||
no_implicit_prelude: bool,
|
||||
) -> Module<'ra> {
|
||||
let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
|
||||
let vis =
|
||||
kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id));
|
||||
let module = self.arenas.new_module(parent, kind, vis, expn_id, span, no_implicit_prelude);
|
||||
self.extern_module_map.borrow_mut().insert(module.def_id(), module);
|
||||
module
|
||||
}
|
||||
|
||||
@@ -763,6 +763,7 @@
|
||||
custom_test_frameworks,
|
||||
d,
|
||||
d32,
|
||||
dbg_macro,
|
||||
dead_code,
|
||||
dealloc,
|
||||
debug,
|
||||
|
||||
@@ -332,7 +332,7 @@ fn try_from(u: $source) -> Result<Self, Self::Error> {
|
||||
/// Implement `TryFrom<integer>` for `bool`
|
||||
macro_rules! impl_try_from_integer_for_bool {
|
||||
($($int:ty)+) => {$(
|
||||
#[stable(feature = "try_from", since = "1.34.0")]
|
||||
#[stable(feature = "bool_try_from_int", since = "1.95.0")]
|
||||
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
|
||||
impl const TryFrom<$int> for bool {
|
||||
type Error = TryFromIntError;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
pub struct RangeIter<A>(legacy::Range<A>);
|
||||
|
||||
impl<A> RangeIter<A> {
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
#[unstable(feature = "new_range_remainder", issue = "154458")]
|
||||
/// Returns the remainder of the range being iterated over.
|
||||
pub fn remainder(self) -> Range<A> {
|
||||
Range { start: self.0.start, end: self.0.end }
|
||||
@@ -161,7 +161,7 @@ impl<A: Step> RangeInclusiveIter<A> {
|
||||
/// Returns the remainder of the range being iterated over.
|
||||
///
|
||||
/// If the iterator is exhausted or empty, returns `None`.
|
||||
#[stable(feature = "new_range_inclusive_api", since = "1.95.0")]
|
||||
#[unstable(feature = "new_range_remainder", issue = "154458")]
|
||||
pub fn remainder(self) -> Option<RangeInclusive<A>> {
|
||||
if self.0.is_empty() {
|
||||
return None;
|
||||
@@ -307,7 +307,7 @@ impl<A: Step> RangeFromIter<A> {
|
||||
/// Returns the remainder of the range being iterated over.
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
#[unstable(feature = "new_range_api", issue = "125687")]
|
||||
#[unstable(feature = "new_range_remainder", issue = "154458")]
|
||||
pub fn remainder(self) -> RangeFrom<A> {
|
||||
if intrinsics::overflow_checks() {
|
||||
if !self.first {
|
||||
|
||||
+43
-39
@@ -5,6 +5,9 @@
|
||||
//! library.
|
||||
// ignore-tidy-dbg
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[doc = include_str!("../../core/src/macros/panic.md")]
|
||||
#[macro_export]
|
||||
#[rustc_builtin_macro(std_panic)]
|
||||
@@ -359,19 +362,16 @@ macro_rules! dbg {
|
||||
};
|
||||
}
|
||||
|
||||
/// Internal macro that processes a list of expressions and produces a chain of
|
||||
/// nested `match`es, one for each expression, before finally calling `eprint!`
|
||||
/// with the collected information and returning all the evaluated expressions
|
||||
/// in a tuple.
|
||||
/// Internal macro that processes a list of expressions, binds their results
|
||||
/// with `match`, calls `eprint!` with the collected information, and returns
|
||||
/// all the evaluated expressions in a tuple.
|
||||
///
|
||||
/// E.g. `dbg_internal!(() () (1, 2))` expands into
|
||||
/// ```rust, ignore
|
||||
/// match 1 {
|
||||
/// tmp_1 => match 2 {
|
||||
/// tmp_2 => {
|
||||
/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */);
|
||||
/// (tmp_1, tmp_2)
|
||||
/// }
|
||||
/// match (1, 2) {
|
||||
/// (tmp_1, tmp_2) => {
|
||||
/// eprint!("...", &tmp_1, &tmp_2, /* some other arguments */);
|
||||
/// (tmp_1, tmp_2)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@@ -380,37 +380,41 @@ macro_rules! dbg {
|
||||
#[doc(hidden)]
|
||||
#[rustc_macro_transparency = "semiopaque"]
|
||||
pub macro dbg_internal {
|
||||
(($($piece:literal),+) ($($processed:expr => $bound:expr),+) ()) => {{
|
||||
$crate::eprint!(
|
||||
$crate::concat!($($piece),+),
|
||||
$(
|
||||
$crate::stringify!($processed),
|
||||
// The `&T: Debug` check happens here (not in the format literal desugaring)
|
||||
// to avoid format literal related messages and suggestions.
|
||||
&&$bound as &dyn $crate::fmt::Debug
|
||||
),+,
|
||||
// The location returned here is that of the macro invocation, so
|
||||
// it will be the same for all expressions. Thus, label these
|
||||
// arguments so that they can be reused in every piece of the
|
||||
// formatting template.
|
||||
file=$crate::file!(),
|
||||
line=$crate::line!(),
|
||||
column=$crate::column!()
|
||||
);
|
||||
// Comma separate the variables only when necessary so that this will
|
||||
// not yield a tuple for a single expression, but rather just parenthesize
|
||||
// the expression.
|
||||
($($bound),+)
|
||||
}},
|
||||
(($($piece:literal),*) ($($processed:expr => $bound:expr),*) ($val:expr $(,$rest:expr)*)) => {
|
||||
(($($piece:literal),+) ($($processed:expr => $bound:ident),+) ()) => {
|
||||
// Use of `match` here is intentional because it affects the lifetimes
|
||||
// of temporaries - https://stackoverflow.com/a/48732525/1063961
|
||||
match $val {
|
||||
tmp => $crate::macros::dbg_internal!(
|
||||
($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n")
|
||||
($($processed => $bound,)* $val => tmp)
|
||||
($($rest),*)
|
||||
),
|
||||
// Always put the arguments in a tuple to avoid an unused parens lint on the pattern.
|
||||
match ($($processed,)+) {
|
||||
($($bound,)+) => {
|
||||
$crate::eprint!(
|
||||
$crate::concat!($($piece),+),
|
||||
$(
|
||||
$crate::stringify!($processed),
|
||||
// The `&T: Debug` check happens here (not in the format literal desugaring)
|
||||
// to avoid format literal related messages and suggestions.
|
||||
&&$bound as &dyn $crate::fmt::Debug
|
||||
),+,
|
||||
// The location returned here is that of the macro invocation, so
|
||||
// it will be the same for all expressions. Thus, label these
|
||||
// arguments so that they can be reused in every piece of the
|
||||
// formatting template.
|
||||
file=$crate::file!(),
|
||||
line=$crate::line!(),
|
||||
column=$crate::column!()
|
||||
);
|
||||
// Comma separate the variables only when necessary so that this will
|
||||
// not yield a tuple for a single expression, but rather just parenthesize
|
||||
// the expression.
|
||||
($($bound),+)
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
(($($piece:literal),*) ($($processed:expr => $bound:ident),*) ($val:expr $(,$rest:expr)*)) => {
|
||||
$crate::macros::dbg_internal!(
|
||||
($($piece,)* "[{file}:{line}:{column}] {} = {:#?}\n")
|
||||
($($processed => $bound,)* $val => tmp)
|
||||
($($rest),*)
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// ignore-tidy-dbg
|
||||
|
||||
/// Test for <https://github.com/rust-lang/rust/issues/153850>:
|
||||
/// `dbg!` shouldn't drop arguments' temporaries.
|
||||
#[test]
|
||||
fn no_dropping_temps() {
|
||||
fn temp() {}
|
||||
|
||||
*dbg!(&temp());
|
||||
*dbg!(&temp(), 1).0;
|
||||
*dbg!(0, &temp()).1;
|
||||
*dbg!(0, &temp(), 2).1;
|
||||
}
|
||||
@@ -226,12 +226,12 @@ macro_rules! deinterleaving_load {
|
||||
($elem:ty, $lanes:literal, 2, $ptr:expr) => {{
|
||||
use $crate::core_arch::macros::deinterleave_mask;
|
||||
use $crate::core_arch::simd::Simd;
|
||||
use $crate::{mem::transmute, ptr};
|
||||
use $crate::mem::transmute;
|
||||
|
||||
type V = Simd<$elem, $lanes>;
|
||||
type W = Simd<$elem, { $lanes * 2 }>;
|
||||
|
||||
let w: W = ptr::read_unaligned($ptr as *const W);
|
||||
let w: W = $crate::ptr::read_unaligned($ptr as *const W);
|
||||
|
||||
let v0: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 2, 0>());
|
||||
let v1: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 2, 1>());
|
||||
@@ -242,12 +242,20 @@ macro_rules! deinterleaving_load {
|
||||
($elem:ty, $lanes:literal, 3, $ptr:expr) => {{
|
||||
use $crate::core_arch::macros::deinterleave_mask;
|
||||
use $crate::core_arch::simd::Simd;
|
||||
use $crate::{mem::transmute, ptr};
|
||||
use $crate::mem::{MaybeUninit, transmute};
|
||||
|
||||
type V = Simd<$elem, $lanes>;
|
||||
type W = Simd<$elem, { $lanes * 3 }>;
|
||||
|
||||
let w: W = ptr::read_unaligned($ptr as *const W);
|
||||
// NOTE: repr(simd) adds padding to make the total size a power of two.
|
||||
// Hence reading W from ptr might read out of bounds.
|
||||
let mut mem = MaybeUninit::<W>::uninit();
|
||||
$crate::ptr::copy_nonoverlapping(
|
||||
$ptr.cast::<$elem>(),
|
||||
mem.as_mut_ptr().cast::<$elem>(),
|
||||
$lanes * 3,
|
||||
);
|
||||
let w = mem.assume_init();
|
||||
|
||||
let v0: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 3, 0>());
|
||||
let v1: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 3, 1>());
|
||||
@@ -259,12 +267,12 @@ macro_rules! deinterleaving_load {
|
||||
($elem:ty, $lanes:literal, 4, $ptr:expr) => {{
|
||||
use $crate::core_arch::macros::deinterleave_mask;
|
||||
use $crate::core_arch::simd::Simd;
|
||||
use $crate::{mem::transmute, ptr};
|
||||
use $crate::mem::transmute;
|
||||
|
||||
type V = Simd<$elem, $lanes>;
|
||||
type W = Simd<$elem, { $lanes * 4 }>;
|
||||
|
||||
let w: W = ptr::read_unaligned($ptr as *const W);
|
||||
let w: W = $crate::ptr::read_unaligned($ptr as *const W);
|
||||
|
||||
let v0: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 4, 0>());
|
||||
let v1: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 4, 1>());
|
||||
|
||||
+1
-1
Submodule src/llvm-project updated: 41f177ed26...1cb4e3833c
@@ -5,7 +5,7 @@
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind};
|
||||
use rustc_hir::{Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{Span, SyntaxContext};
|
||||
@@ -92,16 +92,15 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
(macro_call.span, String::from("()"))
|
||||
}
|
||||
},
|
||||
ExprKind::Match(first, arms, _) => {
|
||||
let vals = collect_vals(first, arms);
|
||||
let suggestion = match *vals.as_slice() {
|
||||
ExprKind::Match(args, _, _) => {
|
||||
let suggestion = match args.kind {
|
||||
// dbg!(1) => 1
|
||||
[val] => {
|
||||
ExprKind::Tup([val]) => {
|
||||
snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability)
|
||||
.to_string()
|
||||
},
|
||||
// dbg!(2, 3) => (2, 3)
|
||||
[first, .., last] => {
|
||||
ExprKind::Tup([first, .., last]) => {
|
||||
let snippet = snippet_with_applicability(
|
||||
cx,
|
||||
first.span.source_callsite().to(last.span.source_callsite()),
|
||||
@@ -165,39 +164,3 @@ fn is_async_move_desugar<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx
|
||||
fn first_dbg_macro_in_expansion(cx: &LateContext<'_>, span: Span) -> Option<MacroCall> {
|
||||
macro_backtrace(span).find(|mc| cx.tcx.is_diagnostic_item(sym::dbg_macro, mc.def_id))
|
||||
}
|
||||
|
||||
/// Extracts all value expressions from the `match`-tree generated by `dbg!`.
|
||||
///
|
||||
/// E.g. from
|
||||
/// ```rust, ignore
|
||||
/// match 1 {
|
||||
/// tmp_1 => match 2 {
|
||||
/// tmp_2 => {
|
||||
/// /* printing */
|
||||
/// (tmp_1, tmp_2)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// this extracts `1` and `2`.
|
||||
fn collect_vals<'hir>(first: &'hir Expr<'hir>, mut arms: &'hir [Arm<'hir>]) -> Vec<&'hir Expr<'hir>> {
|
||||
let mut vals = vec![first];
|
||||
loop {
|
||||
let [arm] = arms else {
|
||||
unreachable!("dbg! macro expansion only has single-arm matches")
|
||||
};
|
||||
|
||||
match is_async_move_desugar(arm.body)
|
||||
.unwrap_or(arm.body)
|
||||
.peel_drop_temps()
|
||||
.kind
|
||||
{
|
||||
ExprKind::Block(..) => return vals,
|
||||
ExprKind::Match(val, a, _) => {
|
||||
vals.push(val);
|
||||
arms = a;
|
||||
},
|
||||
_ => unreachable!("dbg! macro expansion only results in block or match expressions"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,6 @@ macro_rules! generate {
|
||||
cx,
|
||||
cycle,
|
||||
cyclomatic_complexity,
|
||||
dbg_macro,
|
||||
de,
|
||||
debug_struct,
|
||||
deprecated_in_future,
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
"only-apple",
|
||||
"only-arm",
|
||||
"only-arm64ec",
|
||||
"only-armv7-unknown-linux-gnueabihf",
|
||||
"only-avr",
|
||||
"only-beta",
|
||||
"only-bpf",
|
||||
|
||||
@@ -2,7 +2,7 @@ error: Undefined Behavior: memory access failed: ALLOC has been freed, so this p
|
||||
--> tests/fail/dangling_pointers/dangling_primitive.rs:LL:CC
|
||||
|
|
||||
LL | dbg!(*ptr);
|
||||
| ^^^^^^^^^^ Undefined Behavior occurred here
|
||||
| ^^^^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
@@ -7,7 +7,7 @@ error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is unin
|
||||
--> tests/fail/function_calls/return_pointer_on_unwind.rs:LL:CC
|
||||
|
|
||||
LL | dbg!(x.0);
|
||||
| ^^^^^^^^^ Undefined Behavior occurred here
|
||||
| ^^^ Undefined Behavior occurred here
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
//@ assembly-output: emit-asm
|
||||
//
|
||||
//@ revisions: AARCH64
|
||||
//@[AARCH64] compile-flags: -Copt-level=3
|
||||
//@[AARCH64] only-aarch64-unknown-linux-gnu
|
||||
//
|
||||
//@ revisions: ARMV7
|
||||
//@[ARMV7] compile-flags: -Copt-level=3
|
||||
//@[ARMV7] only-armv7-unknown-linux-gnueabihf
|
||||
//@[ARMV7] ignore-thumb
|
||||
//@[ARMV7] ignore-android
|
||||
#![crate_type = "lib"]
|
||||
#![cfg_attr(target_arch = "arm", feature(arm_target_feature, stdarch_arm_neon_intrinsics))]
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use std::arch::aarch64::*;
|
||||
#[cfg(target_arch = "arm")]
|
||||
use std::arch::arm::*;
|
||||
|
||||
// Loads of 3 are error-prone because a `repr(simd)` type's size is always rounded up to the next
|
||||
// power of 2. Hence, using `read_unaligned` and `write_unaligned` on such types is invalid, it
|
||||
// would go out of bounds.
|
||||
#[unsafe(no_mangle)]
|
||||
#[cfg_attr(target_arch = "arm", target_feature(enable = "neon,v7"))]
|
||||
fn test_vld3q_f32(ptr: *const f32) -> float32x4x3_t {
|
||||
// AARCH64-LABEL: test_vld3q_f32
|
||||
// AARCH64: ld3 { v0.4s, v1.4s, v2.4s }, [x0]
|
||||
// AARCH64: stp q0, q1, [x8]
|
||||
// AARCH64: str q2, [x8, #32]
|
||||
// AARCH64: ret
|
||||
//
|
||||
// ARMV7-LABEL: test_vld3q_f32
|
||||
// ARMV7: vld3.32 {d16, d18, d20}, [r1]!
|
||||
// ARMV7: vld3.32 {d17, d19, d21}, [r1]
|
||||
// ARMV7: vst1.32 {d16, d17}, [r0]!
|
||||
// ARMV7: vst1.32 {d18, d19}, [r0]!
|
||||
// ARMV7: vst1.64 {d20, d21}, [r0]
|
||||
// ARMV7: bx lr
|
||||
unsafe { vld3q_f32(ptr) }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[cfg_attr(target_arch = "arm", target_feature(enable = "neon,v7"))]
|
||||
fn test_vld3q_s32(ptr: *const i32) -> int32x4x3_t {
|
||||
// AARCH64-LABEL: test_vld3q_s32
|
||||
// AARCH64: ld3 { v0.4s, v1.4s, v2.4s }, [x0]
|
||||
// AARCH64: stp q0, q1, [x8]
|
||||
// AARCH64: str q2, [x8, #32]
|
||||
// AARCH64: ret
|
||||
//
|
||||
// ARMV7-LABEL: test_vld3q_s32
|
||||
// ARMV7: vld3.32 {d16, d18, d20}, [r1]!
|
||||
// ARMV7: vld3.32 {d17, d19, d21}, [r1]
|
||||
// ARMV7: vst1.32 {d16, d17}, [r0]!
|
||||
// ARMV7: vst1.32 {d18, d19}, [r0]!
|
||||
// ARMV7: vst1.64 {d20, d21}, [r0]
|
||||
// ARMV7: bx lr
|
||||
unsafe { vld3q_s32(ptr) }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
#[cfg_attr(target_arch = "arm", target_feature(enable = "neon,v7"))]
|
||||
fn test_vld3q_u32(ptr: *const u32) -> uint32x4x3_t {
|
||||
// AARCH64-LABEL: test_vld3q_u32
|
||||
// AARCH64: ld3 { v0.4s, v1.4s, v2.4s }, [x0]
|
||||
// AARCH64: stp q0, q1, [x8]
|
||||
// AARCH64: str q2, [x8, #32]
|
||||
// AARCH64: ret
|
||||
//
|
||||
// ARMV7-LABEL: test_vld3q_u32
|
||||
// ARMV7: vld3.32 {d16, d18, d20}, [r1]!
|
||||
// ARMV7: vld3.32 {d17, d19, d21}, [r1]
|
||||
// ARMV7: vst1.32 {d16, d17}, [r0]!
|
||||
// ARMV7: vst1.32 {d18, d19}, [r0]!
|
||||
// ARMV7: vst1.64 {d20, d21}, [r0]
|
||||
// ARMV7: bx lr
|
||||
unsafe { vld3q_u32(ptr) }
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//@ compile-flags: -C panic=unwind -Copt-level=0
|
||||
//@ needs-unwind
|
||||
//@ only-wasm32
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// Test that `panic_in_cleanup` is called on webassembly targets when a panic
|
||||
// occurs in a destructor during unwinding.
|
||||
|
||||
extern "Rust" {
|
||||
fn may_panic();
|
||||
}
|
||||
|
||||
struct PanicOnDrop;
|
||||
|
||||
impl Drop for PanicOnDrop {
|
||||
fn drop(&mut self) {
|
||||
unsafe { may_panic() }
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @double_panic
|
||||
// CHECK: invoke void @may_panic()
|
||||
// CHECK: invoke void @{{.+}}drop_in_place{{.+}}
|
||||
// CHECK: unwind label %[[TERMINATE:.*]]
|
||||
//
|
||||
// CHECK: [[TERMINATE]]:
|
||||
// CHECK: call void @{{.*panic_in_cleanup}}
|
||||
// CHECK: unreachable
|
||||
#[no_mangle]
|
||||
pub fn double_panic() {
|
||||
let _guard = PanicOnDrop;
|
||||
unsafe { may_panic() }
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(new_range_api)]
|
||||
#![feature(new_range_remainder)]
|
||||
use std::range::{RangeFrom, RangeFromIter};
|
||||
|
||||
// CHECK-LABEL: @iterrangefrom_remainder(
|
||||
|
||||
@@ -9,10 +9,6 @@
|
||||
// Ensure a catch-all generates:
|
||||
// - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused)
|
||||
// - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions)
|
||||
//
|
||||
// Unlike on windows, on Wasm, we specifically do want to catch foreign
|
||||
// exceptions. To catch only C++ exceptions we'd need to call
|
||||
// @llvm.wasm.get.exception and @llvm.wasm.get.ehselector in the catchpad.
|
||||
|
||||
#![feature(no_core, lang_items, rustc_attrs)]
|
||||
#![crate_type = "lib"]
|
||||
@@ -40,14 +36,8 @@ fn panic_cannot_unwind() -> ! {
|
||||
#[no_mangle]
|
||||
#[rustc_nounwind]
|
||||
pub fn doesnt_unwind() {
|
||||
// CHECK: catchswitch within none [label %{{.*}}] unwind to caller
|
||||
// emscripten: %catchpad = catchpad within %catchswitch [ptr null]
|
||||
// wasi: %catchpad = catchpad within %catchswitch [ptr null]
|
||||
// seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null]
|
||||
//
|
||||
// We don't call these intrinsics on wasm targets so we generate a catch_all
|
||||
// instruction which also picks up foreign exceptions
|
||||
// NOT: @llvm.wasm.get.exception
|
||||
// NOT: @llvm.wasm.get.ehselector
|
||||
unwinds();
|
||||
}
|
||||
|
||||
@@ -1,67 +1,44 @@
|
||||
//! Diagnostic test for <https://github.com/rust-lang/rust/issues/120327>: suggest borrowing
|
||||
//! variables passed to `dbg!` that are later used.
|
||||
//@ dont-require-annotations: HELP
|
||||
|
||||
fn s() -> String {
|
||||
let a = String::new();
|
||||
dbg!(a);
|
||||
dbg!(a); //~ HELP consider borrowing instead of transferring ownership
|
||||
return a; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
fn m() -> String {
|
||||
let a = String::new();
|
||||
dbg!(1, 2, a, 1, 2);
|
||||
dbg!(1, 2, a, 1, 2); //~ HELP consider borrowing instead of transferring ownership
|
||||
return a; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
fn t(a: String) -> String {
|
||||
let b: String = "".to_string();
|
||||
dbg!(a, b);
|
||||
dbg!(a, b); //~ HELP consider borrowing instead of transferring ownership
|
||||
return b; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
fn x(a: String) -> String {
|
||||
let b: String = "".to_string();
|
||||
dbg!(a, b);
|
||||
dbg!(a, b); //~ HELP consider borrowing instead of transferring ownership
|
||||
return a; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
macro_rules! my_dbg {
|
||||
() => {
|
||||
eprintln!("[{}:{}:{}]", file!(), line!(), column!())
|
||||
};
|
||||
($val:expr $(,)?) => {
|
||||
match $val {
|
||||
tmp => {
|
||||
eprintln!("[{}:{}:{}] {} = {:#?}",
|
||||
file!(), line!(), column!(), stringify!($val), &tmp);
|
||||
tmp
|
||||
}
|
||||
}
|
||||
};
|
||||
($($val:expr),+ $(,)?) => {
|
||||
($(my_dbg!($val)),+,)
|
||||
};
|
||||
}
|
||||
|
||||
fn test_my_dbg() -> String {
|
||||
let b: String = "".to_string();
|
||||
my_dbg!(b, 1);
|
||||
return b; //~ ERROR use of moved value:
|
||||
}
|
||||
|
||||
fn test_not_macro() -> String {
|
||||
let a = String::new();
|
||||
let _b = match a {
|
||||
tmp => {
|
||||
eprintln!("dbg: {}", tmp);
|
||||
tmp
|
||||
}
|
||||
};
|
||||
return a; //~ ERROR use of moved value:
|
||||
fn two_of_them(a: String) -> String {
|
||||
dbg!(a, a); //~ ERROR use of moved value
|
||||
//~| HELP consider borrowing instead of transferring ownership
|
||||
//~| HELP consider borrowing instead of transferring ownership
|
||||
return a; //~ ERROR use of moved value
|
||||
}
|
||||
|
||||
fn get_expr(_s: String) {}
|
||||
|
||||
// The suggestion is purely syntactic; applying it here will result in a type error.
|
||||
fn test() {
|
||||
let a: String = "".to_string();
|
||||
let _res = get_expr(dbg!(a));
|
||||
let _res = get_expr(dbg!(a)); //~ HELP consider borrowing instead of transferring ownership
|
||||
let _l = a.len(); //~ ERROR borrow of moved value
|
||||
}
|
||||
|
||||
|
||||
@@ -1,112 +1,133 @@
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:4:12
|
||||
--> $DIR/dbg-issue-120327.rs:8:12
|
||||
|
|
||||
LL | let a = String::new();
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | dbg!(a);
|
||||
| ------- value moved here
|
||||
| - value moved here
|
||||
LL | return a;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | dbg!(a.clone());
|
||||
| ++++++++
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | dbg!(&a);
|
||||
| +
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:10:12
|
||||
--> $DIR/dbg-issue-120327.rs:14:12
|
||||
|
|
||||
LL | let a = String::new();
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | dbg!(1, 2, a, 1, 2);
|
||||
| ------------------- value moved here
|
||||
| - value moved here
|
||||
LL | return a;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | dbg!(1, 2, a.clone(), 1, 2);
|
||||
| ++++++++
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | dbg!(1, 2, &a, 1, 2);
|
||||
| +
|
||||
|
||||
error[E0382]: use of moved value: `b`
|
||||
--> $DIR/dbg-issue-120327.rs:16:12
|
||||
--> $DIR/dbg-issue-120327.rs:20:12
|
||||
|
|
||||
LL | let b: String = "".to_string();
|
||||
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
|
||||
LL | dbg!(a, b);
|
||||
| ---------- value moved here
|
||||
| - value moved here
|
||||
LL | return b;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | dbg!(a, b.clone());
|
||||
| ++++++++
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | dbg!(a, &b);
|
||||
| +
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:22:12
|
||||
--> $DIR/dbg-issue-120327.rs:26:12
|
||||
|
|
||||
LL | fn x(a: String) -> String {
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | let b: String = "".to_string();
|
||||
LL | dbg!(a, b);
|
||||
| ---------- value moved here
|
||||
| - value moved here
|
||||
LL | return a;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | dbg!(a.clone(), b);
|
||||
| ++++++++
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | dbg!(&a, b);
|
||||
| +
|
||||
|
||||
error[E0382]: use of moved value: `b`
|
||||
--> $DIR/dbg-issue-120327.rs:46:12
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:30:13
|
||||
|
|
||||
LL | tmp => {
|
||||
| --- value moved here
|
||||
...
|
||||
LL | let b: String = "".to_string();
|
||||
| - move occurs because `b` has type `String`, which does not implement the `Copy` trait
|
||||
LL | my_dbg!(b, 1);
|
||||
LL | return b;
|
||||
| ^ value used here after move
|
||||
LL | fn two_of_them(a: String) -> String {
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | dbg!(a, a);
|
||||
| - ^ value used here after move
|
||||
| |
|
||||
| value moved here
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | dbg!(a.clone(), a);
|
||||
| ++++++++
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | my_dbg!(&b, 1);
|
||||
| +
|
||||
help: borrow this binding in the pattern to avoid moving the value
|
||||
|
|
||||
LL | ref tmp => {
|
||||
| +++
|
||||
LL | dbg!(&a, a);
|
||||
| +
|
||||
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:57:12
|
||||
--> $DIR/dbg-issue-120327.rs:33:12
|
||||
|
|
||||
LL | let a = String::new();
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | let _b = match a {
|
||||
LL | tmp => {
|
||||
| --- value moved here
|
||||
LL | fn two_of_them(a: String) -> String {
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | dbg!(a, a);
|
||||
| - value moved here
|
||||
...
|
||||
LL | return a;
|
||||
| ^ value used here after move
|
||||
|
|
||||
help: borrow this binding in the pattern to avoid moving the value
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | ref tmp => {
|
||||
| +++
|
||||
LL | dbg!(a, a.clone());
|
||||
| ++++++++
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | dbg!(a, &a);
|
||||
| +
|
||||
|
||||
error[E0382]: borrow of moved value: `a`
|
||||
--> $DIR/dbg-issue-120327.rs:65:14
|
||||
--> $DIR/dbg-issue-120327.rs:42:14
|
||||
|
|
||||
LL | let a: String = "".to_string();
|
||||
| - move occurs because `a` has type `String`, which does not implement the `Copy` trait
|
||||
LL | let _res = get_expr(dbg!(a));
|
||||
| ------- value moved here
|
||||
| - value moved here
|
||||
LL | let _l = a.len();
|
||||
| ^ value borrowed here after move
|
||||
|
|
||||
help: consider cloning the value if the performance cost is acceptable
|
||||
|
|
||||
LL | let _res = get_expr(dbg!(a.clone()));
|
||||
| ++++++++
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | let _res = get_expr(dbg!(&a));
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//@ compile-flags: -O -C debug_assertions=yes
|
||||
|
||||
#![feature(new_range_api)]
|
||||
#![feature(new_range_remainder)]
|
||||
|
||||
use std::panic;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
//@ compile-flags: -O -C debug_assertions=no
|
||||
|
||||
#![feature(new_range_api)]
|
||||
#![feature(new_range_remainder)]
|
||||
|
||||
fn main() {
|
||||
let mut it = core::range::RangeFrom::from(u8::MAX..).into_iter();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//@ compile-flags: -O -C overflow-checks=yes
|
||||
|
||||
#![feature(new_range_api)]
|
||||
#![feature(new_range_remainder)]
|
||||
|
||||
use std::panic;
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ pub fn g<T: Default>(mut v: T) {
|
||||
}
|
||||
|
||||
pub fn h<T: Copy + Default + std::fmt::Debug>() {
|
||||
let mut z = T::default();
|
||||
let mut z = T::default(); //~ WARN unused variable: `z`
|
||||
let _ = move |b| {
|
||||
loop {
|
||||
if b {
|
||||
|
||||
@@ -156,6 +156,14 @@ LL | z = T::default();
|
||||
|
|
||||
= help: maybe it is overwritten before being read?
|
||||
|
||||
warning: unused variable: `z`
|
||||
--> $DIR/liveness-upvars.rs:101:9
|
||||
|
|
||||
LL | let mut z = T::default();
|
||||
| ^^^^^ help: if this is intentional, prefix it with an underscore: `_z`
|
||||
|
|
||||
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
|
||||
|
||||
warning: value captured by `state` is never read
|
||||
--> $DIR/liveness-upvars.rs:131:9
|
||||
|
|
||||
@@ -196,5 +204,5 @@ LL | s = yield ();
|
||||
|
|
||||
= help: maybe it is overwritten before being read?
|
||||
|
||||
warning: 24 warnings emitted
|
||||
warning: 25 warnings emitted
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ fn range_inclusive(mut r: RangeInclusive<usize>) {
|
||||
|
||||
let mut i = r.into_iter();
|
||||
i.next();
|
||||
i.remainder();
|
||||
i.remainder(); //~ ERROR unstable
|
||||
}
|
||||
|
||||
// Unstable module
|
||||
|
||||
@@ -48,6 +48,16 @@ LL | use std::range::RangeIter;
|
||||
= help: add `#![feature(new_range_api)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error[E0658]: use of unstable library feature `new_range_remainder`
|
||||
--> $DIR/new_range_stability.rs:14:7
|
||||
|
|
||||
LL | i.remainder();
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: see issue #154458 <https://github.com/rust-lang/rust/issues/154458> for more information
|
||||
= help: add `#![feature(new_range_remainder)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
error[E0382]: use of moved value: `a`
|
||||
--> $DIR/dbg-macro-move-semantics.rs:9:13
|
||||
--> $DIR/dbg-macro-move-semantics.rs:9:18
|
||||
|
|
||||
LL | let a = NoCopy(0);
|
||||
| - move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait
|
||||
LL | let _ = dbg!(a);
|
||||
| ------- value moved here
|
||||
| - value moved here
|
||||
LL | let _ = dbg!(a);
|
||||
| ^^^^^^^ value used here after move
|
||||
| ^ value used here after move
|
||||
|
|
||||
note: if `NoCopy` implemented `Clone`, you could clone the value
|
||||
--> $DIR/dbg-macro-move-semantics.rs:4:1
|
||||
|
|
||||
LL | struct NoCopy(usize);
|
||||
| ^^^^^^^^^^^^^ consider implementing `Clone` for this type
|
||||
...
|
||||
LL | let _ = dbg!(a);
|
||||
| - you could clone this value
|
||||
help: consider borrowing instead of transferring ownership
|
||||
|
|
||||
LL | let _ = dbg!(&a);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
mod foo {
|
||||
pub use self as this;
|
||||
//~^ ERROR `self` is only public within the crate, and cannot be re-exported outside
|
||||
|
||||
pub mod bar {
|
||||
pub use super as parent;
|
||||
//~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
|
||||
pub use self::super as parent2;
|
||||
//~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
|
||||
pub use super::{self as parent3};
|
||||
//~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
|
||||
pub use self::{super as parent4};
|
||||
//~^ ERROR `super` is only public within the crate, and cannot be re-exported outside
|
||||
|
||||
pub use crate as root;
|
||||
pub use crate::{self as root2};
|
||||
pub use super::super as root3;
|
||||
}
|
||||
}
|
||||
|
||||
pub use foo::*;
|
||||
pub use foo::bar::*;
|
||||
|
||||
pub fn main() {}
|
||||
@@ -0,0 +1,43 @@
|
||||
error[E0365]: `self` is only public within the crate, and cannot be re-exported outside
|
||||
--> $DIR/pub-use-self-super-crate.rs:2:13
|
||||
|
|
||||
LL | pub use self as this;
|
||||
| ^^^^^^^^^^^^ re-export of crate public `self`
|
||||
|
|
||||
= note: consider declaring type or module `self` with `pub`
|
||||
|
||||
error[E0365]: `super` is only public within the crate, and cannot be re-exported outside
|
||||
--> $DIR/pub-use-self-super-crate.rs:6:17
|
||||
|
|
||||
LL | pub use super as parent;
|
||||
| ^^^^^^^^^^^^^^^ re-export of crate public `super`
|
||||
|
|
||||
= note: consider declaring type or module `super` with `pub`
|
||||
|
||||
error[E0365]: `super` is only public within the crate, and cannot be re-exported outside
|
||||
--> $DIR/pub-use-self-super-crate.rs:8:17
|
||||
|
|
||||
LL | pub use self::super as parent2;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ re-export of crate public `super`
|
||||
|
|
||||
= note: consider declaring type or module `super` with `pub`
|
||||
|
||||
error[E0365]: `super` is only public within the crate, and cannot be re-exported outside
|
||||
--> $DIR/pub-use-self-super-crate.rs:10:25
|
||||
|
|
||||
LL | pub use super::{self as parent3};
|
||||
| ^^^^^^^^^^^^^^^ re-export of crate public `super`
|
||||
|
|
||||
= note: consider declaring type or module `super` with `pub`
|
||||
|
||||
error[E0365]: `super` is only public within the crate, and cannot be re-exported outside
|
||||
--> $DIR/pub-use-self-super-crate.rs:12:24
|
||||
|
|
||||
LL | pub use self::{super as parent4};
|
||||
| ^^^^^^^^^^^^^^^^ re-export of crate public `super`
|
||||
|
|
||||
= note: consider declaring type or module `super` with `pub`
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0365`.
|
||||
@@ -70,7 +70,7 @@ macro_rules! macro_dollar_crate {
|
||||
|
||||
fn outer() {}
|
||||
|
||||
mod foo {
|
||||
pub mod foo {
|
||||
pub mod bar {
|
||||
pub mod foobar {
|
||||
pub mod qux {
|
||||
|
||||
Reference in New Issue
Block a user